-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51898 from ryzngard/feature/value_tracking/service
Add value tracking service
- Loading branch information
Showing
7 changed files
with
566 additions
and
0 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
src/EditorFeatures/Core/ValueTracking/IValueTrackingService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Collections.Immutable; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Host; | ||
|
||
namespace Microsoft.CodeAnalysis.ValueTracking | ||
{ | ||
internal interface IValueTrackingService : IWorkspaceService | ||
{ | ||
Task<ImmutableArray<ValueTrackedItem>> TrackValueSourceAsync(Solution solution, ISymbol symbol, CancellationToken cancellationToken); | ||
Task TrackValueSourceAsync(Solution solution, ISymbol symbol, ValueTrackingProgressCollector progressCollector, CancellationToken cancellationToken); | ||
|
||
Task<ImmutableArray<ValueTrackedItem>> TrackValueSourceAsync(Solution solution, ValueTrackedItem previousTrackedItem, CancellationToken cancellationToken); | ||
Task TrackValueSourceAsync(Solution solution, ValueTrackedItem previousTrackedItem, ValueTrackingProgressCollector progressCollector, CancellationToken cancellationToken); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
namespace Microsoft.CodeAnalysis.ValueTracking | ||
{ | ||
internal class ValueTrackedItem | ||
{ | ||
public Location Location { get; } | ||
public ISymbol Symbol { get; } | ||
|
||
public ValueTrackedItem( | ||
Location location, | ||
ISymbol symbol) | ||
{ | ||
Location = location; | ||
Symbol = symbol; | ||
} | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/EditorFeatures/Core/ValueTracking/ValueTrackingProgressCollector.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
|
||
namespace Microsoft.CodeAnalysis.ValueTracking | ||
{ | ||
internal class ValueTrackingProgressCollector : IProgress<ValueTrackedItem> | ||
{ | ||
private readonly object _lock = new(); | ||
private readonly Stack<ValueTrackedItem> _items = new(); | ||
|
||
public event EventHandler<ValueTrackedItem>? OnNewItem; | ||
|
||
public void Report(ValueTrackedItem item) | ||
{ | ||
lock (_lock) | ||
{ | ||
_items.Push(item); | ||
} | ||
|
||
OnNewItem?.Invoke(null, item); | ||
} | ||
|
||
public ImmutableArray<ValueTrackedItem> GetItems() | ||
{ | ||
lock (_lock) | ||
{ | ||
return _items.ToImmutableArray(); | ||
} | ||
} | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
src/EditorFeatures/Core/ValueTracking/ValueTrackingService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Immutable; | ||
using System.Composition; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.FindSymbols; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
using Microsoft.CodeAnalysis.Shared.Utilities; | ||
|
||
namespace Microsoft.CodeAnalysis.ValueTracking | ||
{ | ||
[ExportWorkspaceService(typeof(IValueTrackingService)), Shared] | ||
internal class ValueTrackingService : IValueTrackingService | ||
{ | ||
[ImportingConstructor] | ||
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
public ValueTrackingService() | ||
{ | ||
} | ||
|
||
public async Task<ImmutableArray<ValueTrackedItem>> TrackValueSourceAsync( | ||
Solution solution, | ||
ISymbol symbol, | ||
CancellationToken cancellationToken) | ||
{ | ||
var progressTracker = new ValueTrackingProgressCollector(); | ||
await TrackValueSourceAsync(solution, symbol, progressTracker, cancellationToken).ConfigureAwait(false); | ||
return progressTracker.GetItems(); | ||
} | ||
|
||
public async Task TrackValueSourceAsync( | ||
Solution solution, | ||
ISymbol symbol, | ||
ValueTrackingProgressCollector progressCollector, | ||
CancellationToken cancellationToken) | ||
{ | ||
if (symbol | ||
is IPropertySymbol | ||
or IFieldSymbol | ||
or ILocalSymbol | ||
or IParameterSymbol) | ||
{ | ||
// Add all initializations of the symbol. Those are not caught in | ||
// the reference finder but should still show up in the tree | ||
foreach (var syntaxRef in symbol.DeclaringSyntaxReferences) | ||
{ | ||
var location = Location.Create(syntaxRef.SyntaxTree, syntaxRef.Span); | ||
progressCollector.Report(new ValueTrackedItem(location, symbol)); | ||
} | ||
|
||
var findReferenceProgressCollector = new FindReferencesProgress(progressCollector); | ||
await SymbolFinder.FindReferencesAsync( | ||
symbol, solution, findReferenceProgressCollector, | ||
documents: null, FindReferencesSearchOptions.Default, cancellationToken).ConfigureAwait(false); | ||
} | ||
} | ||
|
||
public async Task<ImmutableArray<ValueTrackedItem>> TrackValueSourceAsync( | ||
Solution solution, | ||
ValueTrackedItem previousTrackedItem, | ||
CancellationToken cancellationToken) | ||
{ | ||
var progressTracker = new ValueTrackingProgressCollector(); | ||
await TrackValueSourceAsync(solution, previousTrackedItem, progressTracker, cancellationToken).ConfigureAwait(false); | ||
return progressTracker.GetItems(); | ||
} | ||
|
||
public Task TrackValueSourceAsync( | ||
Solution solution, | ||
ValueTrackedItem previousTrackedItem, | ||
ValueTrackingProgressCollector progressCollector, | ||
CancellationToken cancellationToken) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
private class FindReferencesProgress : IStreamingFindReferencesProgress, IStreamingProgressTracker | ||
{ | ||
private readonly ValueTrackingProgressCollector _valueTrackingProgressCollector; | ||
public FindReferencesProgress(ValueTrackingProgressCollector valueTrackingProgressCollector) | ||
{ | ||
_valueTrackingProgressCollector = valueTrackingProgressCollector; | ||
} | ||
|
||
public IStreamingProgressTracker ProgressTracker => this; | ||
|
||
public ValueTask AddItemsAsync(int count) => new(); | ||
|
||
public ValueTask ItemCompletedAsync() => new(); | ||
|
||
public ValueTask OnCompletedAsync() => new(); | ||
|
||
public ValueTask OnDefinitionFoundAsync(ISymbol symbol) => new(); | ||
|
||
public ValueTask OnFindInDocumentCompletedAsync(Document document) => new(); | ||
|
||
public ValueTask OnFindInDocumentStartedAsync(Document document) => new(); | ||
|
||
public ValueTask OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location) | ||
{ | ||
if (location.IsWrittenTo) | ||
{ | ||
_valueTrackingProgressCollector.Report(new ValueTrackedItem(location.Location, symbol)); | ||
} | ||
|
||
return new(); | ||
} | ||
|
||
public ValueTask OnStartedAsync() => new(); | ||
} | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/EditorFeatures/Test/ValueTracking/AbstractBaseValueTrackingTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Collections.Immutable; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.ValueTracking; | ||
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; | ||
using Microsoft.CodeAnalysis.Shared.Extensions; | ||
using System.Threading; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Xunit; | ||
|
||
namespace Microsoft.CodeAnalysis.Editor.UnitTests.ValueTracking | ||
{ | ||
public abstract class AbstractBaseValueTrackingTests | ||
{ | ||
internal static async Task<ImmutableArray<ValueTrackedItem>> GetTrackedItemsAsync(TestWorkspace testWorkspace, CancellationToken cancellationToken = default) | ||
{ | ||
var cursorDocument = testWorkspace.DocumentWithCursor; | ||
var document = testWorkspace.CurrentSolution.GetRequiredDocument(cursorDocument.Id); | ||
var textSpan = new TextSpan(cursorDocument.CursorPosition!.Value, 0); | ||
var symbol = await GetSelectedSymbolAsync(textSpan, document, cancellationToken); | ||
var service = testWorkspace.Services.GetRequiredService<IValueTrackingService>(); | ||
return await service.TrackValueSourceAsync(testWorkspace.CurrentSolution, symbol, cancellationToken); | ||
|
||
} | ||
|
||
internal static async Task<ISymbol> GetSelectedSymbolAsync(TextSpan textSpan, Document document, CancellationToken cancellationToken) | ||
{ | ||
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); | ||
var selectedNode = root.FindNode(textSpan); | ||
|
||
Assert.NotNull(selectedNode); | ||
|
||
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); | ||
var selectedSymbol = | ||
semanticModel.GetSymbolInfo(selectedNode, cancellationToken).Symbol | ||
?? semanticModel.GetDeclaredSymbol(selectedNode, cancellationToken); | ||
|
||
Assert.NotNull(selectedSymbol); | ||
return selectedSymbol!; | ||
} | ||
|
||
internal static void ValidateItem(ValueTrackedItem item, int line) | ||
{ | ||
var lineSpan = item.Location.GetLineSpan(); | ||
Assert.Equal(line, lineSpan.StartLinePosition.Line); | ||
} | ||
} | ||
} |
Oops, something went wrong.