Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Value Tracking: Remove inproc symbol usage #59473

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ private ValueTrackedTreeItemViewModel(
internal static async ValueTask<TreeItemViewModel> CreateAsync(
Solution solution,
ValueTrackedItem item,
ImmutableArray<TreeItemViewModel> children,
ValueTrackingTreeViewModel treeViewModel,
IGlyphService glyphService,
IValueTrackingService valueTrackingService,
Expand All @@ -108,7 +109,7 @@ internal static async ValueTask<TreeItemViewModel> CreateAsync(
globalOptions,
threadingContext,
fileName,
children: ImmutableArray<TreeItemViewModel>.Empty);
children);
}

private void CalculateChildren()
Expand Down Expand Up @@ -173,7 +174,7 @@ private async Task<ImmutableArray<TreeItemViewModel>> CalculateChildrenAsync(Can
cancellationToken).ConfigureAwait(false);

return await valueTrackedItems.SelectAsArrayAsync((item, cancellationToken) =>
CreateAsync(_solution, item, TreeViewModel, _glyphService, _valueTrackingService, _globalOptions, ThreadingContext, cancellationToken), cancellationToken).ConfigureAwait(false);
CreateAsync(_solution, item, children: ImmutableArray<TreeItemViewModel>.Empty, TreeViewModel, _glyphService, _valueTrackingService, _globalOptions, ThreadingContext, cancellationToken), cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
Expand Down Expand Up @@ -90,101 +90,65 @@ public bool ExecuteCommand(ValueTrackingEditorCommandArgs args, CommandExecution

_threadingContext.JoinableTaskFactory.RunAsync(async () =>
{
var selectedSymbol = await GetSelectedSymbolAsync(textSpan, document, cancellationToken).ConfigureAwait(false);
if (selectedSymbol is null)
var service = document.Project.Solution.Workspace.Services.GetRequiredService<IValueTrackingService>();
var items = await service.TrackValueSourceAsync(textSpan, document, cancellationToken).ConfigureAwait(false);
if (items.Length == 0)
{
// TODO: Show error dialog
return;
}

var syntaxTree = document.GetRequiredSyntaxTreeSynchronously(cancellationToken);
var location = Location.Create(syntaxTree, textSpan);

await ShowToolWindowAsync(args.TextView, selectedSymbol, location, document.Project.Solution, cancellationToken).ConfigureAwait(false);
await ShowToolWindowAsync(args.TextView, document, items, cancellationToken).ConfigureAwait(false);
});

return true;
}

private static async Task<ISymbol?> GetSelectedSymbolAsync(TextSpan textSpan, Document document, CancellationToken cancellationToken)
{
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var selectedNode = root.FindNode(textSpan);
if (selectedNode is null)
{
return null;
}

var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh thank goodness. so now nothign symbolic happens on the client side right? it's all on the server?

var selectedSymbol =
semanticModel.GetSymbolInfo(selectedNode, cancellationToken).Symbol
?? semanticModel.GetDeclaredSymbol(selectedNode, cancellationToken);

if (selectedSymbol is null)
{
return null;
}

return selectedSymbol switch
{
ILocalSymbol
or IPropertySymbol { SetMethod: not null }
or IFieldSymbol { IsReadOnly: false }
or IEventSymbol
or IParameterSymbol
=> selectedSymbol,

_ => null
};
}

private async Task ShowToolWindowAsync(ITextView textView, ISymbol selectedSymbol, Location location, Solution solution, CancellationToken cancellationToken)
private async Task ShowToolWindowAsync(ITextView textView, Document document, ImmutableArray<ValueTrackedItem> items, CancellationToken cancellationToken)
{
var item = await ValueTrackedItem.TryCreateAsync(solution, location, selectedSymbol, cancellationToken: cancellationToken).ConfigureAwait(false);
if (item is null)
{
return;
}

var toolWindow = await GetOrCreateToolWindowAsync(textView, cancellationToken).ConfigureAwait(false);
if (toolWindow?.ViewModel is null)
{
return;
}

var valueTrackingService = solution.Workspace.Services.GetRequiredService<IValueTrackingService>();
var classificationFormatMap = _classificationFormatMapService.GetClassificationFormatMap(textView);
var solution = document.Project.Solution;
var valueTrackingService = solution.Workspace.Services.GetRequiredService<IValueTrackingService>();
var rootItemMap = items.GroupBy(i => i.Parent, resultSelector: (key, items) => (parent: key, children: items));

var childItems = await valueTrackingService.TrackValueSourceAsync(solution, item, cancellationToken).ConfigureAwait(false);

var childViewModels = await childItems.SelectAsArrayAsync((item, cancellationToken) =>
ValueTrackedTreeItemViewModel.CreateAsync(solution, item, toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, cancellationToken), cancellationToken).ConfigureAwait(false);

RoslynDebug.AssertNotNull(location.SourceTree);
var document = solution.GetRequiredDocument(location.SourceTree);
var options = _globalOptions.GetClassificationOptions(document.Project.Language);
using var _ = CodeAnalysis.PooledObjects.ArrayBuilder<TreeItemViewModel>.GetInstance(out var rootItems);

var sourceText = await location.SourceTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
var documentSpan = await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(document, location.SourceSpan, options, cancellationToken).ConfigureAwait(false);
var classificationResult = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(documentSpan, options, cancellationToken).ConfigureAwait(false);
foreach (var (parent, children) in rootItemMap)
{
if (parent is null)
{
foreach (var child in children)
{
var root = await ValueTrackedTreeItemViewModel.CreateAsync(solution, child, children: ImmutableArray<TreeItemViewModel>.Empty, toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, cancellationToken).ConfigureAwait(false);
rootItems.Add(root);
}
}
else
{
using var _1 = CodeAnalysis.PooledObjects.ArrayBuilder<TreeItemViewModel>.GetInstance(out var childItems);
foreach (var child in children)
{
var childViewModel = await ValueTrackedTreeItemViewModel.CreateAsync(solution, child, children: ImmutableArray<TreeItemViewModel>.Empty, toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, cancellationToken).ConfigureAwait(false);
childItems.Add(childViewModel);
}

var root = new TreeItemViewModel(
location.SourceSpan,
sourceText,
document.Id,
document.FilePath ?? document.Name,
selectedSymbol.GetGlyph(),
classificationResult.ClassifiedSpans,
toolWindow.ViewModel,
_glyphService,
_threadingContext,
solution.Workspace,
childViewModels);
var root = await ValueTrackedTreeItemViewModel.CreateAsync(solution, parent, childItems.ToImmutable(), toolWindow.ViewModel, _glyphService, valueTrackingService, _globalOptions, _threadingContext, cancellationToken).ConfigureAwait(false);
rootItems.Add(root);
}
}

await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

toolWindow.ViewModel.Roots.Clear();
toolWindow.ViewModel.Roots.Add(root);
foreach (var root in rootItems)
{
toolWindow.ViewModel.Roots.Add(root);
}

await ShowToolWindowAsync(cancellationToken).ConfigureAwait(true);
}
Expand Down