Skip to content

Commit 1b75734

Browse files
authored
Revert "Revert "Refactoring of Active Statement tracking for OOP"" (#44734)
* Revert "Revert "Refactoring of Active Statement tracking for OOP"" * Only apply active statement tracking for C# and VB buffers
1 parent 884fdff commit 1b75734

File tree

35 files changed

+1248
-831
lines changed

35 files changed

+1248
-831
lines changed

src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,26 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Collections.Immutable;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Microsoft.CodeAnalysis.EditAndContinue;
12+
using Microsoft.CodeAnalysis.EditAndContinue.UnitTests;
13+
using Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue;
14+
using Microsoft.CodeAnalysis.Editor.UnitTests;
15+
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
16+
using Microsoft.CodeAnalysis.Host;
17+
using Microsoft.CodeAnalysis.Test.Utilities;
18+
using Microsoft.CodeAnalysis.Text;
519
using Roslyn.Test.Utilities;
620
using Xunit;
721

822
namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests
923
{
24+
[UseExportProvider]
1025
public class ActiveStatementTrackingServiceTests : EditingTestBase
1126
{
1227
[Fact, WorkItem(846042, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/846042")]
@@ -125,5 +140,82 @@ static void Main(string[] args)
125140

126141
edits.VerifyRudeDiagnostics(active);
127142
}
143+
144+
[Theory]
145+
[CombinatorialData]
146+
public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTrackingBeforeOpenDoc)
147+
{
148+
var sourceV1 = "class C { void F() => G(1); void G(int a) => System.Console.WriteLine(1); }";
149+
150+
using var workspace = new TestWorkspace();
151+
152+
var span11 = new LinePositionSpan(new LinePosition(0, 10), new LinePosition(0, 15));
153+
var span12 = new LinePositionSpan(new LinePosition(0, 20), new LinePosition(0, 25));
154+
var span21 = new LinePositionSpan(new LinePosition(0, 11), new LinePosition(0, 16));
155+
var span22 = new LinePositionSpan(new LinePosition(0, 21), new LinePosition(0, 26));
156+
157+
var encService = new MockEditAndContinueWorkspaceService();
158+
159+
encService.GetBaseActiveStatementSpansAsyncImpl = documentIds => ImmutableArray.Create(ImmutableArray.Create(
160+
(span11, ActiveStatementFlags.IsNonLeafFrame),
161+
(span12, ActiveStatementFlags.IsLeafFrame)));
162+
163+
encService.GetDocumentActiveStatementSpansAsyncImpl = document => ImmutableArray.Create(
164+
(span21, ActiveStatementFlags.IsNonLeafFrame),
165+
(span22, ActiveStatementFlags.IsLeafFrame));
166+
167+
var testDocument = new TestHostDocument(text: sourceV1, exportProvider: workspace.ExportProvider);
168+
workspace.AddTestProject(new TestHostProject(workspace, testDocument));
169+
var textBuffer = testDocument.GetTextBuffer();
170+
171+
var solution = workspace.CurrentSolution;
172+
var project = solution.Projects.Single();
173+
var document = project.Documents.Single();
174+
var snapshot = textBuffer.CurrentSnapshot;
175+
Assert.Same(snapshot, document.GetTextSynchronously(CancellationToken.None).FindCorrespondingEditorTextSnapshot());
176+
177+
var trackingSession = new ActiveStatementTrackingService.TrackingSession(workspace, encService);
178+
179+
if (scheduleInitialTrackingBeforeOpenDoc)
180+
{
181+
await trackingSession.TrackActiveSpansAsync().ConfigureAwait(false);
182+
183+
var spans1 = trackingSession.Test_GetTrackingSpans();
184+
AssertEx.Equal(new[]
185+
{
186+
$"V0 →←@[10..15): IsNonLeafFrame",
187+
$"V0 →←@[20..25): IsLeafFrame"
188+
}, spans1[document.Id].Select(s => $"{s.Span}: {s.Flags}"));
189+
}
190+
191+
var spans2 = await trackingSession.GetLatestSpansAsync(document, snapshot, CancellationToken.None).ConfigureAwait(false);
192+
AssertEx.Equal(new[]
193+
{
194+
$"V0 →←@[11..16): IsNonLeafFrame",
195+
$"V0 →←@[21..26): IsLeafFrame"
196+
}, spans2.Select(s => $"{s.Span}: {s.Flags}"));
197+
198+
if (!scheduleInitialTrackingBeforeOpenDoc)
199+
{
200+
await trackingSession.TrackActiveSpansAsync().ConfigureAwait(false);
201+
202+
var spans1 = trackingSession.Test_GetTrackingSpans();
203+
AssertEx.Equal(new[]
204+
{
205+
$"V0 →←@[11..16): IsNonLeafFrame",
206+
$"V0 →←@[21..26): IsLeafFrame"
207+
}, spans1[document.Id].Select(s => $"{s.Span}: {s.Flags}"));
208+
}
209+
210+
// we are not able to determine active statements in a document:
211+
encService.GetDocumentActiveStatementSpansAsyncImpl = document => default;
212+
213+
var spans3 = await trackingSession.GetLatestSpansAsync(document, snapshot, CancellationToken.None).ConfigureAwait(false);
214+
AssertEx.Equal(new[]
215+
{
216+
$"V0 →←@[11..16): IsNonLeafFrame",
217+
$"V0 →←@[21..26): IsLeafFrame"
218+
}, spans3.Select(s => $"{s.Span}: {s.Flags}"));
219+
}
128220
}
129221
}

src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ public static void Main()
281281
var oldStatementSyntax = oldSyntaxRoot.FindNode(oldStatementTextSpan);
282282

283283
var baseActiveStatements = ImmutableArray.Create(ActiveStatementsDescription.CreateActiveStatement(ActiveStatementFlags.IsLeafFrame, oldStatementSpan, DocumentId.CreateNewId(ProjectId.CreateNewId())));
284-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newDocument, trackingService: null, CancellationToken.None);
284+
var spanTracker = new TestActiveStatementSpanTracker();
285+
286+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newDocument, spanTracker, CancellationToken.None);
285287

