提交 ef062ad7 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Revert "Revert "Remove the synchronous find-refs window.""

上级 c123c6a9
......@@ -108,7 +108,6 @@
<Compile Include="EventHookup\IHACK_EventHookupDismissalOnBufferChangePreventerService.cs" />
<Compile Include="ExtractInterface\ExtractInterfaceCommandHandler.cs" />
<Compile Include="ExtractMethod\ExtractMethodCommandHandler.cs" />
<Compile Include="FindReferences\CSharpFindReferencesService.cs" />
<Compile Include="FindUsages\CSharpFindUsagesService.cs" />
<Compile Include="Formatting\CSharpEditorFormattingService.cs" />
<Compile Include="Formatting\Indentation\CSharpIndentationService.cs" />
......
// 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 System.Composition;
using Microsoft.CodeAnalysis.Editor.FindReferences;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Editor.CSharp.FindReferences
{
[ExportLanguageService(typeof(IFindReferencesService), LanguageNames.CSharp), Shared]
internal class CSharpFindReferencesService : AbstractFindReferencesService
{
[ImportingConstructor]
public CSharpFindReferencesService(
[ImportMany] IEnumerable<IDefinitionsAndReferencesPresenter> referencedSymbolsPresenters,
[ImportMany] IEnumerable<INavigableItemsPresenter> navigableItemsPresenters)
: base(referencedSymbolsPresenters, navigableItemsPresenters)
{
}
}
}
\ No newline at end of file
......@@ -262,7 +262,6 @@
<Compile Include="Implementation\Diagnostics\SuggestionAdornmentManagerProvider.cs" />
<Compile Include="Implementation\Diagnostics\SuggestionTag.cs" />
<Compile Include="FindUsages\AbstractFindUsagesService.ProgressAdapter.cs" />
<Compile Include="GoToImplementation\IGoToImplementationService.cs" />
<Compile Include="Implementation\Intellisense\Completion\BraceCompletionMetadata.cs" />
<Compile Include="Implementation\Intellisense\Completion\OptionSetExtensions.cs" />
<Compile Include="Implementation\Intellisense\Completion\Presentation\ClassificationTags.cs" />
......@@ -289,9 +288,7 @@
<Compile Include="Implementation\TodoComment\TodoItemsUpdatedArgs.cs" />
<Compile Include="Host\ICallHierarchyPresenter.cs" />
<Compile Include="Host\IPreviewPaneService.cs" />
<Compile Include="Host\INavigableItemsPresenter.cs" />
<Compile Include="Host\IPreviewDialogService.cs" />
<Compile Include="Host\IDefinitionsAndReferencesPresenter.cs" />
<Compile Include="Host\IWaitContext.cs" />
<Compile Include="Host\IWaitIndicator.cs" />
<Compile Include="IBraceMatchingService.cs" />
......@@ -380,9 +377,7 @@
<Compile Include="Implementation\EndConstructGeneration\IEndConstructGenerationService.cs" />
<Compile Include="Implementation\ExtractInterface\AbstractExtractInterfaceCommandHandler.cs" />
<Compile Include="Implementation\ExtractMethod\AbstractExtractMethodCommandHandler.cs" />
<Compile Include="FindReferences\AbstractFindReferencesService.cs" />
<Compile Include="FindReferences\FindReferencesCommandHandler.cs" />
<Compile Include="FindReferences\IFindReferencesService.cs" />
<Compile Include="Implementation\ForegroundNotification\ForegroundNotificationService.cs" />
<Compile Include="Implementation\Formatting\FormatCommandHandler.cs" />
<Compile Include="Implementation\Formatting\FormatCommandHandler.ReturnKey.cs" />
......
// 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 Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.FindReferences
{
internal abstract partial class AbstractFindReferencesService :
ForegroundThreadAffinitizedObject, IFindReferencesService
{
private readonly IEnumerable<IDefinitionsAndReferencesPresenter> _referenceSymbolPresenters;
private readonly IEnumerable<INavigableItemsPresenter> _navigableItemPresenters;
protected AbstractFindReferencesService(
IEnumerable<IDefinitionsAndReferencesPresenter> referenceSymbolPresenters,
IEnumerable<INavigableItemsPresenter> navigableItemPresenters)
{
_referenceSymbolPresenters = referenceSymbolPresenters;
_navigableItemPresenters = navigableItemPresenters;
}
private async Task<Tuple<IEnumerable<ReferencedSymbol>, Solution>> FindReferencedSymbolsAsync(
Document document, int position, IWaitContext waitContext)
{
var cancellationToken = waitContext.CancellationToken;
var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
document, position, cancellationToken).ConfigureAwait(false);
if (symbolAndProject == null)
{
return null;
}
var symbol = symbolAndProject?.symbol;
var project = symbolAndProject?.project;
var displayName = FindUsagesHelpers.GetDisplayName(symbol);
waitContext.Message = string.Format(
EditorFeaturesResources.Finding_references_of_0, displayName);
var result = await SymbolFinder.FindReferencesAsync(symbol, project.Solution, cancellationToken).ConfigureAwait(false);
return Tuple.Create(result, project.Solution);
}
public bool TryFindReferences(Document document, int position, IWaitContext waitContext)
{
var cancellationToken = waitContext.CancellationToken;
var result = this.FindReferencedSymbolsAsync(document, position, waitContext).WaitAndGetResult(cancellationToken);
return TryDisplayReferences(result, cancellationToken);
}
private bool TryDisplayReferences(IEnumerable<INavigableItem> result)
{
if (result != null && result.Any())
{
var title = result.First().DisplayTaggedParts.JoinText();
foreach (var presenter in _navigableItemPresenters)
{
presenter.DisplayResult(title, result);
return true;
}
}
return false;
}
private bool TryDisplayReferences(
Tuple<IEnumerable<ReferencedSymbol>, Solution> result,
CancellationToken cancellationToken)
{
if (result != null && result.Item1 != null)
{
var solution = result.Item2;
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
var definitionsAndReferences = factory.CreateDefinitionsAndReferences(
solution, result.Item1, includeHiddenLocations: false, cancellationToken: cancellationToken);
foreach (var presenter in _referenceSymbolPresenters)
{
presenter.DisplayResult(definitionsAndReferences);
return true;
}
}
return false;
}
}
}
\ No newline at end of file
......@@ -22,7 +22,6 @@ namespace Microsoft.CodeAnalysis.Editor.FindReferences
[ExportCommandHandler(PredefinedCommandHandlerNames.FindReferences, ContentTypeNames.RoslynContentType)]
internal class FindReferencesCommandHandler : ICommandHandler<FindReferencesCommandArgs>
{
private readonly IEnumerable<IDefinitionsAndReferencesPresenter> _synchronousPresenters;
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IWaitIndicator _waitIndicator;
......@@ -31,16 +30,13 @@ internal class FindReferencesCommandHandler : ICommandHandler<FindReferencesComm
[ImportingConstructor]
internal FindReferencesCommandHandler(
IWaitIndicator waitIndicator,
[ImportMany] IEnumerable<IDefinitionsAndReferencesPresenter> synchronousPresenters,
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
[ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners)
{
Contract.ThrowIfNull(synchronousPresenters);
Contract.ThrowIfNull(streamingPresenters);
Contract.ThrowIfNull(asyncListeners);
_waitIndicator = waitIndicator;
_synchronousPresenters = synchronousPresenters;
_streamingPresenters = streamingPresenters;
_asyncListener = new AggregateAsynchronousOperationListener(
asyncListeners, FeatureAttribute.FindReferences);
......@@ -74,30 +70,18 @@ public void ExecuteCommand(FindReferencesCommandArgs args, Action nextHandler)
private bool TryExecuteCommand(int caretPosition, Document document)
{
var streamingService = document.GetLanguageService<IFindUsagesService>();
var synchronousService = document.GetLanguageService<IFindReferencesService>();
var streamingPresenter = GetStreamingPresenter();
// See if we're running on a host that can provide streaming results.
// We'll both need a FAR service that can stream results to us, and
// a presenter that can accept streamed results.
var streamingEnabled = document.Project.Solution.Workspace.Options.GetOption(FeatureOnOffOptions.StreamingFindReferences, document.Project.Language);
if (streamingEnabled && streamingService != null && streamingPresenter != null)
if (streamingService != null && streamingPresenter != null)
{
StreamingFindReferences(document, caretPosition, streamingService, streamingPresenter);
return true;
}
// Otherwise, either the language doesn't support streaming results,
// or the host has no way to present results in a streaming manner.
// Fall back to the old non-streaming approach to finding and presenting
// results.
if (synchronousService != null)
{
FindReferences(document, synchronousService, caretPosition);
return true;
}
return false;
}
......@@ -150,31 +134,5 @@ private IStreamingFindUsagesPresenter GetStreamingPresenter()
{
}
}
internal void FindReferences(
Document document, IFindReferencesService service, int caretPosition)
{
_waitIndicator.Wait(
title: EditorFeaturesResources.Find_References,
message: EditorFeaturesResources.Finding_references,
action: context =>
{
using (Logger.LogBlock(
FunctionId.CommandHandler_FindAllReference,
KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "legacy"),
context.CancellationToken))
{
if (!service.TryFindReferences(document, caretPosition, context))
{
// The service failed, so just present an empty list of references
foreach (var presenter in _synchronousPresenters)
{
presenter.DisplayResult(DefinitionsAndReferences.Empty);
return;
}
}
}
}, allowCancel: true);
}
}
}
\ 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.
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Editor
{
internal interface IFindReferencesService : ILanguageService
{
/// <summary>
/// Finds the references for the symbol at the specific position in the document and then
/// presents them.
/// </summary>
/// <returns>True if finding references of the symbol at the provided position succeeds. False, otherwise.</returns>
bool TryFindReferences(Document document, int position, IWaitContext waitContext);
}
}
\ No newline at end of file
......@@ -38,7 +38,7 @@ public Task ReportProgressAsync(int current, int maximum)
/// <summary>
/// Forwards IFindReferencesProgress calls to an IFindUsagesContext instance.
/// </summary>
private class FindReferencesProgressAdapter : ForegroundThreadAffinitizedObject, IStreamingFindReferencesProgress
internal class FindReferencesProgressAdapter : ForegroundThreadAffinitizedObject, IStreamingFindReferencesProgress
{
private readonly Solution _solution;
private readonly IFindUsagesContext _context;
......
// 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.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
......@@ -89,7 +90,13 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
var symbol = symbolAndProject?.symbol;
var project = symbolAndProject?.project;
return await FindReferencesAsync(
context, symbol, project, cancellationToken).ConfigureAwait(false);
}
public static async Task<FindReferencesProgressAdapter> FindReferencesAsync(
IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken)
{
context.SetSearchTitle(string.Format(EditorFeaturesResources._0_references,
FindUsagesHelpers.GetDisplayName(symbol)));
......
......@@ -33,32 +33,30 @@ internal partial class GoToImplementationCommandHandler : ICommandHandler<GoToIm
_streamingPresenters = streamingPresenters;
}
private (Document, IGoToImplementationService, IFindUsagesService) GetDocumentAndServices(ITextSnapshot snapshot)
private (Document, IFindUsagesService) GetDocumentAndService(ITextSnapshot snapshot)
{
var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
return (document,
document?.GetLanguageService<IGoToImplementationService>(),
document?.GetLanguageService<IFindUsagesService>());
return (document, document?.GetLanguageService<IFindUsagesService>());
}
public CommandState GetCommandState(GoToImplementationCommandArgs args, Func<CommandState> nextHandler)
{
// Because this is expensive to compute, we just always say yes as long as the language allows it.
var (document, implService, findUsagesService) = GetDocumentAndServices(args.SubjectBuffer.CurrentSnapshot);
return implService != null || findUsagesService != null
var (document, findUsagesService) = GetDocumentAndService(args.SubjectBuffer.CurrentSnapshot);
return findUsagesService != null
? CommandState.Available
: CommandState.Unavailable;
}
public void ExecuteCommand(GoToImplementationCommandArgs args, Action nextHandler)
{
var (document, implService, findUsagesService) = GetDocumentAndServices(args.SubjectBuffer.CurrentSnapshot);
if (implService != null || findUsagesService != null)
var (document, findUsagesService) = GetDocumentAndService(args.SubjectBuffer.CurrentSnapshot);
if (findUsagesService != null)
{
var caret = args.TextView.GetCaretPoint(args.SubjectBuffer);
if (caret.HasValue)
{
ExecuteCommand(document, caret.Value, implService, findUsagesService);
ExecuteCommand(document, caret.Value, findUsagesService);
return;
}
}
......@@ -67,17 +65,12 @@ public void ExecuteCommand(GoToImplementationCommandArgs args, Action nextHandle
}
private void ExecuteCommand(
Document document, int caretPosition,
IGoToImplementationService synchronousService,
IFindUsagesService streamingService)
Document document, int caretPosition, IFindUsagesService streamingService)
{
var streamingPresenter = GetStreamingPresenter();
var streamingEnabled = document.Project.Solution.Workspace.Options.GetOption(FeatureOnOffOptions.StreamingGoToImplementation, document.Project.Language);
var canUseStreamingWindow = streamingEnabled && streamingService != null;
var canUseSynchronousWindow = synchronousService != null;
if (canUseStreamingWindow || canUseSynchronousWindow)
if (streamingService != null)
{
// We have all the cheap stuff, so let's do expensive stuff now
string messageToShow = null;
......@@ -87,18 +80,10 @@ public void ExecuteCommand(GoToImplementationCommandArgs args, Action nextHandle
allowCancel: true,
action: context =>
{
if (canUseStreamingWindow)
{
StreamingGoToImplementation(
document, caretPosition,
streamingService, streamingPresenter,
context.CancellationToken, out messageToShow);
}
else
{
synchronousService.TryGoToImplementation(
document, caretPosition, context.CancellationToken, out messageToShow);
}
StreamingGoToImplementation(
document, caretPosition,
streamingService, streamingPresenter,
context.CancellationToken, out messageToShow);
});
if (messageToShow != null)
......
// 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.Threading;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Editor
{
internal interface IGoToImplementationService : ILanguageService
{
/// <summary>
/// Finds the implementations for the symbol at the specific position in the document and then
/// navigates to them.
/// </summary>
/// <returns>True if navigating to the implementation of the symbol at the provided position succeeds. False, otherwise.</returns>
bool TryGoToImplementation(Document document, int position, CancellationToken cancellationToken, out string message);
}
}
// 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 Microsoft.CodeAnalysis.FindUsages;
namespace Microsoft.CodeAnalysis.Editor.Host
{
internal interface IDefinitionsAndReferencesPresenter
{
void DisplayResult(DefinitionsAndReferences definitionsAndReferences);
}
}
\ 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.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Navigation;
namespace Microsoft.CodeAnalysis.Editor.Host
{
internal interface INavigableItemsPresenter
{
void DisplayResult(string title, IEnumerable<INavigableItem> items);
}
}
\ No newline at end of file
......@@ -89,13 +89,5 @@ internal static class FeatureOnOffOptions
[ExportOption]
public static readonly PerLanguageOption<bool> RefactoringVerification = new PerLanguageOption<bool>(
nameof(FeatureOnOffOptions), nameof(RefactoringVerification), defaultValue: false);
[ExportOption]
public static readonly PerLanguageOption<bool> StreamingFindReferences = new PerLanguageOption<bool>(
nameof(FeatureOnOffOptions), nameof(StreamingFindReferences), defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> StreamingGoToImplementation = new PerLanguageOption<bool>(
nameof(FeatureOnOffOptions), nameof(StreamingGoToImplementation), defaultValue: true);
}
}
\ No newline at end of file
......@@ -213,7 +213,6 @@
<Compile Include="Extensions\ITextSnapshotLineExtensionsTests.cs" />
<Compile Include="Extensions\SetExtensionTests.cs" />
<Compile Include="FindReferences\FindReferencesCommandHandlerTests.cs" />
<Compile Include="FindReferences\MockDefinitionsAndReferencesPresenter.cs" />
<Compile Include="LineSeparators\AdornmentManagerTests.cs" />
<Compile Include="LinkedFiles\LinkedFileDiffMergingEditorTests.cs" />
<Compile Include="MetadataAsSource\AbstractMetadataAsSourceTests.cs" />
......@@ -257,4 +256,4 @@
</ItemGroup>
<ItemGroup />
<Import Project="..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ 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.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Commands;
......@@ -19,18 +20,56 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences
{
public class FindReferencesCommandHandlerTests
{
private class MockFindUsagesContext : FindUsagesContext
{
public readonly List<DefinitionItem> Result = new List<DefinitionItem>();
public override Task OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (Result)
{
Result.Add(definition);
}
return SpecializedTasks.EmptyTask;
}
}
private class MockStreamingFindUsagesPresenter : IStreamingFindUsagesPresenter
{
private readonly FindUsagesContext _context;
public MockStreamingFindUsagesPresenter(FindUsagesContext context)
{
_context = context;
}
public FindUsagesContext StartSearch(string title, bool supportsReferences)
=> _context;
public void ClearAll()
{
}
}
[WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)]
public void TestFindReferencesSynchronousCall()
public async Task TestFindReferencesAsynchronousCall()
{
using (var workspace = TestWorkspace.CreateCSharp("class C { C() { new C(); } }"))
{
var findReferencesPresenter = new MockDefinitionsAndReferencesPresenter();
var context = new MockFindUsagesContext();
var presenter = new MockStreamingFindUsagesPresenter(context);
var waiter = new AsynchronousOperationListener();
var waiters =
SpecializedCollections.SingletonEnumerable(
new Lazy<IAsynchronousOperationListener, FeatureMetadata>(
() => waiter, new FeatureMetadata(new Dictionary<string, object>() { { "FeatureName", FeatureAttribute.FindReferences } })));
var handler = new FindReferencesCommandHandler(
TestWaitIndicator.Default,
SpecializedCollections.SingletonEnumerable(findReferencesPresenter),
SpecializedCollections.EmptyEnumerable<Lazy<IStreamingFindUsagesPresenter>>(),
workspace.ExportProvider.GetExports<IAsynchronousOperationListener, FeatureMetadata>());
SpecializedCollections.SingletonEnumerable(new Lazy<IStreamingFindUsagesPresenter>(() => presenter)),
waiters);
var textView = workspace.Documents[0].GetTextView();
textView.Caret.MoveTo(new SnapshotPoint(textView.TextSnapshot, 7));
......@@ -38,16 +77,17 @@ public void TestFindReferencesSynchronousCall()
textView,
textView.TextBuffer), () => { });
AssertResult(findReferencesPresenter.DefinitionsAndReferences, "C", ".ctor");
await waiter.CreateWaitTask();
AssertResult(context.Result, "C.C()", "class C");
}
}
private bool AssertResult(
DefinitionsAndReferences definitionsAndReferences,
private void AssertResult(
List<DefinitionItem> result,
params string[] definitions)
{
return definitionsAndReferences.Definitions.Select(r => r.DisplayParts.JoinText())
.SetEquals(definitions);
Assert.Equal(result.Select(kvp => kvp.DisplayParts.JoinText()).OrderBy(a => a),
definitions.OrderBy(a => a));
}
}
}
\ 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.
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.FindUsages;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences
{
internal class MockDefinitionsAndReferencesPresenter : IDefinitionsAndReferencesPresenter
{
public DefinitionsAndReferences DefinitionsAndReferences;
public void DisplayResult(DefinitionsAndReferences definitionsAndReferences)
{
DefinitionsAndReferences = definitionsAndReferences;
}
}
}
\ No newline at end of file
......@@ -91,7 +91,6 @@
<Compile Include="EndConstructGeneration\VisualBasicEndConstructGenerationService.vb" />
<Compile Include="ExtractInterface\ExtractInterfaceCommandHandler.vb" />
<Compile Include="ExtractMethod\ExtractMethodCommandHandler.vb" />
<Compile Include="FindReferences\VisualBasicFindReferencesService.vb" />
<Compile Include="FindUsages\VisualBasicFindUsagesService.vb" />
<Compile Include="Formatting\Indentation\SmartTokenFormatter.vb" />
<Compile Include="Formatting\Indentation\SmartTokenFormatterCommandHandler.vb" />
......
' 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.Composition
Imports Microsoft.CodeAnalysis.Editor.FindReferences
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.FindReferences
<ExportLanguageService(GetType(IFindReferencesService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicFindReferencesService
Inherits AbstractFindReferencesService
<ImportingConstructor>
Protected Sub New(<ImportMany> referencedSymbolsPresenters As IEnumerable(Of IDefinitionsAndReferencesPresenter),
<ImportMany> navigableItemsPresenters As IEnumerable(Of INavigableItemsPresenter))
MyBase.New(referencedSymbolsPresenters, navigableItemsPresenters)
End Sub
End Class
End Namespace
\ 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.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
......
......@@ -91,7 +91,6 @@ internal static class Guids
// Roslyn guids
public const string RoslynPackageIdString = "6cf2e545-6109-4730-8883-cf43d7aec3e1";
public const string RoslynCommandSetIdString = "9ed8fbd1-02d6-4223-a99c-a938f97e6dbe";
public const string RoslynLibraryIdString = "82fab260-0c56-4f02-b186-508358588fee";
public const string RoslynGroupIdString = "b61e1a20-8c13-49a9-a727-a0ec091647dd";
public const string RoslynOptionPageFeatureManagerComponentsIdString = "6F738951-348C-4816-9BA4-F60D92D3E98E";
......@@ -104,7 +103,6 @@ internal static class Guids
public static readonly Guid RoslynPackageId = new Guid(RoslynPackageIdString);
public static readonly Guid RoslynCommandSetId = new Guid(RoslynCommandSetIdString);
public static readonly Guid RoslynGroupId = new Guid(RoslynGroupIdString);
public static readonly Guid RoslynLibraryId = new Guid(RoslynLibraryIdString);
// TODO: Remove pending https://github.com/dotnet/roslyn/issues/8927 .
// Interactive guids
......
// 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.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults;
using Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.FindReferences
{
[Export(typeof(IDefinitionsAndReferencesPresenter))]
internal sealed class DefinitionsAndReferencesPresenter : ForegroundThreadAffinitizedObject, IDefinitionsAndReferencesPresenter
{
private readonly IServiceProvider _serviceProvider;
private readonly LibraryManager _manager;
[ImportingConstructor]
private DefinitionsAndReferencesPresenter(SVsServiceProvider serviceProvider) :
base(assertIsForeground: true)
{
_serviceProvider = serviceProvider;
// VS service should only be used in UI thread.
_manager = (LibraryManager)serviceProvider.GetService(typeof(LibraryManager));
}
public void DisplayResult(DefinitionsAndReferences definitionsAndReferences)
{
_manager.PresentDefinitionsAndReferences(definitionsAndReferences);
}
}
}
\ 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.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults;
using Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.GoToDefinition
{
[Export(typeof(INavigableItemsPresenter))]
internal class NavigableItemsPresenter : INavigableItemsPresenter
{
private readonly IServiceProvider _serviceProvider;
private readonly LibraryManager _manager;
[ImportingConstructor]
private NavigableItemsPresenter(
SVsServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_manager = (LibraryManager)serviceProvider.GetService(typeof(LibraryManager));
}
public void DisplayResult(string title, IEnumerable<INavigableItem> items)
{
if (title == null)
{
throw new ArgumentNullException(nameof(title));
}
_manager.PresentNavigableItems(title, items);
}
}
}
// 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.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
[Guid(Guids.RoslynLibraryIdString)]
internal partial class LibraryManager : AbstractLibraryManager
{
public LibraryManager(IServiceProvider serviceProvider)
: base(Guids.RoslynLibraryId, serviceProvider)
{
}
public override uint GetLibraryFlags()
{
return (uint)_LIB_FLAGS2.LF_SUPPORTSLISTREFERENCES;
}
protected override IVsSimpleObjectList2 GetList(uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch)
{
switch (listType)
{
case (uint)_LIB_LISTTYPE.LLT_HIERARCHY:
if (IsSymbolObjectList((_LIB_LISTFLAGS)flags, pobSrch))
{
return ((NavInfo)pobSrch[0].pIVsNavInfo).CreateObjectList();
}
break;
}
return null;
}
private bool IsSymbolObjectList(_LIB_LISTFLAGS flags, VSOBSEARCHCRITERIA2[] pobSrch)
{
return
(flags & _LIB_LISTFLAGS.LLF_USESEARCHFILTER) != 0 &&
pobSrch != null &&
pobSrch.Length == 1 &&
(pobSrch[0].grfOptions & (uint)_VSOBSEARCHOPTIONS2.VSOBSO_LISTREFERENCES) != 0 &&
pobSrch[0].pIVsNavInfo is NavInfo;
}
protected override uint GetSupportedCategoryFields(uint category)
{
switch (category)
{
case (uint)LIB_CATEGORY.LC_LISTTYPE:
return (uint)_LIB_LISTTYPE.LLT_HIERARCHY;
}
return 0;
}
protected override uint GetUpdateCounter()
{
return 0;
}
private void PresentObjectList(string title, ObjectList objectList)
{
if (string.IsNullOrWhiteSpace(title))
{
title = "None";
}
var navInfo = new NavInfo(objectList);
var findSymbol = (IVsFindSymbol)this.ServiceProvider.GetService(typeof(SVsObjectSearch));
var searchCriteria = new VSOBSEARCHCRITERIA2()
{
dwCustom = 0,
eSrchType = VSOBSEARCHTYPE.SO_ENTIREWORD,
grfOptions = (uint)_VSOBSEARCHOPTIONS2.VSOBSO_LISTREFERENCES | (uint)_VSOBSEARCHOPTIONS.VSOBSO_CASESENSITIVE,
pIVsNavInfo = navInfo,
szName = title,
};
var criteria = new[] { searchCriteria };
var hresult = findSymbol.DoSearch(Guids.RoslynLibraryId, criteria);
ErrorHandler.ThrowOnFailure(hresult);
}
private bool IsValidSourceLocation(Location location, Solution solution)
{
if (!location.IsInSource)
{
return false;
}
var document = solution.GetDocument(location.SourceTree);
return IsValidSourceLocation(document, location.SourceSpan);
}
private bool IsValidSourceLocation(Document document, TextSpan sourceSpan)
{
if (document == null)
{
return false;
}
var solution = document.Project.Solution;
var documentNavigationService = solution.Workspace.Services.GetService<IDocumentNavigationService>();
return documentNavigationService.CanNavigateToSpan(solution.Workspace, document.Id, sourceSpan);
}
}
}
// 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.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal partial class LibraryManager
{
public void PresentDefinitionsAndReferences(DefinitionsAndReferences definitionsAndReferences)
{
var firstDefinition = definitionsAndReferences.Definitions.FirstOrDefault();
var title = firstDefinition?.DisplayParts.JoinText();
PresentObjectList(title, new ObjectList(CreateFindReferencesItems(definitionsAndReferences), this));
}
// internal for test purposes
internal IList<AbstractTreeItem> CreateFindReferencesItems(
DefinitionsAndReferences definitionsAndReferences)
{
var definitionDocuments =
definitionsAndReferences.Definitions.SelectMany(d => d.SourceSpans)
.Select(loc => loc.Document);
var referenceDocuments =
definitionsAndReferences.References
.Select(r => r.SourceSpan.Document);
var allDocuments = definitionDocuments.Concat(referenceDocuments).WhereNotNull().ToSet();
var commonPathElements = CountCommonPathElements(allDocuments);
var query =
from d in definitionsAndReferences.Definitions
let referenceItems = CreateReferenceItems(d, definitionsAndReferences, commonPathElements)
select new DefinitionTreeItem(d, referenceItems);
return query.ToList<AbstractTreeItem>();
}
private ImmutableArray<SourceReferenceTreeItem> CreateReferenceItems(
DefinitionItem definitionItem,
DefinitionsAndReferences definitionsAndReferences,
int commonPathElements)
{
var result = ImmutableArray.CreateBuilder<SourceReferenceTreeItem>();
var definitionGlyph = definitionItem.Tags.GetGlyph();
// Skip the first definition. We'll present it in the definition item.
var definitionLocationsAndGlyphs =
from loc in definitionItem.SourceSpans.Skip(1)
select ValueTuple.Create(loc, definitionGlyph);
var referenceLocationsAndGlyphs =
from r in definitionsAndReferences.References
where r.Definition == definitionItem
select ValueTuple.Create(r.SourceSpan, Glyph.Reference);
var allLocationsAndGlyphs = definitionLocationsAndGlyphs.Concat(referenceLocationsAndGlyphs);
foreach (var locationAndGlyph in allLocationsAndGlyphs)
{
var documentLocation = locationAndGlyph.Item1;
var glyph = locationAndGlyph.Item2;
result.Add(new SourceReferenceTreeItem(
documentLocation.Document,
documentLocation.SourceSpan,
glyph.GetGlyphIndex(),
commonPathElements));
}
var linkedReferences = result.GroupBy(r => r.DisplayText.ToLowerInvariant()).Where(g => g.Count() > 1).SelectMany(g => g);
foreach (var linkedReference in linkedReferences)
{
linkedReference.AddProjectNameDisambiguator();
}
result.Sort();
return result.ToImmutable();
}
}
}
\ 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.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal partial class LibraryManager
{
private IList<AbstractTreeItem> CreateNavigableItemTreeItems(IEnumerable<INavigableItem> items)
{
var itemsList = items.Where(i => i.Document != null).ToList();
if (itemsList.Count == 0)
{
return new List<AbstractTreeItem>();
}
// Collect all the documents in the list of items we're presenting. Then determine
// what number of common path elements they have in common. We can avoid showing
// these common locations, thus presenting a much cleaner result view to the user.
var documents = new HashSet<Document>();
CollectDocuments(itemsList, documents);
var commonPathElements = CountCommonPathElements(documents);
return CreateNavigableItemTreeItems(itemsList, commonPathElements);
}
private int CountCommonPathElements(ISet<Document> documents)
{
if (documents.Count == 0)
{
return 0;
}
var commonPathElements = 0;
for (var index = 0; ; index++)
{
var pathPortion = GetPathPortion(documents.First(), index);
if (pathPortion == null)
{
return commonPathElements;
}
foreach (var document in documents)
{
if (GetPathPortion(document, index) != pathPortion)
{
return commonPathElements;
}
}
commonPathElements++;
}
}
private string GetPathPortion(Document document, int index)
{
if (index == 0)
{
return document.Project.Name;
}
index--;
if (index < document.Folders.Count)
{
return document.Folders[index];
}
return null;
}
private void CollectDocuments(IEnumerable<INavigableItem> items, HashSet<Document> documents)
{
foreach (var item in items)
{
documents.Add(item.Document);
CollectDocuments(item.ChildItems, documents);
}
}
private IList<AbstractTreeItem> CreateNavigableItemTreeItems(IEnumerable<INavigableItem> items, int commonPathElements)
{
var sourceListItems =
from item in items
where IsValidSourceLocation(item.Document, item.SourceSpan)
select CreateTreeItem(item, commonPathElements);
return sourceListItems.ToList();
}
private AbstractTreeItem CreateTreeItem(INavigableItem item, int commonPathElements)
{
var result = new SourceReferenceTreeItem(
item.Document, item.SourceSpan, item.Glyph.GetGlyphIndex(), commonPathElements,
displayText: item.DisplayTaggedParts.JoinText(),
includeFileLocation: item.DisplayFileLocation);
if (!item.ChildItems.IsEmpty)
{
var childItems = CreateNavigableItemTreeItems(item.ChildItems, commonPathElements);
result.Children.AddRange(childItems);
}
return result;
}
public void PresentNavigableItems(string title, IEnumerable<INavigableItem> items)
{
PresentObjectList(title, new ObjectList(CreateNavigableItemTreeItems(items), this));
}
}
}
// 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.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal class NavInfo : IVsNavInfo
{
private readonly ObjectList _objectList;
public NavInfo(ObjectList objectList)
{
_objectList = objectList;
}
public ObjectList CreateObjectList()
{
return _objectList;
}
int IVsNavInfo.EnumCanonicalNodes(out IVsEnumNavInfoNodes ppEnum)
{
ppEnum = null;
return VSConstants.E_NOTIMPL;
}
int IVsNavInfo.EnumPresentationNodes(uint dwFlags, out IVsEnumNavInfoNodes ppEnum)
{
ppEnum = null;
return VSConstants.E_NOTIMPL;
}
int IVsNavInfo.GetLibGuid(out Guid pGuid)
{
pGuid = Guid.Empty;
return VSConstants.E_NOTIMPL;
}
int IVsNavInfo.GetSymbolType(out uint pdwType)
{
pdwType = 0;
return VSConstants.E_NOTIMPL;
}
}
}
// 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;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Microsoft.VisualStudio.Shell.Interop;
using System.Linq;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal class ObjectList : AbstractObjectList<LibraryManager>
{
private readonly IList<AbstractTreeItem> _items;
public ObjectList(IList<AbstractTreeItem> items, LibraryManager manager)
: base(manager)
{
_items = items;
}
protected override bool CanGoToSource(uint index, VSOBJGOTOSRCTYPE srcType)
{
var item = _items[(int)index];
switch (srcType)
{
case VSOBJGOTOSRCTYPE.GS_ANY:
return true;
case VSOBJGOTOSRCTYPE.GS_DEFINITION:
return item.CanGoToDefinition();
case VSOBJGOTOSRCTYPE.GS_REFERENCE:
return item.CanGoToReference();
}
return false;
}
protected override bool TryGetCategoryField(uint index, int category, out uint categoryField)
{
if (category == (int)LIB_CATEGORY.LC_LISTTYPE)
{
categoryField = (uint)_LIB_LISTTYPE.LLT_HIERARCHY;
return true;
}
else
{
categoryField = 0;
return false;
}
}
protected override void GetDisplayData(uint index, ref VSTREEDISPLAYDATA data)
{
var item = _items[(int)index];
data.Image = item.GlyphIndex;
data.SelectedImage = item.GlyphIndex;
data.State |= (uint)_VSTREEDISPLAYSTATE.TDS_FORCESELECT;
if (item.UseGrayText)
{
data.State |= (uint)_VSTREEDISPLAYSTATE.TDS_GRAYTEXT;
}
data.ForceSelectStart = item.DisplaySelectionStart;
data.ForceSelectLength = item.DisplaySelectionLength;
}
protected override bool GetExpandable(uint index, uint listTypeExcluded)
{
var item = _items[(int)index];
return (item?.Children?.Any() == true);
}
protected override uint GetItemCount()
{
return (uint)_items.Count;
}
protected override IVsSimpleObjectList2 GetList(uint index, uint listType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch)
{
var item = _items[(int)index];
return (item?.Children?.Any() == true) ? new ObjectList(item.Children, LibraryManager) : null;
}
protected override string GetText(uint index, VSTREETEXTOPTIONS tto)
{
var item = _items[(int)index];
switch (tto)
{
case VSTREETEXTOPTIONS.TTO_DISPLAYTEXT:
return item.DisplayText;
case VSTREETEXTOPTIONS.TTO_SORTTEXT:
return index.ToString("D5");
}
return string.Empty;
}
protected override string GetTipText(uint index, VSTREETOOLTIPTYPE eTipType)
{
var item = _items[(int)index];
return item.DisplayText;
}
protected override int GoToSource(uint index, VSOBJGOTOSRCTYPE srcType)
{
if (index >= _items.Count)
{
return VSConstants.E_INVALIDARG;
}
var item = _items[(int)index];
return item.GoToSource();
}
protected override uint GetUpdateCounter()
{
return 0;
}
}
}
// 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;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal abstract class AbstractTreeItem
{
protected static int ReferenceGlyphIndex = Glyph.Reference.GetGlyphIndex();
public IList<AbstractTreeItem> Children { get; protected set; }
public ushort GlyphIndex { get; protected set; }
// TODO: Old C# code base has a helper, GetLineTextWithUnicodeDirectionMarkersIfNeeded, which we will need at some point.
public string DisplayText { get; protected set; }
public ushort DisplaySelectionStart { get; protected set; }
public ushort DisplaySelectionLength { get; protected set; }
public virtual bool UseGrayText
{
get
{
return this.Children == null || this.Children.Count == 0;
}
}
protected AbstractTreeItem(ushort glyphIndex)
{
this.Children = new List<AbstractTreeItem>();
this.GlyphIndex = glyphIndex;
}
public abstract int GoToSource();
public virtual bool CanGoToReference()
{
return false;
}
public virtual bool CanGoToDefinition()
{
return false;
}
}
}
\ 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.
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal class DefinitionTreeItem : AbstractTreeItem
{
private readonly DefinitionItem _definitionItem;
public DefinitionTreeItem(
DefinitionItem definitionItem,
ImmutableArray<SourceReferenceTreeItem> referenceItems)
: base(definitionItem.Tags.GetGlyph().GetGlyphIndex())
{
_definitionItem = definitionItem;
this.Children.AddRange(referenceItems);
this.DisplayText = CreateDisplayText();
}
private string CreateDisplayText()
{
var displayString = _definitionItem.DisplayParts.JoinText();
var referenceCount = this.Children.Count(i => i.GlyphIndex == ReferenceGlyphIndex);
var referenceCountDisplay = referenceCount == 1
? ServicesVSResources._1_reference
: string.Format(ServicesVSResources._0_references, referenceCount);
// If we don't have an origination or reference count, then just display the
// parts and nothing else. These items happen when we're getting third party
// results that tell us about their definition location, but not any additional
// reference. We don't want to say '0' references in that case as that can
// be misleading.
var hasOrigination = _definitionItem.OriginationParts.Length > 0;
return hasOrigination
? $"[{_definitionItem.OriginationParts.JoinText()}] {displayString} ({referenceCountDisplay})"
: referenceCount > 0
? $"{displayString} ({referenceCountDisplay})"
: displayString;
}
public override int GoToSource()
{
return _definitionItem.TryNavigateTo()
? VSConstants.S_OK
: VSConstants.E_FAIL;
}
public override bool CanGoToDefinition()
{
return _definitionItem.CanNavigateTo();
}
}
}
\ 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.
using System;
using System.IO;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
using Roslyn.Utilities;
using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
{
internal class SourceReferenceTreeItem : AbstractTreeItem, IComparable<SourceReferenceTreeItem>
{
protected readonly Workspace _workspace;
protected readonly DocumentId _documentId;
protected readonly string _projectName;
protected readonly string _filePath;
protected readonly TextSpan _sourceSpan;
protected readonly string _textLineString;
protected readonly int _lineNumber;
protected readonly int _offset;
protected readonly int _mappedLineNumber;
protected readonly int _mappedOffset;
private static readonly ObjectPool<StringBuilder> s_filePathBuilderPool = new ObjectPool<StringBuilder>(() => new StringBuilder());
private SourceReferenceTreeItem(
Document document, TextSpan sourceSpan, ushort glyphIndex, int commonPathElements)
: base(glyphIndex)
{
// We store the document ID, line and offset for navigation so that we
// still provide reasonable navigation if the user makes changes elsewhere
// in the document other than inserting or removing lines.
_workspace = document.Project.Solution.Workspace;
_documentId = document.Id;
_projectName = document.Project.Name;
_filePath = GetFilePath(document, commonPathElements);
_sourceSpan = sourceSpan;
var text = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
var textLine = text.Lines.GetLineFromPosition(_sourceSpan.Start);
_textLineString = textLine.ToString();
_lineNumber = textLine.LineNumber;
_offset = sourceSpan.Start - textLine.Start;
var spanInSecondaryBuffer = text.GetVsTextSpanForLineOffset(_lineNumber, _offset);
var succeeded = spanInSecondaryBuffer.TryMapSpanFromSecondaryBufferToPrimaryBuffer(_workspace, _documentId, out var spanInPrimaryBuffer);
_mappedLineNumber = succeeded ? spanInPrimaryBuffer.iStartLine : _lineNumber;
_mappedOffset = succeeded ? spanInPrimaryBuffer.iStartIndex : _offset;
}
public SourceReferenceTreeItem(
Document document, TextSpan sourceSpan, ushort glyphIndex,
int commonPathElements, string displayText = null, bool includeFileLocation = false)
: this(document, sourceSpan, glyphIndex, commonPathElements)
{
if (displayText != null && !includeFileLocation)
{
this.DisplayText = displayText;
}
else
{
SetDisplayProperties(
_filePath,
_mappedLineNumber,
_mappedOffset,
_offset,
_textLineString,
sourceSpan.Length,
projectNameDisambiguator: string.Empty,
explicitDisplayText: displayText);
}
}
public override int GoToSource()
{
var navigationService = _workspace.Services.GetService<IDocumentNavigationService>();
navigationService.TryNavigateToLineAndOffset(_workspace, _documentId, _lineNumber, _offset);
return VSConstants.S_OK;
}
private static string GetFilePath(Document document, int commonPathElements)
{
var builder = s_filePathBuilderPool.Allocate();
try
{
if (commonPathElements <= 0)
{
builder.Append(document.Project.Name);
builder.Append('\\');
}
commonPathElements--;
foreach (var folder in document.Folders)
{
if (commonPathElements <= 0)
{
builder.Append(folder);
builder.Append('\\');
}
commonPathElements--;
}
builder.Append(Path.GetFileName(document.FilePath));
return builder.ToString();
}
finally
{
s_filePathBuilderPool.ClearAndFree(builder);
}
}
public override bool CanGoToReference() => true;
public override bool UseGrayText => false;
public void AddProjectNameDisambiguator()
{
SetDisplayProperties(
_filePath,
_mappedLineNumber,
_mappedOffset,
_offset,
_textLineString,
_sourceSpan.Length,
projectNameDisambiguator: _projectName);
}
private void SetDisplayProperties(string filePath, int mappedLineNumber, int mappedOffset, int offset, string lineText, int spanLength, string projectNameDisambiguator, string explicitDisplayText = null)
{
var sourceSnippet = explicitDisplayText ?? lineText.Replace('\t', ' ').TrimStart(' ');
var displayText = GetDisplayText(filePath, projectNameDisambiguator, mappedLineNumber + 1, mappedOffset + 1, sourceSnippet);
var selectionStart = offset + displayText.Length - lineText.Length;
displayText = displayText.TrimEnd();
if (displayText.Length > ushort.MaxValue)
{
displayText = displayText.Substring(0, ushort.MaxValue);
}
this.DisplayText = displayText;
if (explicitDisplayText == null)
{
this.DisplaySelectionStart = checked((ushort)Math.Min(ushort.MaxValue, selectionStart));
this.DisplaySelectionLength = checked((ushort)Math.Min(spanLength, DisplayText.Length - DisplaySelectionStart));
}
}
private static string GetDisplayText(string fileName, string projectNameDisambiguator, int lineNumber, int offset, string sourceText)
{
var fileLocationDescription = GetFileLocationsText(fileName, projectNameDisambiguator);
return string.IsNullOrWhiteSpace(fileLocationDescription)
? $"({lineNumber}, {offset}) : {sourceText}"
: $"{fileLocationDescription} - ({lineNumber}, {offset}) : {sourceText}";
}
private static string GetFileLocationsText(string fileName, string projectNameDisambiguator)
{
if (!string.IsNullOrWhiteSpace(fileName) && !string.IsNullOrWhiteSpace(projectNameDisambiguator))
{
return $"{fileName} [{projectNameDisambiguator}]";
}
if (!string.IsNullOrWhiteSpace(fileName))
{
return fileName;
}
if (!string.IsNullOrWhiteSpace(projectNameDisambiguator))
{
return $"[{projectNameDisambiguator}]";
}
return string.Empty;
}
int IComparable<SourceReferenceTreeItem>.CompareTo(SourceReferenceTreeItem other)
{
if (other == null)
{
return 1;
}
if (this.GlyphIndex != other.GlyphIndex)
{
// references come after anything else.
if (this.GlyphIndex == ReferenceGlyphIndex)
{
return 1;
}
else if (other.GlyphIndex == ReferenceGlyphIndex)
{
return -1;
}
}
int compare = LogicalStringComparer.Instance.Compare(_filePath, _filePath);
compare = compare != 0 ? compare : _lineNumber.CompareTo(other._lineNumber);
compare = compare != 0 ? compare : _offset.CompareTo(other._offset);
compare = compare != 0 ? compare : _projectName.CompareTo(other._projectName);
return compare;
}
}
}
\ No newline at end of file
......@@ -2,35 +2,27 @@
using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Versions;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interactive;
using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.RuleSets;
using Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource;
using Microsoft.VisualStudio.LanguageServices.Packaging;
using Microsoft.VisualStudio.LanguageServices.SymbolSearch;
using Microsoft.VisualStudio.LanguageServices.Telemetry;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using static Microsoft.CodeAnalysis.Utilities.ForegroundThreadDataKind;
using Task = System.Threading.Tasks.Task;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.LanguageServices.Telemetry;
namespace Microsoft.VisualStudio.LanguageServices.Setup
{
......@@ -39,8 +31,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Setup
[ProvideMenuResource("Menus.ctmenu", version: 16)]
internal class RoslynPackage : AbstractPackage
{
private LibraryManager _libraryManager;
private uint _libraryManagerCookie;
private VisualStudioWorkspace _workspace;
private WorkspaceFailureOutputPane _outputPane;
private IComponentModel _componentModel;
......@@ -62,8 +52,6 @@ protected override void Initialize()
var method = compilerFailFast.GetMethod(nameof(FailFast.OnFatalException), BindingFlags.Static | BindingFlags.NonPublic);
property.SetValue(null, Delegate.CreateDelegate(property.PropertyType, method));
RegisterFindResultsLibraryManager();
var componentModel = (IComponentModel)this.GetService(typeof(SComponentModel));
_workspace = componentModel.GetService<VisualStudioWorkspace>();
......@@ -105,8 +93,6 @@ protected override void LoadComponentsInUIContext()
this.ComponentModel.GetService<VisualStudioDiagnosticListTableCommandHandler>().Initialize(this);
this.ComponentModel.GetService<HACK_ThemeColorFixer>();
this.ComponentModel.GetExtensions<IDefinitionsAndReferencesPresenter>();
this.ComponentModel.GetExtensions<INavigableItemsPresenter>();
this.ComponentModel.GetService<VisualStudioMetadataAsSourceFileSupportService>();
this.ComponentModel.GetService<VirtualMemoryNotificationListener>();
......@@ -157,8 +143,6 @@ internal IComponentModel ComponentModel
protected override void Dispose(bool disposing)
{
UnregisterFindResultsLibraryManager();
DisposeVisualStudioServices();
UnregisterAnalyzerTracker();
......@@ -181,38 +165,6 @@ private void ReportSessionWideTelemetry()
LinkedFileDiffMergingLogger.ReportTelemetry();
}
private void RegisterFindResultsLibraryManager()
{
var objectManager = this.GetService(typeof(SVsObjectManager)) as IVsObjectManager2;
if (objectManager != null)
{
_libraryManager = new LibraryManager(this);
if (ErrorHandler.Failed(objectManager.RegisterSimpleLibrary(_libraryManager, out _libraryManagerCookie)))
{
_libraryManagerCookie = 0;
}
((IServiceContainer)this).AddService(typeof(LibraryManager), _libraryManager, promote: true);
}
}
private void UnregisterFindResultsLibraryManager()
{
if (_libraryManagerCookie != 0)
{
var objectManager = this.GetService(typeof(SVsObjectManager)) as IVsObjectManager2;
if (objectManager != null)
{
objectManager.UnregisterLibrary(_libraryManagerCookie);
_libraryManagerCookie = 0;
}
((IServiceContainer)this).RemoveService(typeof(LibraryManager), promote: true);
_libraryManager = null;
}
}
private void DisposeVisualStudioServices()
{
if (_workspace != null)
......
......@@ -73,7 +73,6 @@
<Compile Include="Implementation\LanguageService\AbstractPackage.cs" />
<Compile Include="Implementation\Library\AbstractLibraryService.cs" />
<Compile Include="Implementation\Library\ClassView\AbstractSyncClassViewCommandHandler.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\DefinitionTreeItem.cs" />
<Compile Include="Implementation\Library\ILibraryService.cs" />
<Compile Include="Implementation\Library\ObjectBrowser\ObjectBrowserTaskExtensions.cs" />
<Compile Include="Implementation\Library\VsNavInfo\NavInfoNodeEnum.cs" />
......@@ -379,14 +378,12 @@
<Compile Include="Implementation\ExtractInterface\VisualStudioExtractInterfaceOptionsService.cs" />
<Compile Include="Implementation\F1Help\AbstractHelpContextService.cs" />
<Compile Include="Implementation\F1Help\IHelpContextService.cs" />
<Compile Include="Implementation\FindReferences\DefinitionsAndReferencesPresenter.cs" />
<Compile Include="Implementation\GCManager.cs" />
<Compile Include="Implementation\GenerateType\GenerateTypeDialog.xaml.cs">
<DependentUpon>GenerateTypeDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Implementation\GenerateType\GenerateTypeDialogViewModel.cs" />
<Compile Include="Implementation\GenerateType\VisualStudioGenerateTypeOptionsServiceFactory.cs" />
<Compile Include="Implementation\GoToDefinition\NavigableItemsPresenter.cs" />
<Compile Include="Implementation\Interop\Feedback.cs" />
<Compile Include="Implementation\LanguageService\HACK_AbstractCreateServicesOnUiThread.cs" />
<Compile Include="Implementation\Library\ObjectBrowser\AbstractListItemFactory.cs" />
......@@ -437,13 +434,6 @@
<Compile Include="Implementation\Library\AbstractLibraryManager_IVsLibraryMgr.cs" />
<Compile Include="Implementation\Library\AbstractLibraryManager_IVsSimpleLibrary2.cs" />
<Compile Include="Implementation\Library\AbstractObjectList.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\AbstractTreeItem.cs" />
<Compile Include="Implementation\Library\FindResults\LibraryManager.cs" />
<Compile Include="Implementation\Library\FindResults\LibraryManager_FindReferences.cs" />
<Compile Include="Implementation\Library\FindResults\LibraryManager_GoToDefinition.cs" />
<Compile Include="Implementation\Library\FindResults\NavInfo.cs" />
<Compile Include="Implementation\Library\FindResults\ObjectList.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\SourceReferenceTreeItem.cs" />
<Compile Include="Implementation\Library\ObjectBrowser\AbstractDescriptionBuilder.cs" />
<Compile Include="Implementation\Library\ObjectBrowser\AbstractDescriptionBuilder.LinkFlags.cs" />
<Compile Include="Implementation\Library\ObjectBrowser\AbstractObjectBrowserLibraryManager.cs" />
......
......@@ -6,22 +6,20 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Undo;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.GeneratedCodeRecognition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.LanguageServices.Implementation;
using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices
......@@ -31,18 +29,15 @@ namespace Microsoft.VisualStudio.LanguageServices
internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IEnumerable<Lazy<IDefinitionsAndReferencesPresenter>> _referencedSymbolsPresenters;
[ImportingConstructor]
private RoslynVisualStudioWorkspace(
ExportProvider exportProvider,
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
[ImportMany] IEnumerable<Lazy<IDefinitionsAndReferencesPresenter>> referencedSymbolsPresenters,
[ImportMany] IEnumerable<IDocumentOptionsProviderFactory> documentOptionsProviderFactories)
: base(exportProvider.AsExportProvider())
{
_streamingPresenters = streamingPresenters;
_referencedSymbolsPresenters = referencedSymbolsPresenters;
foreach (var providerFactory in documentOptionsProviderFactories)
{
......@@ -202,44 +197,27 @@ private static bool TryResolveSymbol(ISymbol symbol, Project project, Cancellati
public override bool TryFindAllReferences(ISymbol symbol, Project project, CancellationToken cancellationToken)
{
if (!_referencedSymbolsPresenters.Any())
if (!_streamingPresenters.Any())
{
return false;
}
if (!TryResolveSymbol(symbol, project, cancellationToken, out var searchSymbol, out var searchProject))
if (!TryResolveSymbol(symbol, project, cancellationToken,
out var searchSymbol, out var searchProject))
{
return false;
}
var searchSolution = searchProject.Solution;
var context = _streamingPresenters.First().Value.StartSearch(
EditorFeaturesResources.Find_References, supportsReferences: true);
var task = AbstractFindUsagesService.FindReferencesAsync(
context, searchSymbol, searchProject, CancellationToken.None);
var result = SymbolFinder
.FindReferencesAsync(searchSymbol, searchSolution, cancellationToken)
.WaitAndGetResult(cancellationToken).ToList();
if (result != null)
{
DisplayReferencedSymbols(searchSolution, result);
return true;
}
return false;
return true;
}
public override void DisplayReferencedSymbols(
Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
public override void DisplayReferencedSymbols(Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
{
var service = this.Services.GetService<IDefinitionsAndReferencesFactory>();
var definitionsAndReferences = service.CreateDefinitionsAndReferences(
solution, referencedSymbols,
includeHiddenLocations: false, cancellationToken: CancellationToken.None);
foreach (var presenter in _referencedSymbolsPresenters)
{
presenter.Value.DisplayResult(definitionsAndReferences);
return;
}
}
internal override object GetBrowseObject(SymbolListItem symbolListItem)
......
' 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.Utilities
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.FindUsages
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
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
<WorkItem(1138943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1138943")>
Public Async Function ConstructorReferencesShouldNotAppearUnderClassNodeInCSharp() As System.Threading.Tasks.Task
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
{
TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C() ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.cs - (11, 21) : var a = new C();")),
TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C(int) ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.cs - (12, 21) : var b = new C(5);")),
TestFindResult.CreateDefinition($"[CSharpAssembly1] class C ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.cs - (13, 17) : var c = C.z;"))
}
Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
<WorkItem(1138943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1138943")>
Public Async Function ConstructorReferencesShouldNotAppearUnderClassNodeInVisualBasic() As System.Threading.Tasks.Task
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
{
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Class C ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.vb - (14, 17) : Dim d = C.z")),
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New() ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.vb - (12, 21) : Dim a = New C()")),
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New(Integer) ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.vb - (13, 21) : Dim b = New C(5)"))
}
Await VerifyAsync(markup, LanguageNames.VisualBasic, expectedResults)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestSourceNamespace() As System.Threading.Tasks.Task
Dim markup = <Text><![CDATA[
namespace NS$$
{
}
namespace NS
{
}
]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateUnnavigable($"namespace NS ({String.Format(ServicesVSResources._0_references, 2)})",
TestFindResult.CreateReference("Test1.cs - (2, 11) : namespace NS"),
TestFindResult.CreateReference("Test1.cs - (6, 11) : namespace NS"))
}
Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestMetadataNamespace() As System.Threading.Tasks.Task
Dim markup = <Text><![CDATA[
using System$$;
using System.Threading;
]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateUnnavigable($"namespace System ({String.Format(ServicesVSResources._0_references, 2)})",
TestFindResult.CreateReference("Test1.cs - (2, 7) : using System;"),
TestFindResult.CreateReference("Test1.cs - (3, 7) : using System.Threading;"))
}
Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
End Function
Private Shared ReadOnly s_exportProvider As ExportProvider = MinimalTestExportProvider.CreateExportProvider(
TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic.WithParts(
GetType(MockDocumentNavigationServiceProvider),
GetType(MockSymbolNavigationServiceProvider),
GetType(DefaultDefinitionsAndReferencesFactory)))
Private Async Function VerifyAsync(markup As XElement, languageName As String, expectedResults As IList(Of AbstractTreeItem)) As System.Threading.Tasks.Task
Dim workspaceXml =
<Workspace>
<Project Language=<%= languageName %> CommonReferences="true">
<Document><%= markup %></Document>
</Project>
</Workspace>
Using workspace = TestWorkspace.Create(workspaceXml, exportProvider:=s_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 = Await SymbolFinder.FindSymbolAtPositionAsync(workspaceDoc, doc.CursorPosition.Value, CancellationToken.None)
Assert.NotNull(symbol)
Dim result = Await SymbolFinder.FindReferencesAsync(symbol, workspace.CurrentSolution, CancellationToken.None)
WpfTestCase.RequireWpfFact($"The {NameOf(Implementation.Library.FindResults.LibraryManager)} assumes it's on the VS UI thread and thus uses WaitAndGetResult")
Dim libraryManager = New LibraryManager(New MockServiceProvider(New MockComponentModel(workspace.ExportProvider)))
Dim factory = workspace.Services.GetService(Of IDefinitionsAndReferencesFactory)
Dim definitionsAndReferences = factory.CreateDefinitionsAndReferences(
workspace.CurrentSolution, result,
includeHiddenLocations:=False, cancellationToken:=CancellationToken.None)
Dim findReferencesTree = libraryManager.CreateFindReferencesItems(definitionsAndReferences)
' 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 Function
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)
Assert.Equal(expectedItem.CanGoToDefinition, actualItem.CanGoToDefinition)
Assert.Equal(expectedItem.CanGoToReference, actualItem.CanGoToReference)
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(items As IList(Of AbstractTreeItem)) As String
Dim indentString = String.Empty
Dim stringBuilder = New StringBuilder()
GetResultTextWorker(items, stringBuilder, indentString)
Return stringBuilder.ToString()
End Function
Private Sub GetResultTextWorker(items As IList(Of AbstractTreeItem), stringBuilder As StringBuilder, indentString As String)
For Each item In items
stringBuilder.Append(indentString)
stringBuilder.Append(item.DisplayText)
stringBuilder.Append(" [Kind: " &
If(item.CanGoToDefinition, "Def", String.Empty) &
If(item.CanGoToReference, "Ref", String.Empty) &
If(item.CanGoToDefinition OrElse item.CanGoToDefinition, "None", String.Empty) &
"]")
If item.Children IsNot Nothing AndAlso item.Children.Any() Then
GetResultTextWorker(item.Children, stringBuilder, indentString + " ")
End If
Next
End Sub
Private Class TestFindResult
Inherits AbstractTreeItem
Public ReadOnly expectedCanGoToDefinition As Boolean?
Public ReadOnly expectedCanGoToReference As Boolean?
Public Overrides Function CanGoToDefinition() As Boolean
Return If(expectedCanGoToDefinition, True)
End Function
Public Overrides Function CanGoToReference() As Boolean
Return If(expectedCanGoToReference, True)
End Function
Public Shared Function CreateDefinition(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=True, expectedCanGoToReference:=False)
End Function
Public Shared Function CreateReference(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=False, expectedCanGoToReference:=True)
End Function
Public Shared Function CreateUnnavigable(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=False, expectedCanGoToReference:=False)
End Function
Private Sub New(displayText As String,
children As TestFindResult(),
expectedCanGoToDefinition As Boolean,
expectedCanGoToReference As Boolean)
MyBase.New(0)
Me.DisplayText = displayText
Me.expectedCanGoToDefinition = expectedCanGoToDefinition
Me.expectedCanGoToReference = expectedCanGoToReference
Me.Children = If(children IsNot Nothing AndAlso children.Length > 0, children, Nothing)
End Sub
Public Overrides Function GoToSource() As Integer
Throw New NotImplementedException()
End Function
End Class
End Class
End Namespace
\ No newline at end of file
......@@ -330,7 +330,6 @@
<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="Help\HelpTests.vb" />
......@@ -411,4 +410,4 @@
<None Include="project.json" />
</ItemGroup>
<Import Project="..\..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册