提交 4f165b43 编写于 作者: C CyrusNajmabadi

Merge pull request #6977 from CyrusNajmabadi/addImportReferences

Add import can now add project references.
......@@ -270,21 +270,36 @@ public static IEnumerable<T> Flatten<T>(this IEnumerable<IEnumerable<T>> sequenc
return sequence.SelectMany(s => s);
}
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> source, IComparer<T> comparer)
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, IComparer<T> comparer)
{
return source.OrderBy(Functions<T>.Identity, comparer);
}
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> source, Comparison<T> compare)
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, Comparison<T> compare)
{
return source.OrderBy(new ComparisonComparer<T>(compare));
}
public static IEnumerable<T> Order<T>(this IEnumerable<T> source) where T : IComparable<T>
public static IOrderedEnumerable<T> Order<T>(this IEnumerable<T> source) where T : IComparable<T>
{
return source.OrderBy(Comparisons<T>.Comparer);
}
public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source, IComparer<T> comparer)
{
return source.ThenBy(Functions<T>.Identity, comparer);
}
public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source, Comparison<T> compare)
{
return source.ThenBy(new ComparisonComparer<T>(compare));
}
public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source) where T : IComparable<T>
{
return source.ThenBy(Comparisons<T>.Comparer);
}
private static class Comparisons<T> where T : IComparable<T>
{
public static readonly Comparison<T> CompareTo = (t1, t2) => t1.CompareTo(t2);
......
......@@ -103,7 +103,8 @@ public async Task TestPickTheRightPreview_NoPreference()
GetMainDocumentAndPreviews(workspace, out document, out previews);
// The changed document comes first.
var preview = await previews.TakeNextPreviewAsync();
var previewObjects = await previews.GetPreviewsAsync();
var preview = previewObjects[0];
Assert.NotNull(preview);
Assert.True(preview is IWpfDifferenceViewer);
var diffView = preview as IWpfDifferenceViewer;
......@@ -111,85 +112,19 @@ public async Task TestPickTheRightPreview_NoPreference()
Assert.Equal(ChangedDocumentText, text);
diffView.Close();
// The added document comes next.
preview = await previews.TakeNextPreviewAsync();
Assert.NotNull(preview);
Assert.True(preview is IWpfDifferenceViewer);
diffView = preview as IWpfDifferenceViewer;
text = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString();
Assert.Contains(AddedDocumentName, text, StringComparison.Ordinal);
Assert.Contains(AddedDocumentText, text, StringComparison.Ordinal);
diffView.Close();
// Then comes the removed metadata reference.
preview = await previews.TakeNextPreviewAsync();
preview = previewObjects[1];
Assert.NotNull(preview);
Assert.True(preview is string);
text = preview as string;
Assert.Contains(s_removedMetadataReferenceDisplayName, text, StringComparison.Ordinal);
// And finally the added project.
preview = await previews.TakeNextPreviewAsync();
preview = previewObjects[2];
Assert.NotNull(preview);
Assert.True(preview is string);
text = preview as string;
Assert.Contains(AddedProjectName, text, StringComparison.Ordinal);
// There are no more previews.
preview = await previews.TakeNextPreviewAsync();
Assert.Null(preview);
preview = await previews.TakeNextPreviewAsync();
Assert.Null(preview);
}
}
[WpfFact]
public async Task TestPickTheRightPreview_WithPreference()
{
using (var workspace = await CreateWorkspaceFromFileAsync("class D {}", null, null))
{
Document document = null;
SolutionPreviewResult previews = null;
GetMainDocumentAndPreviews(workspace, out document, out previews);
// Should return preview that matches the preferred (added) project.
var preview = await previews.TakeNextPreviewAsync(preferredProjectId: s_addedProjectId);
Assert.NotNull(preview);
Assert.True(preview is string);
var text = preview as string;
Assert.Contains(AddedProjectName, text, StringComparison.Ordinal);
// Should return preview that matches the preferred (changed) document.
preview = await previews.TakeNextPreviewAsync(preferredDocumentId: document.Id);
Assert.NotNull(preview);
Assert.True(preview is IWpfDifferenceViewer);
var diffView = preview as IWpfDifferenceViewer;
text = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString();
Assert.Equal(ChangedDocumentText, text);
diffView.Close();
// There is no longer a preview for the preferred project. Should return the first remaining preview.
preview = await previews.TakeNextPreviewAsync(preferredProjectId: s_addedProjectId);
Assert.NotNull(preview);
Assert.True(preview is IWpfDifferenceViewer);
diffView = preview as IWpfDifferenceViewer;
text = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString();
Assert.Contains(AddedDocumentName, text, StringComparison.Ordinal);
Assert.Contains(AddedDocumentText, text, StringComparison.Ordinal);
diffView.Close();
// There is no longer a preview for the preferred document. Should return the first remaining preview.
preview = await previews.TakeNextPreviewAsync(preferredDocumentId: document.Id);
Assert.NotNull(preview);
Assert.True(preview is string);
text = preview as string;
Assert.Contains(s_removedMetadataReferenceDisplayName, text, StringComparison.Ordinal);
// There are no more previews.
preview = await previews.TakeNextPreviewAsync();
Assert.Null(preview);
preview = await previews.TakeNextPreviewAsync();
Assert.Null(preview);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host;
......@@ -7,6 +8,6 @@ namespace Microsoft.CodeAnalysis.Editor.Host
{
internal interface IPreviewPaneService : IWorkspaceService
{
object GetPreviewPane(DiagnosticData diagnostic, string language, string projectType, object previewContent);
object GetPreviewPane(DiagnosticData diagnostic, string language, string projectType, IList<object> previewContent);
}
}
......@@ -66,13 +66,15 @@ public SolutionPreviewResult GetPreviews(Workspace workspace, IEnumerable<CodeAc
var previewOp = op as PreviewOperation;
if (previewOp != null)
{
return new SolutionPreviewResult(new List<SolutionPreviewItem>() { new SolutionPreviewItem(projectId: null, documentId: null, lazyPreview: c => previewOp.GetPreviewAsync(c)) });
return new SolutionPreviewResult(new List<SolutionPreviewItem>() { new SolutionPreviewItem(projectId: null, documentId: null,
lazyPreview: c => previewOp.GetPreviewAsync(c)) });
}
var title = op.Title;
if (title != null)
{
return new SolutionPreviewResult(new List<SolutionPreviewItem>() { new SolutionPreviewItem(projectId: null, documentId: null, lazyPreview: c => Task.FromResult<object>(title)) });
return new SolutionPreviewResult(new List<SolutionPreviewItem>() { new SolutionPreviewItem(projectId: null, documentId: null,
lazyPreview: c => Task.FromResult<object>(title)) });
}
}
......
......@@ -88,107 +88,107 @@ public SolutionPreviewResult GetSolutionPreviews(Solution oldSolution, Solution
foreach (var documentId in projectChanges.GetChangedDocuments())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, (c) =>
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, c =>
CreateChangedDocumentPreviewViewAsync(oldSolution.GetDocument(documentId), newSolution.GetDocument(documentId), zoomLevel, c)));
}
foreach (var documentId in projectChanges.GetAddedDocuments())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, (c) =>
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, c =>
CreateAddedDocumentPreviewViewAsync(newSolution.GetDocument(documentId), zoomLevel, c)));
}
foreach (var documentId in projectChanges.GetRemovedDocuments())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, documentId, (c) =>
previewItems.Add(new SolutionPreviewItem(oldProject.Id, documentId, c =>
CreateRemovedDocumentPreviewViewAsync(oldSolution.GetDocument(documentId), zoomLevel, c)));
}
foreach (var documentId in projectChanges.GetChangedAdditionalDocuments())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, (c) =>
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, c =>
CreateChangedAdditionalDocumentPreviewViewAsync(oldSolution.GetAdditionalDocument(documentId), newSolution.GetAdditionalDocument(documentId), zoomLevel, c)));
}
foreach (var documentId in projectChanges.GetAddedAdditionalDocuments())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, (c) =>
previewItems.Add(new SolutionPreviewItem(documentId.ProjectId, documentId, c =>
CreateAddedAdditionalDocumentPreviewViewAsync(newSolution.GetAdditionalDocument(documentId), zoomLevel, c)));
}
foreach (var documentId in projectChanges.GetRemovedAdditionalDocuments())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, documentId, (c) =>
previewItems.Add(new SolutionPreviewItem(oldProject.Id, documentId, c =>
CreateRemovedAdditionalDocumentPreviewViewAsync(oldSolution.GetAdditionalDocument(documentId), zoomLevel, c)));
}
foreach (var metadataReference in projectChanges.GetAddedMetadataReferences())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.AddingReferenceTo, metadataReference.Display, oldProject.Name))));
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null,
string.Format(EditorFeaturesResources.AddingReferenceTo, metadataReference.Display, oldProject.Name)));
}
foreach (var metadataReference in projectChanges.GetRemovedMetadataReferences())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.RemovingReferenceFrom, metadataReference.Display, oldProject.Name))));
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null,
string.Format(EditorFeaturesResources.RemovingReferenceFrom, metadataReference.Display, oldProject.Name)));
}
foreach (var projectReference in projectChanges.GetAddedProjectReferences())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.AddingReferenceTo, newSolution.GetProject(projectReference.ProjectId).Name, oldProject.Name))));
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null,
string.Format(EditorFeaturesResources.AddingReferenceTo, newSolution.GetProject(projectReference.ProjectId).Name, oldProject.Name)));
}
foreach (var projectReference in projectChanges.GetRemovedProjectReferences())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.RemovingReferenceFrom, oldSolution.GetProject(projectReference.ProjectId).Name, oldProject.Name))));
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null,
string.Format(EditorFeaturesResources.RemovingReferenceFrom, oldSolution.GetProject(projectReference.ProjectId).Name, oldProject.Name)));
}
foreach (var analyzer in projectChanges.GetAddedAnalyzerReferences())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.AddingAnalyzerReferenceTo, analyzer.Display, oldProject.Name))));
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null,
string.Format(EditorFeaturesResources.AddingAnalyzerReferenceTo, analyzer.Display, oldProject.Name)));
}
foreach (var analyzer in projectChanges.GetRemovedAnalyzerReferences())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.RemovingAnalyzerReferenceFrom, analyzer.Display, oldProject.Name))));
previewItems.Add(new SolutionPreviewItem(oldProject.Id, null,
string.Format(EditorFeaturesResources.RemovingAnalyzerReferenceFrom, analyzer.Display, oldProject.Name)));
}
}
foreach (var project in solutionChanges.GetAddedProjects())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(project.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.AddingProject, project.Name))));
previewItems.Add(new SolutionPreviewItem(project.Id, null,
string.Format(EditorFeaturesResources.AddingProject, project.Name)));
}
foreach (var project in solutionChanges.GetRemovedProjects())
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(project.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.RemovingProject, project.Name))));
previewItems.Add(new SolutionPreviewItem(project.Id, null,
string.Format(EditorFeaturesResources.RemovingProject, project.Name)));
}
foreach (var projectChanges in solutionChanges.GetProjectChanges().Where(pc => pc.OldProject.AllProjectReferences != pc.NewProject.AllProjectReferences))
foreach (var projectChanges in solutionChanges.GetProjectChanges().Where(ProjectReferencesChanged))
{
cancellationToken.ThrowIfCancellationRequested();
previewItems.Add(new SolutionPreviewItem(projectChanges.OldProject.Id, null, (c) =>
Task.FromResult<object>(string.Format(EditorFeaturesResources.ChangingProjectReferencesFor, projectChanges.OldProject.Name))));
previewItems.Add(new SolutionPreviewItem(projectChanges.OldProject.Id, null,
string.Format(EditorFeaturesResources.ChangingProjectReferencesFor, projectChanges.OldProject.Name)));
}
changeSummary = new SolutionChangeSummary(oldSolution, newSolution, solutionChanges);
......@@ -197,6 +197,29 @@ public SolutionPreviewResult GetSolutionPreviews(Solution oldSolution, Solution
return new SolutionPreviewResult(previewItems, changeSummary);
}
private bool ProjectReferencesChanged(ProjectChanges projectChanges)
{
var oldProjectReferences = projectChanges.OldProject.ProjectReferences.ToDictionary(r => r.ProjectId);
var newProjectReferences = projectChanges.NewProject.ProjectReferences.ToDictionary(r => r.ProjectId);
// These are the set of project reference that remained in the project. We don't care
// about project references that were added or removed. Those will already be reported.
var preservedProjectIds = oldProjectReferences.Keys.Intersect(newProjectReferences.Keys);
foreach (var projectId in preservedProjectIds)
{
var oldProjectReference = oldProjectReferences[projectId];
var newProjectReference = newProjectReferences[projectId];
if (!oldProjectReference.Equals(newProjectReference))
{
return true;
}
}
return false;
}
public Task<object> CreateAddedDocumentPreviewViewAsync(Document document, CancellationToken cancellationToken)
{
return CreateAddedDocumentPreviewViewAsync(document, DefaultZoomLevel, cancellationToken);
......@@ -405,7 +428,7 @@ public Task<object> CreateChangedDocumentPreviewViewAsync(Document oldDocument,
leftWorkspace.OpenDocument(leftDocument.Id);
var rightWorkspace = new PreviewWorkspace(
oldDocument.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);
newDocument.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);
rightWorkspace.OpenDocument(newDocument.Id);
return CreateChangedDocumentViewAsync(
......
......@@ -3,6 +3,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor
{
......@@ -11,6 +12,7 @@ internal class SolutionPreviewItem
public readonly ProjectId ProjectId;
public readonly DocumentId DocumentId;
public readonly Func<CancellationToken, Task<object>> LazyPreview;
public readonly string Text;
/// <summary>
/// Construct an instance of <see cref="SolutionPreviewItem"/>
......@@ -27,5 +29,13 @@ public SolutionPreviewItem(ProjectId projectId, DocumentId documentId, Func<Canc
DocumentId = documentId;
LazyPreview = lazyPreview;
}
public SolutionPreviewItem(ProjectId projectId, DocumentId documentId, string text)
{
ProjectId = projectId;
DocumentId = documentId;
Text = text;
LazyPreview = c => Task.FromResult<object>(text);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.Text.Differencing;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor
{
internal class SolutionPreviewResult : ForegroundThreadAffinitizedObject
{
private IList<SolutionPreviewItem> _previews = null;
private readonly IList<SolutionPreviewItem> _previews;
public readonly SolutionChangeSummary ChangeSummary;
public SolutionPreviewResult(IList<SolutionPreviewItem> previews, SolutionChangeSummary changeSummary = null)
{
_previews = previews;
_previews = previews ?? SpecializedCollections.EmptyList<SolutionPreviewItem>();
this.ChangeSummary = changeSummary;
}
public bool IsEmpty
{
get { return (_previews == null) || (_previews.Count == 0); }
}
public bool IsEmpty => _previews.Count == 0;
/// <remarks>
/// Once a preview object is returned from this function, the ownership of this preview object is
/// transferred to the caller. It is the caller's responsibility to ensure that the preview object
/// will be properly disposed (i.e. that any contained IWpfTextViews will be properly closed).
///
/// This function guarantees that it will not return the same preview object twice if called twice
/// (thereby reducing the possibility that a given preview object can end up with more than one owner).
/// </remarks>
public async Task<object> TakeNextPreviewAsync(DocumentId preferredDocumentId = null, ProjectId preferredProjectId = null, CancellationToken cancellationToken = default(CancellationToken))
public async Task<IList<object>> GetPreviewsAsync(DocumentId preferredDocumentId = null, ProjectId preferredProjectId = null, CancellationToken cancellationToken = default(CancellationToken))
{
AssertIsForeground();
cancellationToken.ThrowIfCancellationRequested();
if (IsEmpty)
var orderedPreviews = _previews.OrderBy((i1, i2) =>
{
return null;
}
SolutionPreviewItem previewItem = null;
// Check if we have a preview for some change within the supplied preferred document.
if (preferredDocumentId != null)
return i1.DocumentId == preferredDocumentId && i2.DocumentId != preferredDocumentId ? -1 :
i1.DocumentId != preferredDocumentId && i2.DocumentId == preferredDocumentId ? 1 :
_previews.IndexOf(i1) - _previews.IndexOf(i2);
}).ThenBy((i1, i2) =>
{
previewItem = _previews.Where(p => p.DocumentId == preferredDocumentId).FirstOrDefault();
}
// Check if we have a preview for some change within the supplied preferred project.
if ((previewItem == null) && (preferredProjectId != null))
return i1.ProjectId == preferredProjectId && i2.ProjectId != preferredProjectId ? -1 :
i1.ProjectId != preferredProjectId && i2.ProjectId == preferredProjectId ? 1 :
_previews.IndexOf(i1) - _previews.IndexOf(i2);
}).ThenBy((i1, i2) =>
{
previewItem = _previews.Where(p => p.ProjectId == preferredProjectId).FirstOrDefault();
}
return i1.Text == null && i2.Text != null ? -1 :
i1.Text != null && i2.Text == null ? 1 :
_previews.IndexOf(i1) - _previews.IndexOf(i2);
});
// We don't have a preview matching the preferred document or project. Return the first preview.
if (previewItem == null)
{
previewItem = _previews.FirstOrDefault();
}
var result = new List<object>();
var gotRichPreview = false;
cancellationToken.ThrowIfCancellationRequested();
// We should now remove this preview object from the list so that it can not be returned again
// if someone calls this function again (thereby reducing the possibility that a given preview
// object can end up with more than one owner - see <remarks> above).
_previews.Remove(previewItem);
// We use ConfigureAwait(true) to stay on the UI thread.
var preview = await previewItem.LazyPreview(cancellationToken).ConfigureAwait(true);
if (preview == null)
foreach (var previewItem in _previews)
{
// Keep going if preview is null. Null preview indicates that although the preferred document was marked as changed,
// there are no textual changes in the preferred document and so we can't create a diff preview for this document.
// This can happen in the case of the 'rename tracking' code fix - the document where the fix was triggered from (i.e.
// the preferred document) is always reported as changed (on account of difference in document version). However, if
// the renamed identifier is not referenced from any other location in this document, then there will be no text changes
// between the two versions. In such cases, We should keep going until we find a document with text changes that can be
// diffed and previewed.
// There is no danger of infinite recursion here since we remove null previews from the list each time.
preview = await TakeNextPreviewAsync(preferredDocumentId, preferredProjectId, cancellationToken).ConfigureAwait(true);
cancellationToken.ThrowIfCancellationRequested();
if (previewItem.Text != null)
{
result.Add(previewItem.Text);
}
else if (!gotRichPreview)
{
var preview = await previewItem.LazyPreview(cancellationToken).ConfigureAwait(true);
if (preview != null)
{
result.Add(preview);
gotRichPreview = true;
}
}
}
return preview;
return result.Count == 0 ? null : result;
}
}
}
}
\ No newline at end of file
......@@ -208,7 +208,7 @@ public virtual async Task<object> GetPreviewAsync(CancellationToken cancellation
{
// TakeNextPreviewAsync() needs to run on UI thread.
AssertIsForeground();
return await previewResult.TakeNextPreviewAsync(preferredDocumentId, preferredProjectId, cancellationToken).ConfigureAwait(true);
return await previewResult.GetPreviewsAsync(preferredDocumentId, preferredProjectId, cancellationToken).ConfigureAwait(true);
}
// GetPreviewPane() below needs to run on UI thread. We use ConfigureAwait(true) to stay on the UI thread.
......
......@@ -90,7 +90,7 @@ private static async Task VerifyPreviewContents(TestWorkspace workspace, string
if (expectedPreviewContents != null)
{
var editHandler = workspace.ExportProvider.GetExportedValue<ICodeActionEditHandlerService>();
var content = await editHandler.GetPreviews(workspace, operations, CancellationToken.None).TakeNextPreviewAsync();
var content = (await editHandler.GetPreviews(workspace, operations, CancellationToken.None).GetPreviewsAsync())[0];
var diffView = content as IWpfDifferenceViewer;
Assert.NotNull(diffView);
var previewContents = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString();
......
......@@ -358,7 +358,7 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva
if (!hasProjectChange)
{
// If there is just one document change then we expect the preview to be a WpfTextView
var content = await editHandler.GetPreviews(workspace, operations, CancellationToken.None).TakeNextPreviewAsync();
var content = (await editHandler.GetPreviews(workspace, operations, CancellationToken.None).GetPreviewsAsync())[0];
var diffView = content as IWpfDifferenceViewer;
Assert.NotNull(diffView);
diffView.Close();
......@@ -368,15 +368,21 @@ protected async Task TestEquivalenceKeyAsync(string initialMarkup, string equiva
// If there are more changes than just the document we need to browse all the changes and get the document change
var contents = editHandler.GetPreviews(workspace, operations, CancellationToken.None);
bool hasPreview = false;
object preview;
while ((preview = await contents.TakeNextPreviewAsync()) != null)
var previews = await contents.GetPreviewsAsync();
if (previews != null)
{
var diffView = preview as IWpfDifferenceViewer;
if (diffView != null)
foreach (var preview in previews)
{
hasPreview = true;
diffView.Close();
break;
if (preview != null)
{
var diffView = preview as IWpfDifferenceViewer;
if (diffView != null)
{
hasPreview = true;
diffView.Close();
break;
}
}
}
}
......
......@@ -19,11 +19,19 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
Friend MustOverride Function CreateDiagnosticProviderAndFixer(workspace As Workspace, language As String) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider)
Protected Async Function TestMissing(definition As XElement) As Task
Using workspace = Await TestWorkspaceFactory.CreateWorkspaceAsync(definition)
Dim diagnosticAndFix = Await GetDiagnosticAndFixAsync(workspace)
Assert.Null(diagnosticAndFix)
End Using
End Function
Protected Async Function TestAsync(definition As XElement,
Optional expected As String = Nothing,
Optional codeActionIndex As Integer = 0,
Optional verifyTokens As Boolean = True,
Optional fileNameToExpected As Dictionary(Of String, String) = Nothing) As Task
Optional fileNameToExpected As Dictionary(Of String, String) = Nothing,
Optional verifySolutions As Action(Of Solution, Solution) = Nothing) As Task
Using workspace = Await TestWorkspaceFactory.CreateWorkspaceAsync(definition)
Dim diagnosticAndFix = Await GetDiagnosticAndFixAsync(workspace)
Dim codeAction = diagnosticAndFix.Item2.Fixes.ElementAt(codeActionIndex).Action
......@@ -33,6 +41,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
Dim oldSolution = workspace.CurrentSolution
Dim updatedSolution = edit.ChangedSolution
verifySolutions?.Invoke(oldSolution, updatedSolution)
If fileNameToExpected Is Nothing Then
Dim updatedDocument = SolutionUtilities.GetSingleChangedDocument(oldSolution, updatedSolution)
......
......@@ -4,6 +4,7 @@ Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.CSharp.CodeFixes.AddImport
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.UnitTests
Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.AddImport
......@@ -215,5 +216,150 @@ End Namespace
Await TestAsync(input, expected, codeActionIndex:=0)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)>
Public Async Function TestAddProjectReference_CSharpToCSharp() As Task
Dim input =
<Workspace>
<Project Language='C#' AssemblyName='CSAssembly1' CommonReferences='true'>
<Document FilePath='Test1.cs'>
using System.Collections.Generic;
namespace CSAssembly1
{
public class Class1
{
}
}
</Document>
</Project>
<Project Language='C#' AssemblyName='CSAssembly2' CommonReferences='true'>
<CompilationOptions></CompilationOptions>
<Document FilePath="Test2.cs">
namespace CSAssembly2
{
public class Class2
{
$$Class1 c;
}
}
</Document>
</Project>
</Workspace>
Dim expected =
<text>
using CSAssembly1;
namespace CSAssembly2
{
public class Class2
{
Class1 c;
}
}
</text>.Value.Trim()
Await TestAsync(input, expected, codeActionIndex:=0, addedReference:="CSAssembly1")
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)>
Public Async Function TestAddProjectReference_VBToVB() As Task
Dim input =
<Workspace>
<Project Language='Visual Basic' AssemblyName='VBAssembly1' CommonReferences='true'>
<Document FilePath='Test1.vb'>
Namespace VBAssembly1
Public Class Class1
End Class
End Namespace
</Document>
</Project>
<Project Language='Visual Basic' AssemblyName='VBAssembly2' CommonReferences='true'>
<CompilationOptions></CompilationOptions>
<Document FilePath="Test2.vb">
Namespace VBAssembly2
Public Class Class2
dim c As $$Class1
End Class
End Namespace
</Document>
</Project>
</Workspace>
Dim expected =
<text>
Imports VBAssembly1
Namespace VBAssembly2
Public Class Class2
Dim c As Class1
End Class
End Namespace
</text>.Value.Trim()
Await TestAsync(input, expected, codeActionIndex:=0, addedReference:="VBAssembly1")
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)>
Public Async Function TestAddProjectReferenceMissingForCircularReference() As Task
Dim input =
<Workspace>
<Project Language='C#' AssemblyName='CSAssembly1' CommonReferences='true'>
<ProjectReference>CSAssembly2</ProjectReference>
<Document FilePath='Test1.cs'>
using System.Collections.Generic;
namespace CSAssembly1
{
public class Class1
{
}
}
</Document>
</Project>
<Project Language='C#' AssemblyName='CSAssembly2' CommonReferences='true'>
<CompilationOptions></CompilationOptions>
<Document FilePath="Test2.cs">
namespace CSAssembly2
{
public class Class2
{
$$Class1 c;
}
}
</Document>
</Project>
</Workspace>
Await TestMissing(input)
End Function
Protected Overloads Async Function TestAsync(definition As XElement,
Optional expected As String = Nothing,
Optional codeActionIndex As Integer = 0,
Optional addedReference As String = Nothing) As Task
Dim verifySolutions As Action(Of Solution, Solution) = Nothing
If addedReference IsNot Nothing Then
verifySolutions =
Sub(oldSolution As Solution, newSolution As Solution)
Dim changedDoc = SolutionUtilities.GetSingleChangedDocument(oldSolution, newSolution)
Dim oldProject = oldSolution.GetDocument(changedDoc.Id).Project
Dim newProject = newSolution.GetDocument(changedDoc.Id).Project
Dim oldProjectReferences = From r In oldProject.ProjectReferences
Let p = oldSolution.GetProject(r.ProjectId)
Select p.Name
Assert.False(oldProjectReferences.Contains(addedReference))
Dim newProjectReferences = From r In newProject.ProjectReferences
Let p = newSolution.GetProject(r.ProjectId)
Select p.Name
Assert.True(newProjectReferences.Contains(addedReference))
End Sub
End If
Await TestAsync(definition, expected, codeActionIndex, verifySolutions:=verifySolutions)
End Function
End Class
End Namespace
......@@ -116,6 +116,7 @@
<Private>false</Private>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Drawing" />
......
......@@ -2,6 +2,7 @@
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Windows.Controls
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
......@@ -83,7 +84,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings
GetMainDocumentAndPreviews(workspace, document, previews)
' The changed document comes first.
Dim preview = Await previews.TakeNextPreviewAsync()
Dim previewObjects = Await previews.GetPreviewsAsync()
Dim preview = previewObjects(0)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is IWpfDifferenceViewer)
Dim diffView = DirectCast(preview, IWpfDifferenceViewer)
......@@ -91,83 +93,19 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings
Assert.Equal(s_changedDocumentText, text)
diffView.Close()
' The added document comes next.
preview = Await previews.TakeNextPreviewAsync()
Assert.NotNull(preview)
Assert.True(TypeOf preview Is IWpfDifferenceViewer)
diffView = DirectCast(preview, IWpfDifferenceViewer)
text = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString()
Assert.Contains(s_addedDocumentName, text, StringComparison.Ordinal)
Assert.Contains(s_addedDocumentText, text, StringComparison.Ordinal)
diffView.Close()
' Then comes the removed metadata reference.
preview = Await previews.TakeNextPreviewAsync()
preview = previewObjects(1)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is String)
text = DirectCast(preview, String)
Assert.Contains(s_removedMetadataReferenceDisplayName, text, StringComparison.Ordinal)
' And finally the added project.
preview = Await previews.TakeNextPreviewAsync()
preview = previewObjects(2)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is String)
text = DirectCast(preview, String)
Assert.Contains(s_addedProjectName, text, StringComparison.Ordinal)
' There are no more previews.
preview = Await previews.TakeNextPreviewAsync()
Assert.Null(preview)
preview = Await previews.TakeNextPreviewAsync()
Assert.Null(preview)
End Using
End Function
<WpfFact>
Public Async Function TestPickTheRightPreview_WithPreference() As Task
Using workspace = Await CreateWorkspaceFromFileAsync("Class D : End Class", Nothing, Nothing)
Dim document As Document = Nothing
Dim previews As SolutionPreviewResult = Nothing
GetMainDocumentAndPreviews(workspace, document, previews)
' Should return preview that matches the preferred (added) project.
Dim preview = Await previews.TakeNextPreviewAsync(preferredProjectId:=s_addedProjectId)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is String)
Dim text = DirectCast(preview, String)
Assert.Contains(s_addedProjectName, text, StringComparison.Ordinal)
' Should return preview that matches the preferred (changed) document.
preview = Await previews.TakeNextPreviewAsync(preferredDocumentId:=document.Id)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is IWpfDifferenceViewer)
Dim diffView = DirectCast(preview, IWpfDifferenceViewer)
text = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString()
Assert.Equal(s_changedDocumentText, text)
diffView.Close()
' There is no longer a preview for the preferred project. Should return the first remaining preview.
preview = Await previews.TakeNextPreviewAsync(preferredProjectId:=s_addedProjectId)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is IWpfDifferenceViewer)
diffView = DirectCast(preview, IWpfDifferenceViewer)
text = diffView.RightView.TextBuffer.AsTextContainer().CurrentText.ToString()
Assert.Contains(s_addedDocumentName, text, StringComparison.Ordinal)
Assert.Contains(s_addedDocumentText, text, StringComparison.Ordinal)
diffView.Close()
' There is no longer a preview for the preferred document. Should return the first remaining preview.
preview = Await previews.TakeNextPreviewAsync(preferredDocumentId:=document.Id)
Assert.NotNull(preview)
Assert.True(TypeOf preview Is String)
text = DirectCast(preview, String)
Assert.Contains(s_removedMetadataReferenceDisplayName, text, StringComparison.Ordinal)
' There are no more previews.
preview = Await previews.TakeNextPreviewAsync()
Assert.Null(preview)
preview = Await previews.TakeNextPreviewAsync()
Assert.Null(preview)
End Using
End Function
End Class
......
......@@ -22,6 +22,8 @@
namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.AddImport
{
using SymbolReference = ValueTuple<INamespaceOrTypeSymbol, MetadataReference>;
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AddUsingOrImport), Shared]
internal class CSharpAddImportCodeFixProvider : AbstractAddImportCodeFixProvider
{
......@@ -667,22 +669,6 @@ protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode
return leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null;
}
protected override IEnumerable<ITypeSymbol> GetProposedTypes(string name, List<ITypeSymbol> accessibleTypeSymbols, SemanticModel semanticModel, ISet<INamespaceSymbol> namespacesInScope)
{
if (accessibleTypeSymbols == null)
{
yield break;
}
foreach (var typeSymbol in accessibleTypeSymbols)
{
if (typeSymbol?.ContainingType != null)
{
yield return typeSymbol.ContainingType;
}
}
}
internal override bool IsViableField(IFieldSymbol field, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
{
return IsViablePropertyOrField(field, expression, semanticModel, syntaxFacts, cancellationToken);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
namespace Microsoft.CodeAnalysis.CodeFixes.AddImport
{
internal abstract partial class AbstractAddImportCodeFixProvider
{
private abstract class SearchScope
{
protected readonly bool ignoreCase;
protected readonly CancellationToken cancellationToken;
protected SearchScope(bool ignoreCase, CancellationToken cancellationToken)
{
this.ignoreCase = ignoreCase;
this.cancellationToken = cancellationToken;
}
public abstract Task<IEnumerable<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter);
public abstract SymbolReference CreateReference(INamespaceOrTypeSymbol symbol);
}
private class ProjectSearchScope : SearchScope
{
private readonly bool _includeDirectReferences;
private readonly Project _project;
public ProjectSearchScope(Project project, bool includeDirectReferences, bool ignoreCase, CancellationToken cancellationToken)
: base(ignoreCase, cancellationToken)
{
_project = project;
_includeDirectReferences = includeDirectReferences;
}
public override Task<IEnumerable<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter)
{
return SymbolFinder.FindDeclarationsAsync(
_project, name, ignoreCase, filter, _includeDirectReferences, cancellationToken);
}
public override SymbolReference CreateReference(INamespaceOrTypeSymbol symbol)
{
return new ProjectSymbolReference(symbol, _project.Id);
}
}
private class MetadataSearchScope : SearchScope
{
private readonly IAssemblySymbol _assembly;
private readonly PortableExecutableReference _metadataReference;
private readonly Solution _solution;
public MetadataSearchScope(
Solution solution,
IAssemblySymbol assembly,
PortableExecutableReference metadataReference,
bool ignoreCase,
CancellationToken cancellationToken)
: base(ignoreCase, cancellationToken)
{
_solution = solution;
_assembly = assembly;
_metadataReference = metadataReference;
}
public override SymbolReference CreateReference(INamespaceOrTypeSymbol symbol)
{
return new MetadataSymbolReference(symbol, _metadataReference);
}
public override Task<IEnumerable<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter)
{
return SymbolFinder.FindDeclarationsAsync(_solution, _assembly, _metadataReference.FilePath, name, ignoreCase, filter, cancellationToken);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CodeFixes.AddImport
{
internal abstract partial class AbstractAddImportCodeFixProvider
{
private abstract class SymbolReference : IComparable<SymbolReference>, IEquatable<SymbolReference>
{
public readonly INamespaceOrTypeSymbol Symbol;
protected SymbolReference(INamespaceOrTypeSymbol symbol)
{
this.Symbol = symbol;
}
public int CompareTo(SymbolReference other)
{
return INamespaceOrTypeSymbolExtensions.CompareNamespaceOrTypeSymbols(this.Symbol, other.Symbol);
}
public override bool Equals(object obj)
{
return Equals(obj as SymbolReference);
}
public bool Equals(SymbolReference other)
{
return object.Equals(this.Symbol, other?.Symbol);
}
public override int GetHashCode()
{
return this.Symbol.GetHashCode();
}
public abstract Solution UpdateSolution(Document newDocument);
}
private class ProjectSymbolReference : SymbolReference
{
private readonly ProjectId _projectId;
public ProjectSymbolReference(INamespaceOrTypeSymbol symbol, ProjectId projectId)
: base(symbol)
{
_projectId = projectId;
}
public override Solution UpdateSolution(Document newDocument)
{
if (_projectId == newDocument.Project.Id)
{
// This reference was found while searching in the project for our document. No
// need to make any solution changes.
return newDocument.Project.Solution;
}
// If this reference came from searching another project, then add a project reference
// as well.
var newProject = newDocument.Project;
newProject = newProject.AddProjectReference(new ProjectReference(_projectId));
return newProject.Solution;
}
}
private class MetadataSymbolReference : SymbolReference
{
private readonly PortableExecutableReference _reference;
public MetadataSymbolReference(INamespaceOrTypeSymbol symbol, PortableExecutableReference reference)
: base(symbol)
{
_reference = reference;
}
public override Solution UpdateSolution(Document newDocument)
{
return newDocument.Project.AddMetadataReference(_reference).Solution;
}
}
}
}
......@@ -17,6 +17,8 @@ namespace Microsoft.CodeAnalysis.CodeFixes.FullyQualify
{
internal abstract partial class AbstractFullyQualifyCodeFixProvider : CodeFixProvider
{
private const int MaxResults = 3;
protected AbstractFullyQualifyCodeFixProvider()
{
}
......@@ -58,7 +60,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
var proposedContainers =
matchingTypeContainers.Concat(matchingNamespaceContainers)
.Distinct()
.Take(8);
.Take(MaxResults);
var displayService = project.LanguageServices.GetService<ISymbolDisplayService>();
......
......@@ -88,6 +88,8 @@
<Compile Include="ChangeSignature\IUnifiedArgumentSyntax.cs" />
<Compile Include="ChangeSignature\ParameterConfiguration.cs" />
<Compile Include="ChangeSignature\SignatureChange.cs" />
<Compile Include="CodeFixes\AddImport\AbstractAddImportCodeFixProvider.SearchScope.cs" />
<Compile Include="CodeFixes\AddImport\AbstractAddImportCodeFixProvider.SymbolReference.cs" />
<Compile Include="CodeFixes\CodeFixContextExtensions.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixMultipleCodeAction.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixAllCodeAction.cs" />
......
......@@ -336,11 +336,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
Return leftExpressionType IsNot Nothing AndAlso method.ReduceExtensionMethod(leftExpressionType) IsNot Nothing
End Function
Protected Overrides Function GetProposedTypes(name As String, accessibleTypeSymbols As List(Of ITypeSymbol), semanticModel As SemanticModel, namespacesInScope As ISet(Of INamespaceSymbol)) As IEnumerable(Of ITypeSymbol)
Return From typeSymbol In accessibleTypeSymbols
Select typeSymbol.ContainingType
End Function
Friend Overrides Function IsViableField(field As IFieldSymbol, expression As SyntaxNode, semanticModel As SemanticModel, syntaxFacts As ISyntaxFactsService, cancellationToken As CancellationToken) As Boolean
Return False
End Function
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
......@@ -8,6 +10,7 @@
using Microsoft.CodeAnalysis.Diagnostics.Log;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Microsoft.VisualStudio.Text.Differencing;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.PreviewPane
{
......@@ -24,7 +27,7 @@ internal partial class PreviewPane : UserControl, IDisposable
private IWpfDifferenceViewer _previewDiffViewer;
public PreviewPane(Image severityIcon, string id, string title, string description, Uri helpLink, string helpLinkToolTipText,
object previewContent, bool logIdVerbatimInTelemetry)
IList<object> previewContent, bool logIdVerbatimInTelemetry)
{
InitializeComponent();
......@@ -59,23 +62,9 @@ internal partial class PreviewPane : UserControl, IDisposable
InitializePreviewElement(previewContent);
}
private void InitializePreviewElement(object previewContent)
private void InitializePreviewElement(IList<object> previewItems)
{
FrameworkElement previewElement = null;
if (previewContent is IWpfDifferenceViewer)
{
_previewDiffViewer = previewContent as IWpfDifferenceViewer;
previewElement = _previewDiffViewer.VisualElement;
PreviewDockPanel.Background = _previewDiffViewer.InlineView.Background;
}
else if (previewContent is string)
{
previewElement = GetPreviewForString(previewContent as string);
}
else if (previewContent is FrameworkElement)
{
previewElement = previewContent as FrameworkElement;
}
var previewElement = CreatePreviewElement(previewItems);
if (previewElement != null)
{
......@@ -95,6 +84,57 @@ private void InitializePreviewElement(object previewContent)
AdjustWidthAndHeight(previewElement);
}
private FrameworkElement CreatePreviewElement(IList<object> previewItems)
{
if (previewItems == null || previewItems.Count == 0)
{
return null;
}
const int MaxItems = 3;
if (previewItems.Count > MaxItems)
{
previewItems = previewItems.Take(MaxItems).Concat("...").ToList();
}
var grid = new Grid();
for (var i = 0; i < previewItems.Count; i++)
{
var previewItem = previewItems[i];
FrameworkElement previewElement = null;
if (previewItem is IWpfDifferenceViewer)
{
_previewDiffViewer = (IWpfDifferenceViewer)previewItem;
previewElement = _previewDiffViewer.VisualElement;
PreviewDockPanel.Background = _previewDiffViewer.InlineView.Background;
}
else if (previewItem is string)
{
previewElement = GetPreviewForString((string)previewItem, createBorder: previewItems.Count == 0);
}
else if (previewItem is FrameworkElement)
{
previewElement = (FrameworkElement)previewItem;
}
var rowDefinition = i == 0 ? new RowDefinition() : new RowDefinition() { Height = GridLength.Auto };
grid.RowDefinitions.Add(rowDefinition);
Grid.SetRow(previewElement, grid.RowDefinitions.IndexOf(rowDefinition));
grid.Children.Add(previewElement);
if (i == 0)
{
grid.Width = previewElement.Width;
}
}
var preview = grid.Children.Count == 0 ? (FrameworkElement)grid.Children[0] : grid;
return preview;
}
private void InitializeHyperlinks(Uri helpLink, string helpLinkToolTipText)
{
IdHyperlink.SetVSHyperLinkStyle();
......@@ -110,7 +150,7 @@ private void InitializeHyperlinks(Uri helpLink, string helpLinkToolTipText)
LearnMoreHyperlink.ToolTip = helpLinkToolTipText;
}
public static Border GetPreviewForString(string previewContent, bool useItalicFontStyle = false, bool centerAlignTextHorizontally = false)
public static FrameworkElement GetPreviewForString(string previewContent, bool useItalicFontStyle = false, bool centerAlignTextHorizontally = false, bool createBorder = false)
{
var textBlock = new TextBlock()
{
......@@ -130,12 +170,16 @@ public static Border GetPreviewForString(string previewContent, bool useItalicFo
textBlock.TextAlignment = TextAlignment.Center;
}
var preview = new Border()
FrameworkElement preview = textBlock;
if (createBorder)
{
Width = 400,
MinHeight = 75,
Child = textBlock
};
preview = new Border()
{
Width = 400,
MinHeight = 75,
Child = textBlock
};
}
return preview;
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using System.Globalization;
using System.Linq;
......@@ -80,7 +81,7 @@ private static Uri GetHelpLink(DiagnosticData diagnostic, string language, strin
return helpLink;
}
object IPreviewPaneService.GetPreviewPane(DiagnosticData diagnostic, string language, string projectType, object previewContent)
object IPreviewPaneService.GetPreviewPane(DiagnosticData diagnostic, string language, string projectType, IList<object> previewContent)
{
var title = diagnostic?.Message;
......
......@@ -18,13 +18,25 @@ public static partial class SymbolFinder
/// </summary>
public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(Project project, string name, bool ignoreCase, CancellationToken cancellationToken = default(CancellationToken))
{
return FindDeclarationsAsync(project, name, ignoreCase, SymbolFilter.All, cancellationToken);
return FindDeclarationsAsync(project, name, ignoreCase, includeDirectReferences: true, cancellationToken: cancellationToken);
}
internal static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, bool includeDirectReferences, CancellationToken cancellationToken)
{
return FindDeclarationsAsync(project, name, ignoreCase, SymbolFilter.All, includeDirectReferences, cancellationToken);
}
/// <summary>
/// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name.
/// </summary>
public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
return FindDeclarationsAsync(project, name, ignoreCase, filter, includeDirectReferences: true, cancellationToken: cancellationToken);
}
internal static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, bool includeDirectReferences, CancellationToken cancellationToken)
{
if (project == null)
{
......@@ -43,12 +55,12 @@ public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(Project project,
using (Logger.LogBlock(FunctionId.SymbolFinder_FindDeclarationsAsync, cancellationToken))
{
return FindDeclarationsAsyncImpl(project, name, ignoreCase, filter, cancellationToken);
return FindDeclarationsAsyncImpl(project, name, ignoreCase, filter, includeDirectReferences, cancellationToken);
}
}
private static async Task<IEnumerable<ISymbol>> FindDeclarationsAsyncImpl(
Project project, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
Project project, string name, bool ignoreCase, SymbolFilter criteria, bool includeDirectReferences, CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
......@@ -58,16 +70,19 @@ public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(Project project,
await AddDeclarationsAsync(project, name, ignoreCase, criteria, list, cancellationToken).ConfigureAwait(false);
// get declarations from directly referenced projects and metadata
foreach (var assembly in compilation.GetReferencedAssemblySymbols())
if (includeDirectReferences)
{
var assemblyProject = project.Solution.GetProject(assembly, cancellationToken);
if (assemblyProject != null)
{
await AddDeclarationsAsync(assemblyProject, compilation, assembly, name, ignoreCase, criteria, list, cancellationToken).ConfigureAwait(false);
}
else
foreach (var assembly in compilation.GetReferencedAssemblySymbols())
{
await AddDeclarationsAsync(project.Solution, assembly, GetMetadataReferenceFilePath(compilation.GetMetadataReference(assembly)), name, ignoreCase, criteria, list, cancellationToken).ConfigureAwait(false);
var assemblyProject = project.Solution.GetProject(assembly, cancellationToken);
if (assemblyProject != null)
{
await AddDeclarationsAsync(assemblyProject, compilation, assembly, name, ignoreCase, criteria, list, cancellationToken).ConfigureAwait(false);
}
else
{
await AddDeclarationsAsync(project.Solution, assembly, GetMetadataReferenceFilePath(compilation.GetMetadataReference(assembly)), name, ignoreCase, criteria, list, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -130,6 +145,14 @@ private static async Task AddDeclarationsAsync(Project project, Compilation star
}
}
internal static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Solution solution, IAssemblySymbol assembly, string filePath, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken)
{
var result = new List<ISymbol>();
await AddDeclarationsAsync(solution, assembly, filePath, name, ignoreCase, filter, result, cancellationToken).ConfigureAwait(false);
return result;
}
private static async Task AddDeclarationsAsync(
Solution solution, IAssemblySymbol assembly, string filePath, string name, bool ignoreCase, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册