286288
Assert.True(result.HasChanges);
287289
Assert.True(result.SemanticEdits[0].PreserveLocalVariables);
@@ -326,7 +328,9 @@ public static void Main()
326328
var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2));
327329

328330
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
329-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), trackingService: null, CancellationToken.None);
331+
var spanTracker = new TestActiveStatementSpanTracker();
332+
333+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);
330334

331335
Assert.True(result.HasChanges);
332336
Assert.True(result.HasChangesAndErrors);
@@ -351,7 +355,9 @@ public static void Main()
351355
var oldProject = workspace.CurrentSolution.Projects.Single();
352356
var oldDocument = oldProject.Documents.Single();
353357
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
354-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, trackingService: null, CancellationToken.None);
358+
var spanTracker = new TestActiveStatementSpanTracker();
359+
360+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, spanTracker, CancellationToken.None);
355361

356362
Assert.False(result.HasChanges);
357363
Assert.False(result.HasChangesAndErrors);
@@ -391,7 +397,9 @@ public static void Main()
391397
var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2));
392398

393399
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
394-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), trackingService: null, CancellationToken.None);
400+
var spanTracker = new TestActiveStatementSpanTracker();
401+
402+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);
395403

396404
Assert.False(result.HasChanges);
397405
Assert.False(result.HasChangesAndErrors);
@@ -423,7 +431,9 @@ public static void Main()
423431
var documentId = oldDocument.Id;
424432

425433
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
426-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, trackingService: null, CancellationToken.None);
434+
var spanTracker = new TestActiveStatementSpanTracker();
435+
436+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, spanTracker, CancellationToken.None);
427437

428438
Assert.False(result.HasChanges);
429439
Assert.False(result.HasChangesAndErrors);
@@ -473,7 +483,9 @@ public static void Main()
473483
var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2));
474484

475485
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
476-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), trackingService: null, CancellationToken.None);
486+
var spanTracker = new TestActiveStatementSpanTracker();
487+
488+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);
477489

478490
Assert.True(result.HasChanges);
479491
Assert.True(result.HasChangesAndErrors);
@@ -505,7 +517,9 @@ public static void Main()
505517
var documentId = oldDocument.Id;
506518

507519
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
508-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, trackingService: null, CancellationToken.None);
520+
var spanTracker = new TestActiveStatementSpanTracker();
521+
522+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, spanTracker, CancellationToken.None);
509523

510524
Assert.False(result.HasChanges);
511525
Assert.False(result.HasChangesAndErrors);
@@ -547,7 +561,9 @@ public static void Main()
547561
var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2));
548562

549563
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
550-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), trackingService: null, CancellationToken.None);
564+
var spanTracker = new TestActiveStatementSpanTracker();
565+
566+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);
551567

552568
Assert.True(result.HasChanges);
553569

@@ -589,7 +605,9 @@ public static void Main(Bar x)
589605
var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2));
590606

591607
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
592-
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), trackingService: null, CancellationToken.None);
608+
var spanTracker = new TestActiveStatementSpanTracker();
609+
610+
var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);
593611

