提交 a767f3a7 编写于 作者: D David Poeschl

Change constructor ref node location in Find Refs

Fixes internal issue #1138943.

In the SymbolFinder API, references to constructors are included as references to both the constructor method symbol and the related type symbol. Because reference locations are deduplicated across all results shown in Find References, we have to decide which definition node to use as the parent. Prior to this change the first related definition returned to us by the SymbolFinder won, but this ordering was not guaranteed to be consistent. This change introduces a precedence ordering for definitions returned by the SymbolFinder that currently guarantees that members will be preferred over types.

Additionally, this change removes the requirement that definitions shown in Find References have distinct locations. This allows us to meaningfully separate references between a type and its default constructor which has the same location.
上级 795ce59a
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Imports Microsoft.CodeAnalysis.Navigation
Imports Microsoft.VisualStudio.Language.CallHierarchy
......@@ -267,8 +268,8 @@ class D : C
testState.Navigate(root, EditorFeaturesResources.Overrides, "D.foo()")
Dim mockNavigationService = DirectCast(testState.Workspace.Services.GetService(Of ISymbolNavigationService)(), MockSymbolNavigationServiceProvider.MockSymbolNavigationService)
Assert.NotNull(mockNavigationService.Symbol)
Assert.NotNull(mockNavigationService.Project)
Assert.NotNull(mockNavigationService.TryNavigateToSymbolProvidedSymbol)
Assert.NotNull(mockNavigationService.TryNavigateToSymbolProvidedProject)
End Sub
<WorkItem(1022864)>
......@@ -306,8 +307,8 @@ namespace N
testState.Navigate(root, String.Format(EditorFeaturesResources.CallsTo, "Foo"), "N.G.Main()")
Dim navigationService = DirectCast(testState.Workspace.Services.GetService(Of IDocumentNavigationService)(), MockDocumentNavigationServiceProvider.MockDocumentNavigationService)
Assert.NotEqual(navigationService.DocumentId, Nothing)
Assert.NotEqual(navigationService.TextSpan, Nothing)
Assert.NotEqual(navigationService.ProvidedDocumentId, Nothing)
Assert.NotEqual(navigationService.ProvidedTextSpan, Nothing)
End Sub
End Class
......
......@@ -191,8 +191,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CallHierarchy\CallHierarchyTests.vb" />
<Compile Include="CallHierarchy\MockDocumentNavigationServiceProvider.vb" />
<Compile Include="CallHierarchy\MockSymbolNavigationServiceProvider.vb" />
<Compile Include="Utilities\MockDocumentNavigationServiceProvider.vb" />
<Compile Include="Utilities\MockSymbolNavigationServiceProvider.vb" />
<Compile Include="CodeFixes\CodeFixServiceTests.vb" />
<Compile Include="Compilation\CompilationTests.vb" />
<Compile Include="Diagnostics\AbstractCrossLanguageUserDiagnosticTest.vb" />
......@@ -339,4 +339,4 @@
<Import Project="..\..\..\build\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -6,7 +6,7 @@ Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Navigation
Imports Microsoft.CodeAnalysis.Text
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.CallHierarchy
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
' Note: by default, TestWorkspace produces a composition from all assemblies except EditorServicesTest2.
' This type has to be defined here until we get that cleaned up. Otherwise, other tests may import it.
<ExportWorkspaceServiceFactory(GetType(IDocumentNavigationService), ServiceLayer.Host), [Shared]>
......@@ -22,33 +22,68 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.CallHierarchy
Friend Class MockDocumentNavigationService
Implements IDocumentNavigationService
Public DocumentId As DocumentId
Public TextSpan As TextSpan
Public ProvidedDocumentId As DocumentId
Public ProvidedTextSpan As TextSpan
Public ProvidedLineNumber As Integer
Public ProvidedOffset As Integer
Public ProvidedPosition As Integer
Public ProvidedVirtualSpace As Integer
Public ProvidedUsePreviewTab As Boolean
Public CanNavigateToLineAndOffsetReturnValue As Boolean = True
Public CanNavigateToPositionReturnValue As Boolean = True
Public CanNavigateToSpanReturnValue As Boolean = True
Public TryNavigateToLineAndOffsetReturnValue As Boolean = True
Public TryNavigateToPositionReturnValue As Boolean = True
Public TryNavigateToSpanReturnValue As Boolean = True
Public Function CanNavigateToLineAndOffset(workspace As Workspace, documentId As DocumentId, lineNumber As Integer, offset As Integer) As Boolean Implements IDocumentNavigationService.CanNavigateToLineAndOffset
Throw New NotImplementedException()
Me.ProvidedDocumentId = documentId
Me.ProvidedLineNumber = lineNumber
Return CanNavigateToLineAndOffsetReturnValue
End Function
Public Function CanNavigateToPosition(workspace As Workspace, documentId As DocumentId, position As Integer, Optional virtualSpace As Integer = 0) As Boolean Implements IDocumentNavigationService.CanNavigateToPosition
Throw New NotImplementedException()
Me.ProvidedDocumentId = documentId
Me.ProvidedPosition = position
Me.ProvidedVirtualSpace = virtualSpace
Return CanNavigateToPositionReturnValue
End Function
Public Function CanNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan) As Boolean Implements IDocumentNavigationService.CanNavigateToSpan
Throw New NotImplementedException()
Me.ProvidedDocumentId = documentId
Me.ProvidedTextSpan = textSpan
Return CanNavigateToSpanReturnValue
End Function
Public Function TryNavigateToLineAndOffset(workspace As Workspace, documentId As DocumentId, lineNumber As Integer, offset As Integer, Optional usePreviewTab As Boolean = False) As Boolean Implements IDocumentNavigationService.TryNavigateToLineAndOffset
Throw New NotImplementedException()
Me.ProvidedDocumentId = documentId
Me.ProvidedLineNumber = lineNumber
Me.ProvidedOffset = offset
Me.ProvidedUsePreviewTab = usePreviewTab
Return TryNavigateToLineAndOffsetReturnValue
End Function
Public Function TryNavigateToPosition(workspace As Workspace, documentId As DocumentId, position As Integer, Optional virtualSpace As Integer = 0, Optional usePreviewTab As Boolean = False) As Boolean Implements IDocumentNavigationService.TryNavigateToPosition
Throw New NotImplementedException()
Me.ProvidedDocumentId = documentId
Me.ProvidedPosition = position
Me.ProvidedVirtualSpace = virtualSpace
Me.ProvidedUsePreviewTab = usePreviewTab
Return TryNavigateToPositionReturnValue
End Function
Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, Optional usePreviewTab As Boolean = False) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan
Me.DocumentId = documentId
Me.TextSpan = textSpan
Return True
Me.ProvidedDocumentId = documentId
Me.ProvidedTextSpan = textSpan
Me.ProvidedUsePreviewTab = usePreviewTab
Return TryNavigateToSpanReturnValue
End Function
End Class
End Class
......
......@@ -5,7 +5,7 @@ Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Navigation
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.CallHierarchy
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
' Note: by default, TestWorkspace produces a composition from all assemblies except EditorServicesTest2.
' This type has to be defined here until we get that cleaned up. Otherwise, other tests may import it.
<ExportWorkspaceServiceFactory(GetType(ISymbolNavigationService), ServiceLayer.Host), [Shared]>
......@@ -21,22 +21,44 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.CallHierarchy
Friend Class MockSymbolNavigationService
Implements ISymbolNavigationService
Public Symbol As ISymbol
Public Project As Project
Public TryNavigateToSymbolProvidedSymbol As ISymbol
Public TryNavigateToSymbolProvidedProject As Project
Public TryNavigateToSymbolProvidedUsePreviewTab As Boolean
Public TrySymbolNavigationNotifyProvidedSymbol As ISymbol
Public TrySymbolNavigationNotifyProvidedSolution As Solution
Public TrySymbolNavigationNotifyReturnValue As Boolean = False
Public WouldNavigateToSymbolProvidedSymbol As ISymbol
Public WouldNavigateToSymbolProvidedSolution As Solution
Public WouldNavigateToSymbolReturnValue As Boolean = False
Public NavigationFilePathReturnValue As String = String.Empty
Public NavigationLineNumberReturnValue As Integer = 0
Public NavigationCharOffsetReturnValue As Integer = 0
Public Function TryNavigateToSymbol(symbol As ISymbol, project As Project, Optional usePreviewTab As Boolean = False) As Boolean Implements ISymbolNavigationService.TryNavigateToSymbol
Me.Symbol = symbol
Me.Project = project
Me.TryNavigateToSymbolProvidedSymbol = symbol
Me.TryNavigateToSymbolProvidedProject = project
Me.TryNavigateToSymbolProvidedUsePreviewTab = usePreviewTab
Return True
End Function
Public Function TrySymbolNavigationNotify(symbol As ISymbol, solution As Solution) As Boolean Implements ISymbolNavigationService.TrySymbolNavigationNotify
Throw New NotImplementedException()
Me.TrySymbolNavigationNotifyProvidedSymbol = symbol
Me.TrySymbolNavigationNotifyProvidedSolution = solution
Return TrySymbolNavigationNotifyReturnValue
End Function
Public Function WouldNavigateToSymbol(symbol As ISymbol, solution As Solution, ByRef filePath As String, ByRef lineNumber As Integer, ByRef charOffset As Integer) As Boolean Implements ISymbolNavigationService.WouldNavigateToSymbol
Throw New NotImplementedException()
Me.WouldNavigateToSymbolProvidedSymbol = symbol
Me.WouldNavigateToSymbolProvidedSolution = solution
filePath = Me.NavigationFilePathReturnValue
lineNumber = Me.NavigationLineNumberReturnValue
charOffset = Me.NavigationCharOffsetReturnValue
Return WouldNavigateToSymbolReturnValue
End Function
End Class
End Class
......
// 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 Microsoft.CodeAnalysis;
......@@ -34,7 +35,8 @@ public void PresentReferencedSymbols(string title, Solution solution, IEnumerabl
PresentObjectList(title, new ObjectList(CreateFindReferencesItems(solution, items), this));
}
private IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
// internal for test purposes
internal IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
{
var definitions = new List<AbstractTreeItem>();
var uniqueLocations = new HashSet<ValueTuple<Document, TextSpan>>();
......@@ -42,7 +44,7 @@ private IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEn
referencedSymbols = referencedSymbols.FilterUnreferencedSyntheticDefinitions().ToList();
foreach (var referencedSymbol in referencedSymbols)
foreach (var referencedSymbol in referencedSymbols.OrderBy(GetDefinitionPrecedence))
{
if (!IncludeDefinition(referencedSymbol))
{
......@@ -54,11 +56,11 @@ private IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEn
foreach (var definitionLocation in definition.Locations)
{
var definitionItem = ConvertToDefinitionItem(solution, referencedSymbol, uniqueLocations, definitionLocation, definition.GetGlyph());
var definitionItem = ConvertToDefinitionItem(solution, referencedSymbol, definitionLocation, definition.GetGlyph());
if (definitionItem != null)
{
definitions.Add(definitionItem);
var referenceItems = CreateReferenceItems(solution, uniqueLocations, referencedSymbol.Locations.Select(loc => loc.Location), Glyph.Reference);
var referenceItems = CreateReferenceItems(solution, uniqueLocations, referencedSymbol.Locations.Select(loc => loc.Location));
definitionItem.Children.AddRange(referenceItems);
definitionItem.SetReferenceCount(referenceItems.Count);
}
......@@ -76,10 +78,44 @@ private IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEn
return definitions;
}
/// <summary>
/// Reference locations are deduplicated across the entire find references result set
/// Order the definitions so that references to multiple definitions appear under the
/// desired definition (e.g. constructor references should prefer the constructor method
/// over the type definition). Note that this does not change the order in which
/// definitions are displayed in Find Symbol Results, it only changes which definition
/// a given reference should appear under when its location is a reference to multiple
/// definitions.
/// </summary>
private int GetDefinitionPrecedence(ReferencedSymbol referencedSymbol)
{
switch (referencedSymbol.Definition.Kind)
{
case SymbolKind.Event:
case SymbolKind.Field:
case SymbolKind.Label:
case SymbolKind.Local:
case SymbolKind.Method:
case SymbolKind.Parameter:
case SymbolKind.Property:
case SymbolKind.RangeVariable:
return 0;
case SymbolKind.ArrayType:
case SymbolKind.DynamicType:
case SymbolKind.ErrorType:
case SymbolKind.NamedType:
case SymbolKind.PointerType:
return 1;
default:
return 2;
}
}
private AbstractTreeItem ConvertToDefinitionItem(
Solution solution,
ReferencedSymbol referencedSymbol,
HashSet<ValueTuple<Document, TextSpan>> uniqueLocations,
Location location,
Glyph glyph)
{
......@@ -96,8 +132,7 @@ private IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEn
var document = solution.GetDocument(location.SourceTree);
var sourceSpan = location.SourceSpan;
if (!IsValidSourceLocation(document, sourceSpan) ||
!uniqueLocations.Add(new ValueTuple<Document, TextSpan>(document, sourceSpan)))
if (!IsValidSourceLocation(document, sourceSpan))
{
return null;
}
......@@ -105,10 +140,9 @@ private IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IEn
return new SourceDefinitionTreeItem(document, sourceSpan, referencedSymbol.Definition, glyph.GetGlyphIndex());
}
private IList<SourceReferenceTreeItem> CreateReferenceItems(Solution solution, HashSet<ValueTuple<Document, TextSpan>> uniqueLocations, IEnumerable<Location> locations, Glyph glyph)
private IList<SourceReferenceTreeItem> CreateReferenceItems(Solution solution, HashSet<ValueTuple<Document, TextSpan>> uniqueLocations, IEnumerable<Location> locations)
{
var referenceItems = new List<SourceReferenceTreeItem>();
foreach (var location in locations)
{
if (!location.IsInSource)
......@@ -125,7 +159,7 @@ private IList<SourceReferenceTreeItem> CreateReferenceItems(Solution solution, H
if (uniqueLocations.Add(new ValueTuple<Document, TextSpan>(document, sourceSpan)))
{
referenceItems.Add(new SourceReferenceTreeItem(document, sourceSpan, glyph.GetGlyphIndex()));
referenceItems.Add(new SourceReferenceTreeItem(document, sourceSpan, Glyph.Reference.GetGlyphIndex()));
}
}
......
......@@ -43,7 +43,7 @@ public override int GoToSource()
internal override void SetReferenceCount(int referenceCount)
{
var referenceCountDisplay = referenceCount == 1
? string.Format(ServicesVSResources.ReferenceCountSingular, referenceCount)
? ServicesVSResources.ReferenceCountSingular
: string.Format(ServicesVSResources.ReferenceCountPlural, referenceCount);
this.DisplayText = $"[{_assemblyName}] {_symbolDefinition} ({referenceCountDisplay})";
......
......@@ -20,7 +20,7 @@ public SourceDefinitionTreeItem(Document document, TextSpan sourceSpan, ISymbol
internal override void SetReferenceCount(int referenceCount)
{
var referenceCountDisplay = referenceCount == 1
? string.Format(ServicesVSResources.ReferenceCountSingular, referenceCount)
? ServicesVSResources.ReferenceCountSingular
: string.Format(ServicesVSResources.ReferenceCountPlural, referenceCount);
this.DisplayText = $"[{_projectName}] {_symbolDisplay} ({referenceCountDisplay})";
......
......@@ -850,7 +850,7 @@ internal class ServicesVSResources {
}
/// <summary>
/// Looks up a localized string similar to {0} reference.
/// Looks up a localized string similar to 1 reference.
/// </summary>
internal static string ReferenceCountSingular {
get {
......
......@@ -451,6 +451,6 @@ Use the dropdown to view and switch to other projects this file may belong to.</
<value>{0} references</value>
</data>
<data name="ReferenceCountSingular" xml:space="preserve">
<value>{0} reference</value>
<value>1 reference</value>
</data>
</root>
\ No newline at end of file
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Text
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.UnitTests
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.FindSymbols
Imports Microsoft.VisualStudio.Composition
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ObjectBrowser.Mocks
Imports Roslyn.Test.Utilities
Imports Roslyn.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.FindResults
Public Class FindResultsTests
<Fact, Trait(Traits.Feature, Traits.Features.FindReferences)>
<WorkItem(1138943)>
Public Sub ConstructorReferencesShouldNotAppearUnderClassNodeInCSharp()
Dim markup = <Text><![CDATA[
class $$C
{
const int z = 1;
public C() { }
public C(int x) { }
void T()
{
var a = new C();
var b = new C(5);
var c = C.z;
}
}"]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
New TestFindResult($"[CSharpAssembly1] C.C() ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("CSharpAssembly1\Test1.cs - (11, 21) : var a = new C();")),
New TestFindResult($"[CSharpAssembly1] C.C(int) ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("CSharpAssembly1\Test1.cs - (12, 21) : var b = new C(5);")),
New TestFindResult($"[CSharpAssembly1] class C ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("CSharpAssembly1\Test1.cs - (13, 17) : var c = C.z;"))
}
Verify(markup, LanguageNames.CSharp, expectedResults)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.FindReferences)>
<WorkItem(1138943)>
Public Sub ConstructorReferencesShouldNotAppearUnderClassNodeInVisualBasic()
Dim markup = <Text><![CDATA[
Class C$$
Const z = 1
Public Sub New()
End Sub
Public Sub New(x As Integer)
End Sub
Sub T()
Dim a = New C()
Dim b = New C(5)
Dim d = C.z
End Sub
End Class"]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
New TestFindResult($"[VisualBasicAssembly1] Class C ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("VisualBasicAssembly1\Test1.vb - (14, 17) : Dim d = C.z")),
New TestFindResult($"[VisualBasicAssembly1] Sub C.New() ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("VisualBasicAssembly1\Test1.vb - (12, 21) : Dim a = New C()")),
New TestFindResult($"[VisualBasicAssembly1] Sub C.New(Integer) ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("VisualBasicAssembly1\Test1.vb - (13, 21) : Dim b = New C(5)"))
}
Verify(markup, LanguageNames.VisualBasic, expectedResults)
End Sub
Private Shared ReadOnly ExportProvider As ExportProvider = MinimalTestExportProvider.CreateExportProvider(
TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic.WithParts(
GetType(MockDocumentNavigationServiceProvider),
GetType(MockSymbolNavigationServiceProvider)))
Private Sub Verify(markup As XElement, languageName As String, expectedResults As IList(Of AbstractTreeItem))
Dim workspaceXml =
<Workspace>
<Project Language=<%= languageName %> CommonReferences="true">
<Document><%= markup.NormalizedValue %></Document>
</Project>
</Workspace>
Using workspace = TestWorkspaceFactory.CreateWorkspace(workspaceXml, exportProvider:=ExportProvider)
Dim doc = workspace.Documents.Single()
Dim workspaceDoc = workspace.CurrentSolution.GetDocument(doc.Id)
If Not doc.CursorPosition.HasValue Then
Assert.True(False, "Missing caret location in document.")
End If
Dim symbol = SymbolFinder.FindSymbolAtPositionAsync(workspaceDoc, doc.CursorPosition.Value, CancellationToken.None).Result
Assert.NotNull(symbol)
Dim result = SymbolFinder.FindReferencesAsync(symbol, workspace.CurrentSolution, CancellationToken.None).Result
Dim libraryManager = New LibraryManager(New MockServiceProvider(New MockComponentModel(workspace.ExportProvider)))
Dim findReferencesTree = libraryManager.CreateFindReferencesItems(workspace.CurrentSolution, result)
' We cannot control the ordering of top-level nodes in the Find Symbol References window, so do not consider ordering of these items here.
expectedResults = expectedResults.OrderBy(Function(n) n.DisplayText).ToList()
findReferencesTree = findReferencesTree.OrderBy(Function(n) n.DisplayText).ToList()
VerifyResultsTree(expectedResults, findReferencesTree)
End Using
End Sub
Private Sub VerifyResultsTree(expectedResults As IList(Of AbstractTreeItem), findReferencesTree As IList(Of AbstractTreeItem))
Assert.True(expectedResults.Count = findReferencesTree.Count, $"Unexpected number of results. Expected: {expectedResults.Count} Actual: {findReferencesTree.Count}
Expected Items:
{GetResultText(expectedResults)}
Actual Items:
{GetResultText(findReferencesTree)}
")
For index = 0 To expectedResults.Count - 1
Dim expectedItem = expectedResults(index)
Dim actualItem = findReferencesTree(index)
Assert.Equal(expectedItem.DisplayText, actualItem.DisplayText)
Dim expectedHasChildren = expectedItem.Children IsNot Nothing AndAlso expectedItem.Children.Count > 0
Dim actualHasChildren = actualItem.Children IsNot Nothing AndAlso actualItem.Children.Count > 0
Assert.Equal(expectedHasChildren, actualHasChildren)
If expectedHasChildren Then
VerifyResultsTree(expectedItem.Children, actualItem.Children)
End If
Next
End Sub
Private Function GetResultText(references As IList(Of AbstractTreeItem)) As String
Dim indentString = String.Empty
Dim stringBuilder = New StringBuilder()
GetResultTextWorker(references, stringBuilder, indentString)
Return stringBuilder.ToString()
End Function
Private Sub GetResultTextWorker(references As IList(Of AbstractTreeItem), stringBuilder As StringBuilder, indentString As String)
For Each reference In references
stringBuilder.Append(indentString)
stringBuilder.AppendLine(reference.DisplayText)
If reference.Children IsNot Nothing AndAlso reference.Children.Any() Then
GetResultTextWorker(reference.Children, stringBuilder, indentString + " ")
End If
Next
End Sub
Private Class TestFindResult
Inherits AbstractTreeItem
Public Sub New(displayText As String, ParamArray children As TestFindResult())
MyBase.New(0)
Me.DisplayText = displayText
Me.Children = If(children.Length > 0, children, Nothing)
End Sub
Public Overrides Function GoToSource() As Integer
Throw New NotImplementedException()
End Function
End Class
End Class
End Namespace
......@@ -325,6 +325,7 @@
<Compile Include="EditAndContinue\EditAndContinueWorkspaceServiceTests.vb" />
<Compile Include="EditAndContinue\VsReadOnlyDocumentTrackerTests.vb" />
<Compile Include="ExtractInterface\ExtractInterfaceViewModelTests.vb" />
<Compile Include="FindResults\FindResultsTests.vb" />
<Compile Include="GenerateType\GenerateTypeViewModelTests.vb" />
<Compile Include="GoToDefinition\GoToDefinitionApiTests.vb" />
<Compile Include="GoToDefinition\MockNavigableItemsPresenter.vb" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册