From e32ef2d28fc4385c57c80bc6cf102fcb35a5cca8 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 30 May 2017 12:48:47 -0700 Subject: [PATCH 1/3] Fix crash in DocHighlights when delegating to a different language. --- .../AbstractDocumentHighlightsService.cs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs index 91b1933bd7692..d0ce1e96acc00 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs @@ -76,8 +76,8 @@ internal abstract partial class AbstractDocumentHighlightsService : IDocumentHig // Get unique tags for referenced symbols return await GetTagsForReferencedSymbolAsync( - new SymbolAndProjectId(symbol, document.Project.Id), documentsToSearch, - solution, cancellationToken).ConfigureAwait(false); + new SymbolAndProjectId(symbol, document.Project.Id), + document, documentsToSearch, cancellationToken).ConfigureAwait(false); } private static async Task GetSymbolToSearchAsync(Document document, int position, SemanticModel semanticModel, ISymbol symbol, CancellationToken cancellationToken) @@ -95,8 +95,8 @@ private static async Task GetSymbolToSearchAsync(Document document, int private async Task> GetTagsForReferencedSymbolAsync( SymbolAndProjectId symbolAndProjectId, + Document document, IImmutableSet documentsToSearch, - Solution solution, CancellationToken cancellationToken) { var symbol = symbolAndProjectId.Symbol; @@ -106,11 +106,11 @@ private static async Task GetSymbolToSearchAsync(Document document, int var progress = new StreamingProgressCollector( StreamingFindReferencesProgress.Instance); await SymbolFinder.FindReferencesAsync( - symbolAndProjectId, solution, progress, + symbolAndProjectId, document.Project.Solution, progress, documentsToSearch, cancellationToken).ConfigureAwait(false); return await FilterAndCreateSpansAsync( - progress.GetReferencedSymbols(), solution, documentsToSearch, + progress.GetReferencedSymbols(), document, documentsToSearch, symbol, cancellationToken).ConfigureAwait(false); } @@ -142,10 +142,12 @@ private static bool ShouldConsiderSymbol(ISymbol symbol) } private async Task> FilterAndCreateSpansAsync( - IEnumerable references, Solution solution, - IImmutableSet documentsToSearch, ISymbol symbol, + IEnumerable references, Document document, + IImmutableSet documentsToSearch, ISymbol symbol, CancellationToken cancellationToken) { + var solution = document.Project.Solution; + references = references.FilterToItemsToShow(); references = references.FilterNonMatchingMethodNames(solution, symbol); references = references.FilterToAliasMatches(symbol as IAliasSymbol); @@ -157,13 +159,20 @@ private static bool ShouldConsiderSymbol(ISymbol symbol) var additionalReferences = new List(); - foreach (var document in documentsToSearch) + foreach (var additionalDocument in documentsToSearch) { - additionalReferences.AddRange(await GetAdditionalReferencesAsync(document, symbol, cancellationToken).ConfigureAwait(false)); + // 'documentsToSearch' may contain documents from languages other than our own + // (for example cshtml files when we're searching the cs document). Since we're + // delegating to a virtual method for this language type, we have to make sure + // we only process the document if it's also our language. + if (additionalDocument.Project.Language == document.Project.Language) + { + additionalReferences.AddRange(await GetAdditionalReferencesAsync(document, symbol, cancellationToken).ConfigureAwait(false)); + } } return await CreateSpansAsync( - solution, symbol, references, additionalReferences, + solution, symbol, references, additionalReferences, documentsToSearch, cancellationToken).ConfigureAwait(false); } From 0c0f1a815e1f50c06dd0973e995c63396de1e5cb Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 30 May 2017 16:32:50 -0700 Subject: [PATCH 2/3] Update local names. --- .../AbstractDocumentHighlightsService.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs index d0ce1e96acc00..48b70f0fbc63c 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs @@ -142,11 +142,11 @@ private static bool ShouldConsiderSymbol(ISymbol symbol) } private async Task> FilterAndCreateSpansAsync( - IEnumerable references, Document document, + IEnumerable references, Document startingDocument, IImmutableSet documentsToSearch, ISymbol symbol, CancellationToken cancellationToken) { - var solution = document.Project.Solution; + var solution = startingDocument.Project.Solution; references = references.FilterToItemsToShow(); references = references.FilterNonMatchingMethodNames(solution, symbol); @@ -159,15 +159,15 @@ private static bool ShouldConsiderSymbol(ISymbol symbol) var additionalReferences = new List(); - foreach (var additionalDocument in documentsToSearch) + foreach (var currentDocument in documentsToSearch) { // 'documentsToSearch' may contain documents from languages other than our own // (for example cshtml files when we're searching the cs document). Since we're // delegating to a virtual method for this language type, we have to make sure // we only process the document if it's also our language. - if (additionalDocument.Project.Language == document.Project.Language) + if (currentDocument.Project.Language == startingDocument.Project.Language) { - additionalReferences.AddRange(await GetAdditionalReferencesAsync(document, symbol, cancellationToken).ConfigureAwait(false)); + additionalReferences.AddRange(await GetAdditionalReferencesAsync(currentDocument, symbol, cancellationToken).ConfigureAwait(false)); } } From 02b53323a21944d7ab7acf4d3213a8c117e187cd Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 30 May 2017 16:45:22 -0700 Subject: [PATCH 3/3] Add unit test for this case. --- .../Test2/EditorServicesTest2.vbproj | 1 + .../DocumentHighlightsServiceTests.vb | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb diff --git a/src/EditorFeatures/Test2/EditorServicesTest2.vbproj b/src/EditorFeatures/Test2/EditorServicesTest2.vbproj index fbbb505f5d119..d6707e52f89c5 100644 --- a/src/EditorFeatures/Test2/EditorServicesTest2.vbproj +++ b/src/EditorFeatures/Test2/EditorServicesTest2.vbproj @@ -249,6 +249,7 @@ + diff --git a/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb b/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb new file mode 100644 index 0000000000000..4584f528b096d --- /dev/null +++ b/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb @@ -0,0 +1,45 @@ +Imports System.Collections.Immutable +Imports System.Threading +Imports System.Threading.Tasks +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.ReferenceHighlighting + Public Class DocumentHighlightsServiceTests + + + + Public Async Function TestMultipleLanguagesPassedToAPI() As Task + Dim workspaceElement = + + + + class C + { + $$string Blah() + { + return null; + } + } + + + + + Class VBClass + End Class + + + + Using workspace = TestWorkspace.Create(workspaceElement) + Dim position = workspace.DocumentWithCursor.CursorPosition.Value + + Dim solution = workspace.CurrentSolution + Dim csharpDocument = solution.Projects.Single(Function(p) p.Language = LanguageNames.CSharp).Documents.Single() + Dim vbDocument = solution.Projects.Single(Function(p) p.Language = LanguageNames.VisualBasic).Documents.Single() + + Dim service = csharpDocument.GetLanguageService(Of Microsoft.CodeAnalysis.DocumentHighlighting.IDocumentHighlightsService) + Await service.GetDocumentHighlightsAsync( + csharpDocument, position, ImmutableHashSet.Create(csharpDocument, vbDocument), CancellationToken.None) + End Using + End Function + End Class +End Namespace \ No newline at end of file