594612
Assert.True(result.HasChanges);
595613
Assert.True(result.HasChangesAndErrors);
@@ -640,9 +658,11 @@ public class D
640658

641659
var result = new List<DocumentAnalysisResults>();
642660
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
661+
var spanTracker = new TestActiveStatementSpanTracker();
662+
643663
foreach (var changedDocumentId in changedDocuments)
644664
{
645-
result.Add(await analyzer.AnalyzeDocumentAsync(oldProject.GetDocument(changedDocumentId), baseActiveStatements, newProject.GetDocument(changedDocumentId), trackingService: null, CancellationToken.None));
665+
result.Add(await analyzer.AnalyzeDocumentAsync(oldProject.GetDocument(changedDocumentId), baseActiveStatements, newProject.GetDocument(changedDocumentId), spanTracker, CancellationToken.None));
646666
}
647667

648668
Assert.True(result.IsSingle());
@@ -688,9 +708,11 @@ public static void Main()
688708

689709
var result = new List<DocumentAnalysisResults>();
690710
var baseActiveStatements = ImmutableArray.Create<ActiveStatement>();
711+
var spanTracker = new TestActiveStatementSpanTracker();
712+
691713
foreach (var changedDocumentId in changedDocuments)
692714
{
693-
result.Add(await analyzer.AnalyzeDocumentAsync(oldProject.GetDocument(changedDocumentId), baseActiveStatements, newProject.GetDocument(changedDocumentId), trackingService: null, CancellationToken.None));
715+
result.Add(await analyzer.AnalyzeDocumentAsync(oldProject.GetDocument(changedDocumentId), baseActiveStatements, newProject.GetDocument(changedDocumentId), spanTracker, CancellationToken.None));
694716
}
695717

696718
Assert.True(result.IsSingle());

src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/Extensions.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
#nullable enable
6+
57
using System.Collections.Generic;
68
using Microsoft.CodeAnalysis.Differencing;
79
using Microsoft.CodeAnalysis.EditAndContinue;
@@ -103,13 +105,13 @@ internal static void VerifySemantics(
103105

104106
internal static void VerifySemantics(
105107
this EditScript<SyntaxNode> editScript,
106-
ActiveStatementsDescription activeStatements = null,
107-
TargetFramework[] targetFrameworks = null,
108-
IEnumerable<string> additionalOldSources = null,
109-
IEnumerable<string> additionalNewSources = null,
110-
SemanticEditDescription[] expectedSemanticEdits = null,
111-
DiagnosticDescription expectedDeclarationError = null,
112-
RudeEditDiagnosticDescription[] expectedDiagnostics = null)
108+
ActiveStatementsDescription? activeStatements = null,
109+
TargetFramework[]? targetFrameworks = null,
110+
IEnumerable<string>? additionalOldSources = null,
111+
IEnumerable<string>? additionalNewSources = null,
112+
SemanticEditDescription[]? expectedSemanticEdits = null,
113+
DiagnosticDescription? expectedDeclarationError = null,
114+
RudeEditDiagnosticDescription[]? expectedDiagnostics = null)
113115
{
114116
foreach (var targetFramework in targetFrameworks ?? new[] { TargetFramework.NetStandard20, TargetFramework.NetCoreApp30 })
115117
{
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#nullable enable
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Composition;
10+
using Microsoft.CodeAnalysis.EditAndContinue;
11+
using Microsoft.CodeAnalysis.Host;
12+
using Microsoft.CodeAnalysis.Host.Mef;
13+
using Microsoft.CodeAnalysis.Text;
14+
15+
namespace Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue
16+
{
17+
internal sealed class ActiveStatementSpanTracker : IActiveStatementSpanTracker
18+
{
19+
[ExportWorkspaceServiceFactory(typeof(IActiveStatementSpanTracker), ServiceLayer.Editor), Shared]
20+
private sealed class Factory : IWorkspaceServiceFactory
21+
{
22+
[ImportingConstructor]
23+
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
24+
public Factory() { }
25+
26+
public IWorkspaceService CreateService(HostWorkspaceServices services)
27+
=> new ActiveStatementSpanTracker(services);
28+
}
29+
30+
private readonly IActiveStatementTrackingService _trackingService;
31+
32+
public ActiveStatementSpanTracker(HostWorkspaceServices services)
33+
{
34+
_trackingService = services.GetRequiredService<IActiveStatementTrackingService>();
35+
}
36+
37+
public bool TryGetSpan(ActiveStatementId id, SourceText source, out TextSpan span)
38+
=> _trackingService.TryGetSpan(id, source, out span);
39+
}
40+
}

0 commit comments

Comments
 (0)