From b7b107c32b404fab75b38d9309573a95e0dbceff Mon Sep 17 00:00:00 2001 From: David Wengier Date: Wed, 14 Apr 2021 12:00:27 +1000 Subject: [PATCH 01/32] Create capabilities parser and tests --- ...ManagedEditAndContinueCapabilitiesTests.cs | 75 +++++++++++++++++++ .../ManagedEditAndContinueCapabilities.cs | 51 +++++++++++++ .../ManagedEditAndContinueCapability.cs | 20 +++++ 3 files changed, 146 insertions(+) create mode 100644 src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs create mode 100644 src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs create mode 100644 src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs diff --git a/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs b/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs new file mode 100644 index 0000000000000..244afcbd7b182 --- /dev/null +++ b/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs @@ -0,0 +1,75 @@ +// 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 Xunit; + +namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests +{ + public class ManagedEditAndContinueCapabilitiesTests + { + [Fact] + public void Parse() + { + var capabilities = "Baseline"; + + var service = new ManagedEditAndContinueCapabilities(capabilities); + + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); + Assert.False(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void Parse_CaseSensitive() + { + var capabilities = "BaseLine"; + + var service = new ManagedEditAndContinueCapabilities(capabilities); + + Assert.False(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); + } + + [Fact] + public void Parse_IgnoreInvalid() + { + var capabilities = "Baseline Invalid RuntimeEdits"; + + var service = new ManagedEditAndContinueCapabilities(capabilities); + + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void Parse_IgnoreInvalidNumeric() + { + var capabilities = "Baseline 90 RuntimeEdits"; + + var service = new ManagedEditAndContinueCapabilities(capabilities); + + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void Parse_MultipleSpaces() + { + var capabilities = " Baseline RuntimeEdits "; + + var service = new ManagedEditAndContinueCapabilities(capabilities); + + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void HasCapability_IgnoreInvalid() + { + var capabilities = "Baseline"; + + var service = new ManagedEditAndContinueCapabilities(capabilities); + + Assert.False(service.HasCapability((ManagedEditAndContinueCapability)999)); + } + } +} diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs new file mode 100644 index 0000000000000..c8ef93211484f --- /dev/null +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs @@ -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; +using System.Net.Http.Headers; + +namespace Microsoft.CodeAnalysis.EditAndContinue +{ + internal class ManagedEditAndContinueCapabilities + { + internal static readonly ManagedEditAndContinueCapabilities Net5CoreCLR = new(ManagedEditAndContinueCapability.Baseline, ManagedEditAndContinueCapability.AddDefinitionToExistingType, ManagedEditAndContinueCapability.NewTypeDefinition); + internal static readonly ManagedEditAndContinueCapabilities Net6CoreCLR = new(ManagedEditAndContinueCapability.Baseline, ManagedEditAndContinueCapability.AddDefinitionToExistingType, ManagedEditAndContinueCapability.NewTypeDefinition, ManagedEditAndContinueCapability.RuntimeEdits); + internal static readonly ManagedEditAndContinueCapabilities Net5MonoVM = new(); + internal static readonly ManagedEditAndContinueCapabilities Net6MonoVM = new(ManagedEditAndContinueCapability.Baseline, ManagedEditAndContinueCapability.RuntimeEdits); + + private readonly bool[] _capabilities; + + private ManagedEditAndContinueCapabilities(params ManagedEditAndContinueCapability[] capabilities) + : this("") + { + foreach (var capability in capabilities) + { + _capabilities[(int)capability] = true; + } + } + + internal ManagedEditAndContinueCapabilities(string capabilities) + { + _capabilities = new bool[(int)ManagedEditAndContinueCapability.Count]; + + if (string.IsNullOrEmpty(capabilities)) + { + return; + } + + foreach (var capability in capabilities.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) + { + if (Enum.TryParse(capability, out ManagedEditAndContinueCapability result) && (int)result < (int)ManagedEditAndContinueCapability.Count) + { + _capabilities[(int)result] = true; + } + } + } + + public bool HasCapability(ManagedEditAndContinueCapability capability) + { + return (int)capability < (int)ManagedEditAndContinueCapability.Count && _capabilities[(int)capability]; + } + } +} diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs new file mode 100644 index 0000000000000..df9493412f8d9 --- /dev/null +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs @@ -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.EditAndContinue +{ + /// + /// The capabilities that the runtime has with respect to edit and continue + /// + internal enum ManagedEditAndContinueCapability + { + Baseline, + AddDefinitionToExistingType, + NewTypeDefinition, + RuntimeEdits, + + // Must be last + Count + } +} From 393b4d7cb90074069bb81fb4aa5b4f6d29938b83 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Wed, 14 Apr 2021 13:32:24 +1000 Subject: [PATCH 02/32] Nullable --- .../EditAndContinue/ManagedEditAndContinueCapabilities.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs index c8ef93211484f..3602db80b5f3a 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Net.Http.Headers; namespace Microsoft.CodeAnalysis.EditAndContinue { @@ -25,7 +24,7 @@ private ManagedEditAndContinueCapabilities(params ManagedEditAndContinueCapabili } } - internal ManagedEditAndContinueCapabilities(string capabilities) + internal ManagedEditAndContinueCapabilities(string? capabilities) { _capabilities = new bool[(int)ManagedEditAndContinueCapability.Count]; From 18bfbbec0daa736cf3acd37042c2acf1a39e61ae Mon Sep 17 00:00:00 2001 From: David Wengier Date: Wed, 14 Apr 2021 13:33:06 +1000 Subject: [PATCH 03/32] Add a temporary shim to get strongly typed capabilities that will be removed in future when the debugger API changes. --- ...ontinueDebuggerServiceExtensions_REMOVE.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs new file mode 100644 index 0000000000000..959882094eb90 --- /dev/null +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs @@ -0,0 +1,21 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; + +namespace Microsoft.CodeAnalysis.EditAndContinue +{ + internal static class ManagedEditAndContinueDebuggerServiceExtensions_REMOVE + { + /// + /// This will be removed when IManagedEditAndContinueDebuggerService gets the method for real + /// + public static ValueTask GetCapabilitiesAsync(this IManagedEditAndContinueDebuggerService _1, CancellationToken _2) + { + return new ValueTask("Baseline"); + } + } +} From 2a1b7777f0dcd657e004e907696c5faffa767fc2 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Wed, 14 Apr 2021 13:55:37 +1000 Subject: [PATCH 04/32] Plumb through to analyzer --- .../AbstractEditAndContinueAnalyzer.cs | 1 + .../EditAndContinue/DebuggingSession.cs | 9 +++++++++ .../EditAndContinueDocumentAnalysesCache.cs | 18 +++++++++++------- .../EditAndContinueWorkspaceService.cs | 12 +++++++++--- .../Portable/EditAndContinue/EditSession.cs | 4 +++- .../IEditAndContinueAnalyzer.cs | 2 +- 6 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 30ca572b91487..3a4f411138ef5 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -439,6 +439,7 @@ public async Task AnalyzeDocumentAsync( ImmutableArray oldActiveStatements, Document newDocument, ImmutableArray newActiveStatementSpans, + ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { DocumentAnalysisResults.Log.Write("Analyzing document {0}", newDocument.Name); diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index a741aa2245304..c76f79f5aa2ed 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -295,6 +295,15 @@ public bool TryGetOrCreateEmitBaseline(Project project, out ImmutableArray + /// Gets the capabilities of the runtime with respect to applying code changes. + /// + public async Task GetCapabilitiesAsync(CancellationToken cancellationToken) + { + var runtimeCapabiltiies = await DebuggerService.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + return new ManagedEditAndContinueCapabilities(runtimeCapabiltiies); + } + private static unsafe bool TryCreateInitialBaseline( CompilationOutputs compilationOutputs, out ImmutableArray diagnostics, diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs index 622b89a776cfd..9afe23240d5ce 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs @@ -30,11 +30,11 @@ public EditAndContinueDocumentAnalysesCache(AsyncLazy baseA _baseActiveStatements = baseActiveStatements; } - public async ValueTask> GetActiveStatementsAsync(Document baseDocument, Document document, ImmutableArray activeStatementSpans, CancellationToken cancellationToken) + public async ValueTask> GetActiveStatementsAsync(Document baseDocument, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { try { - var results = await GetDocumentAnalysisAsync(baseDocument.Project, document, activeStatementSpans, cancellationToken).ConfigureAwait(false); + var results = await GetDocumentAnalysisAsync(baseDocument.Project, document, activeStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); return results.ActiveStatements; } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) @@ -46,6 +46,7 @@ public async ValueTask> GetActiveStatementsAsync public async ValueTask> GetDocumentAnalysesAsync( Project oldProject, IReadOnlyList<(Document newDocument, ImmutableArray newActiveStatementSpans)> documentInfos, + ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { try @@ -55,7 +56,7 @@ public async ValueTask> GetDocumentAnaly return ImmutableArray.Empty; } - var tasks = documentInfos.Select(info => Task.Run(() => GetDocumentAnalysisAsync(oldProject, info.newDocument, info.newActiveStatementSpans, cancellationToken).AsTask(), cancellationToken)); + var tasks = documentInfos.Select(info => Task.Run(() => GetDocumentAnalysisAsync(oldProject, info.newDocument, info.newActiveStatementSpans, capabilities, cancellationToken).AsTask(), cancellationToken)); var allResults = await Task.WhenAll(tasks).ConfigureAwait(false); return allResults.ToImmutableArray(); @@ -72,7 +73,7 @@ public async ValueTask> GetDocumentAnaly /// Base project. /// Document snapshot to analyze. /// Active statement spans tracked by the editor. - public async ValueTask GetDocumentAnalysisAsync(Project baseProject, Document document, ImmutableArray activeStatementSpans, CancellationToken cancellationToken) + public async ValueTask GetDocumentAnalysisAsync(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { try { @@ -80,7 +81,7 @@ public async ValueTask GetDocumentAnalysisAsync(Project lock (_guard) { - lazyResults = GetDocumentAnalysisNoLock(baseProject, document, activeStatementSpans); + lazyResults = GetDocumentAnalysisNoLock(baseProject, document, activeStatementSpans, capabilities); } return await lazyResults.GetValueAsync(cancellationToken).ConfigureAwait(false); @@ -91,7 +92,7 @@ public async ValueTask GetDocumentAnalysisAsync(Project } } - private AsyncLazy GetDocumentAnalysisNoLock(Project baseProject, Document document, ImmutableArray activeStatementSpans) + private AsyncLazy GetDocumentAnalysisNoLock(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapabilities capabilities) { // Do not reuse an analysis of the document unless its snasphot is exactly the same as was used to calculate the results. // Note that comparing document snapshots in effect compares the entire solution snapshots (when another document is changed a new solution snapshot is created @@ -104,6 +105,9 @@ private AsyncLazy GetDocumentAnalysisNoLock(Project bas // For example, when analyzing a partial class we can record all documents its declaration spans. However, in other cases the analysis // checks for absence of a top-level type symbol. Adding a symbol to any document thus invalidates such analysis. It'd be possible // to keep track of which type symbols an analysis is conditional upon, if it was worth the extra complexity. + // + // Note that this doesn't check the runtime capabilities on the asusmption that they can't change without at least a project change, + // though possibly they can't change at all. if (_analyses.TryGetValue(document.Id, out var analysis) && analysis.baseProject == baseProject && analysis.document == document && @@ -125,7 +129,7 @@ private AsyncLazy GetDocumentAnalysisNoLock(Project bas documentBaseActiveStatements = ImmutableArray.Empty; } - return await analyzer.AnalyzeDocumentAsync(baseProject, documentBaseActiveStatements, document, activeStatementSpans, cancellationToken).ConfigureAwait(false); + return await analyzer.AnalyzeDocumentAsync(baseProject, documentBaseActiveStatements, document, activeStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index 0567974a98dc6..cdbef91003843 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -172,8 +172,9 @@ public async ValueTask> GetDocumentDiagnosticsAsync(D } var editSession = debuggingSession.EditSession; + var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); var documentActiveStatementSpans = await activeStatementSpanProvider(cancellationToken).ConfigureAwait(false); - var analysis = await editSession.Analyses.GetDocumentAnalysisAsync(oldProject, document, documentActiveStatementSpans, cancellationToken).ConfigureAwait(false); + var analysis = await editSession.Analyses.GetDocumentAnalysisAsync(oldProject, document, documentActiveStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); if (analysis.HasChanges) { // Once we detected a change in a document let the debugger know that the corresponding loaded module @@ -284,6 +285,8 @@ public void DiscardSolutionUpdate() var lastCommittedSolution = debuggingSession.LastCommittedSolution; var baseActiveStatements = await debuggingSession.EditSession.BaseActiveStatements.GetValueAsync(cancellationToken).ConfigureAwait(false); + var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + using var _ = ArrayBuilder>.GetInstance(out var spans); foreach (var documentId in documentIds) @@ -311,6 +314,7 @@ public void DiscardSolutionUpdate() documentBaseActiveStatements, document, newActiveStatementSpans: ImmutableArray.Empty, + capabilities, cancellationToken).ConfigureAwait(false); if (!analysis.ActiveStatements.IsDefault) @@ -350,7 +354,8 @@ public void DiscardSolutionUpdate() } var documentActiveStatementSpans = await activeStatementSpanProvider(cancellationToken).ConfigureAwait(false); - var activeStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(baseDocument, document, documentActiveStatementSpans, cancellationToken).ConfigureAwait(false); + var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + var activeStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(baseDocument, document, documentActiveStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); if (activeStatements.IsDefault) { return default; @@ -395,7 +400,8 @@ public void DiscardSolutionUpdate() } var activeStatementSpans = await activeStatementSpanProvider(primaryDocument.Id, cancellationToken).ConfigureAwait(false); - var currentActiveStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(oldPrimaryDocument, primaryDocument, activeStatementSpans, cancellationToken).ConfigureAwait(false); + var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + var currentActiveStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(oldPrimaryDocument, primaryDocument, activeStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); if (currentActiveStatements.IsDefault) { // The document has syntax errors. diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index a7aa726b6f0ab..ac419edb5e0c3 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -444,7 +444,9 @@ private static async Task PopulateChangedAndAddedDocumentsAsync(CommittedSolutio var oldProject = DebuggingSession.LastCommittedSolution.GetProject(newProject.Id); Contract.ThrowIfNull(oldProject); - var analyses = await Analyses.GetDocumentAnalysesAsync(oldProject, builder, cancellationToken).ConfigureAwait(false); + var capabilities = await DebuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + + var analyses = await Analyses.GetDocumentAnalysesAsync(oldProject, builder, capabilities, cancellationToken).ConfigureAwait(false); return (analyses, documentDiagnostics.ToImmutable()); } diff --git a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs index fc3602b9525f5..8196b19ab3fad 100644 --- a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal interface IEditAndContinueAnalyzer : ILanguageService { - Task AnalyzeDocumentAsync(Project baseProject, ImmutableArray baseActiveStatements, Document document, ImmutableArray newActiveStatementSpans, CancellationToken cancellationToken); + Task AnalyzeDocumentAsync(Project baseProject, ImmutableArray baseActiveStatements, Document document, ImmutableArray newActiveStatementSpans, ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken); ImmutableArray GetExceptionRegions(SourceText text, SyntaxNode syntaxRoot, LinePositionSpan activeStatementSpan, bool isLeaf, out bool isCovered); } } From 728cf41d73b78cd91101d8a8a3f6b3c982bba5b1 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Wed, 14 Apr 2021 13:55:44 +1000 Subject: [PATCH 05/32] Update tests --- .../CSharpEditAndContinueAnalyzerTests.cs | 24 +++++++++---------- .../EditAndContinueTestHelpers.cs | 2 +- ...VisualBasicEditAndContinueAnalyzerTests.vb | 14 +++++------ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index a6f68489a40e9..e40be95ffb881 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -289,7 +289,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(ActiveStatementsDescription.CreateActiveStatement(ActiveStatementFlags.IsLeafFrame, oldStatementSpan, DocumentId.CreateNewId(ProjectId.CreateNewId()))); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.True(result.HasChanges); var syntaxMap = result.SemanticEdits[0].SyntaxMap; @@ -335,7 +335,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); @@ -361,7 +361,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -402,7 +402,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -435,7 +435,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -486,7 +486,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); @@ -519,7 +519,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -562,7 +562,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.True(result.HasChanges); @@ -605,7 +605,7 @@ public static void Main(Bar x) var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); Assert.True(result.HasChanges); @@ -662,7 +662,7 @@ public class D foreach (var changedDocumentId in changedDocuments) { - result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, CancellationToken.None)); + result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None)); } Assert.True(result.IsSingle()); @@ -714,7 +714,7 @@ class D foreach (var changedDocumentId in changedDocuments) { - result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, CancellationToken.None)); + result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None)); } Assert.True(result.IsSingle()); @@ -748,7 +748,7 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) } }); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); var expectedDiagnostic = outOfMemory ? $"ENC0089: {string.Format(FeaturesResources.Modifying_source_file_will_prevent_the_debug_session_from_continuing_because_the_file_is_too_big, "src.cs")}" : diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index eaae72b51290e..43da6015528c9 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -185,7 +185,7 @@ internal void VerifySemantics(EditScript[] editScripts, TargetFramew Contract.ThrowIfNull(oldModel); Contract.ThrowIfNull(newModel); - var result = Analyzer.AnalyzeDocumentAsync(oldProject, oldActiveStatements, newDocument, newActiveStatementSpans, CancellationToken.None).Result; + var result = Analyzer.AnalyzeDocumentAsync(oldProject, oldActiveStatements, newDocument, newActiveStatementSpans, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None).Result; var oldText = oldDocument.GetTextSynchronously(default); var newText = newDocument.GetTextSynchronously(default); diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb index d940b1d771828..e98f4b121bf21 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb @@ -470,7 +470,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(ActiveStatementsDescription.CreateActiveStatement(ActiveStatementFlags.IsLeafFrame, oldStatementSpan, DocumentId.CreateNewId(ProjectId.CreateNewId()))) - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray(Of TextSpan).Empty, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) Assert.True(result.HasChanges) Dim syntaxMap = result.SemanticEdits(0).SyntaxMap @@ -500,7 +500,7 @@ End Class Dim oldDocument = oldProject.Documents.Single() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() Dim analyzer = New VisualBasicEditAndContinueAnalyzer() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) Assert.False(result.HasChanges) Assert.False(result.HasChangesAndErrors) @@ -534,7 +534,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) Assert.False(result.HasChanges) Assert.False(result.HasChangesAndErrors) @@ -558,7 +558,7 @@ End Class Dim oldDocument = oldProject.Documents.Single() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() Dim analyzer = New VisualBasicEditAndContinueAnalyzer() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) Assert.False(result.HasChanges) Assert.False(result.HasChangesAndErrors) @@ -594,7 +594,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) ' no declaration errors (error in method body is only reported when emitting) Assert.False(result.HasChangesAndErrors) @@ -627,7 +627,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) Assert.True(result.HasChanges) @@ -697,7 +697,7 @@ End Class Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() Dim analyzer = New VisualBasicEditAndContinueAnalyzer() For Each changedDocumentId In changedDocuments - result.Add(Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray(Of TextSpan).Empty, CancellationToken.None)) + result.Add(Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None)) Next Assert.True(result.IsSingle()) From 12c1c0d4f8caa7833c4919b1cfdc56a617f32967 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 16 Apr 2021 08:32:51 +1000 Subject: [PATCH 06/32] Use flags enum and direct parsing --- .../ManagedEditAndContinueCapabilities.cs | 50 +++++++++---------- .../ManagedEditAndContinueCapability.cs | 14 +++--- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs index 3602db80b5f3a..332bf3dec3b6b 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs @@ -2,49 +2,49 @@ // 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; - namespace Microsoft.CodeAnalysis.EditAndContinue { internal class ManagedEditAndContinueCapabilities { - internal static readonly ManagedEditAndContinueCapabilities Net5CoreCLR = new(ManagedEditAndContinueCapability.Baseline, ManagedEditAndContinueCapability.AddDefinitionToExistingType, ManagedEditAndContinueCapability.NewTypeDefinition); - internal static readonly ManagedEditAndContinueCapabilities Net6CoreCLR = new(ManagedEditAndContinueCapability.Baseline, ManagedEditAndContinueCapability.AddDefinitionToExistingType, ManagedEditAndContinueCapability.NewTypeDefinition, ManagedEditAndContinueCapability.RuntimeEdits); - internal static readonly ManagedEditAndContinueCapabilities Net5MonoVM = new(); - internal static readonly ManagedEditAndContinueCapabilities Net6MonoVM = new(ManagedEditAndContinueCapability.Baseline, ManagedEditAndContinueCapability.RuntimeEdits); + internal static readonly ManagedEditAndContinueCapabilities Net5CoreCLR = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition); + internal static readonly ManagedEditAndContinueCapabilities Net6CoreCLR = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition | ManagedEditAndContinueCapability.RuntimeEdits); + internal static readonly ManagedEditAndContinueCapabilities Net5MonoVM = new(ManagedEditAndContinueCapability.None); + internal static readonly ManagedEditAndContinueCapabilities Net6MonoVM = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.RuntimeEdits); - private readonly bool[] _capabilities; + private readonly ManagedEditAndContinueCapability _capabilities; - private ManagedEditAndContinueCapabilities(params ManagedEditAndContinueCapability[] capabilities) - : this("") + private ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability capabilities) { - foreach (var capability in capabilities) - { - _capabilities[(int)capability] = true; - } + _capabilities = capabilities; } internal ManagedEditAndContinueCapabilities(string? capabilities) { - _capabilities = new bool[(int)ManagedEditAndContinueCapability.Count]; - - if (string.IsNullOrEmpty(capabilities)) - { - return; - } + var caps = ManagedEditAndContinueCapability.None; - foreach (var capability in capabilities.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) + if (!string.IsNullOrEmpty(capabilities)) { - if (Enum.TryParse(capability, out ManagedEditAndContinueCapability result) && (int)result < (int)ManagedEditAndContinueCapability.Count) + foreach (var capability in capabilities.Split(' ')) { - _capabilities[(int)result] = true; + caps |= ParseCapability(capability); } } + + _capabilities = caps; } + private static ManagedEditAndContinueCapability ParseCapability(string capability) + => capability switch + { + "Baseline" => ManagedEditAndContinueCapability.Baseline, + "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, + "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, + "RuntimeEdits" => ManagedEditAndContinueCapability.RuntimeEdits, + + _ => ManagedEditAndContinueCapability.None + }; + public bool HasCapability(ManagedEditAndContinueCapability capability) - { - return (int)capability < (int)ManagedEditAndContinueCapability.Count && _capabilities[(int)capability]; - } + => (_capabilities & capability) == capability; } } diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs index df9493412f8d9..405a2dde5a12a 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs @@ -2,19 +2,21 @@ // 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; + namespace Microsoft.CodeAnalysis.EditAndContinue { /// /// The capabilities that the runtime has with respect to edit and continue /// + [Flags] internal enum ManagedEditAndContinueCapability { - Baseline, - AddDefinitionToExistingType, - NewTypeDefinition, - RuntimeEdits, + None = 0, - // Must be last - Count + Baseline = 1 << 0, + AddDefinitionToExistingType = 1 << 1, + NewTypeDefinition = 1 << 2, + RuntimeEdits = 1 << 3, } } From 6e87e88c3798d5969e54aec7bd0fff5ab7a400c6 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 16 Apr 2021 08:33:22 +1000 Subject: [PATCH 07/32] Fix typo --- .../Core/Portable/EditAndContinue/DebuggingSession.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index c76f79f5aa2ed..d0592bc054ddb 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -300,8 +300,8 @@ public bool TryGetOrCreateEmitBaseline(Project project, out ImmutableArray public async Task GetCapabilitiesAsync(CancellationToken cancellationToken) { - var runtimeCapabiltiies = await DebuggerService.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); - return new ManagedEditAndContinueCapabilities(runtimeCapabiltiies); + var runtimeCapabilities = await DebuggerService.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + return new ManagedEditAndContinueCapabilities(runtimeCapabilities); } private static unsafe bool TryCreateInitialBaseline( From aeb0833cdf80bb69cf7292d04c2c4598c71f808b Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 16 Apr 2021 09:15:42 +1000 Subject: [PATCH 08/32] Pass capabilities into the debug session --- .../EditAndContinue/DebuggingSession.cs | 18 ++++++++---------- .../EditAndContinueWorkspaceService.cs | 17 ++++++++--------- .../Portable/EditAndContinue/EditSession.cs | 4 +--- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index d0592bc054ddb..5db988460ee61 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -98,12 +98,13 @@ internal sealed class DebuggingSession : IDisposable internal readonly IManagedEditAndContinueDebuggerService DebuggerService; private readonly DebuggingSessionTelemetry _telemetry; - + private readonly ManagedEditAndContinueCapabilities _capabilities; internal EditSession EditSession; internal DebuggingSession( Solution solution, IManagedEditAndContinueDebuggerService debuggerService, + ManagedEditAndContinueCapabilities capabilities, Func compilationOutputsProvider, IEnumerable> initialDocumentStates, DebuggingSessionTelemetry debuggingSessionTelemetry, @@ -111,6 +112,7 @@ internal DebuggingSession( { _compilationOutputsProvider = compilationOutputsProvider; _telemetry = debuggingSessionTelemetry; + _capabilities = capabilities; DebuggerService = debuggerService; LastCommittedSolution = new CommittedSolution(this, solution, initialDocumentStates); @@ -120,6 +122,11 @@ internal DebuggingSession( internal CancellationToken CancellationToken => _cancellationSource.Token; + /// + /// Gets the capabilities of the runtime with respect to applying code changes. + /// + internal ManagedEditAndContinueCapabilities Capabilities => _capabilities; + public void Dispose() { _cancellationSource.Cancel(); @@ -295,15 +302,6 @@ public bool TryGetOrCreateEmitBaseline(Project project, out ImmutableArray - /// Gets the capabilities of the runtime with respect to applying code changes. - /// - public async Task GetCapabilitiesAsync(CancellationToken cancellationToken) - { - var runtimeCapabilities = await DebuggerService.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); - return new ManagedEditAndContinueCapabilities(runtimeCapabilities); - } - private static unsafe bool TryCreateInitialBaseline( CompilationOutputs compilationOutputs, out ImmutableArray diagnostics, diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index cdbef91003843..f86a88868b8d7 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -85,7 +85,10 @@ public async ValueTask StartDebuggingSessionAsync(Solution solution, IManagedEdi captureMatchingDocuments ? await CommittedSolution.GetMatchingDocumentsAsync(solution, _compilationOutputsProvider, cancellationToken).ConfigureAwait(false) : SpecializedCollections.EmptyEnumerable>(); - var newSession = new DebuggingSession(solution, debuggerService, _compilationOutputsProvider, initialDocumentStates, _debuggingSessionTelemetry, _editSessionTelemetry); + var runtimeCapabilities = await debuggerService.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); + var capabilities = new ManagedEditAndContinueCapabilities(runtimeCapabilities); + + var newSession = new DebuggingSession(solution, debuggerService, capabilities, _compilationOutputsProvider, initialDocumentStates, _debuggingSessionTelemetry, _editSessionTelemetry); var previousSession = Interlocked.CompareExchange(ref _debuggingSession, newSession, null); Contract.ThrowIfFalse(previousSession == null, "New debugging session can't be started until the existing one has ended."); } @@ -172,9 +175,8 @@ public async ValueTask> GetDocumentDiagnosticsAsync(D } var editSession = debuggingSession.EditSession; - var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); var documentActiveStatementSpans = await activeStatementSpanProvider(cancellationToken).ConfigureAwait(false); - var analysis = await editSession.Analyses.GetDocumentAnalysisAsync(oldProject, document, documentActiveStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); + var analysis = await editSession.Analyses.GetDocumentAnalysisAsync(oldProject, document, documentActiveStatementSpans, debuggingSession.Capabilities, cancellationToken).ConfigureAwait(false); if (analysis.HasChanges) { // Once we detected a change in a document let the debugger know that the corresponding loaded module @@ -285,7 +287,6 @@ public void DiscardSolutionUpdate() var lastCommittedSolution = debuggingSession.LastCommittedSolution; var baseActiveStatements = await debuggingSession.EditSession.BaseActiveStatements.GetValueAsync(cancellationToken).ConfigureAwait(false); - var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder>.GetInstance(out var spans); @@ -314,7 +315,7 @@ public void DiscardSolutionUpdate() documentBaseActiveStatements, document, newActiveStatementSpans: ImmutableArray.Empty, - capabilities, + debuggingSession.Capabilities, cancellationToken).ConfigureAwait(false); if (!analysis.ActiveStatements.IsDefault) @@ -354,8 +355,7 @@ public void DiscardSolutionUpdate() } var documentActiveStatementSpans = await activeStatementSpanProvider(cancellationToken).ConfigureAwait(false); - var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); - var activeStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(baseDocument, document, documentActiveStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); + var activeStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(baseDocument, document, documentActiveStatementSpans, debuggingSession.Capabilities, cancellationToken).ConfigureAwait(false); if (activeStatements.IsDefault) { return default; @@ -400,8 +400,7 @@ public void DiscardSolutionUpdate() } var activeStatementSpans = await activeStatementSpanProvider(primaryDocument.Id, cancellationToken).ConfigureAwait(false); - var capabilities = await debuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); - var currentActiveStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(oldPrimaryDocument, primaryDocument, activeStatementSpans, capabilities, cancellationToken).ConfigureAwait(false); + var currentActiveStatements = await debuggingSession.EditSession.Analyses.GetActiveStatementsAsync(oldPrimaryDocument, primaryDocument, activeStatementSpans, debuggingSession.Capabilities, cancellationToken).ConfigureAwait(false); if (currentActiveStatements.IsDefault) { // The document has syntax errors. diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index ac419edb5e0c3..6d1adc2be1962 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -444,9 +444,7 @@ private static async Task PopulateChangedAndAddedDocumentsAsync(CommittedSolutio var oldProject = DebuggingSession.LastCommittedSolution.GetProject(newProject.Id); Contract.ThrowIfNull(oldProject); - var capabilities = await DebuggingSession.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); - - var analyses = await Analyses.GetDocumentAnalysesAsync(oldProject, builder, capabilities, cancellationToken).ConfigureAwait(false); + var analyses = await Analyses.GetDocumentAnalysesAsync(oldProject, builder, DebuggingSession.Capabilities, cancellationToken).ConfigureAwait(false); return (analyses, documentDiagnostics.ToImmutable()); } From dae8308a27703c35a379b2a03ed3559965671ef5 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 16 Apr 2021 09:17:14 +1000 Subject: [PATCH 09/32] Move predefined sets into test code --- .../CSharpEditAndContinueAnalyzerTests.cs | 24 +++++++++---------- .../EditSessionActiveStatementsTests.cs | 1 + .../EditAndContinueTestHelpers.cs | 4 +++- ...VisualBasicEditAndContinueAnalyzerTests.vb | 14 +++++------ .../ManagedEditAndContinueCapabilities.cs | 8 ++----- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index e40be95ffb881..d0f6fab91a745 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -289,7 +289,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(ActiveStatementsDescription.CreateActiveStatement(ActiveStatementFlags.IsLeafFrame, oldStatementSpan, DocumentId.CreateNewId(ProjectId.CreateNewId()))); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.True(result.HasChanges); var syntaxMap = result.SemanticEdits[0].SyntaxMap; @@ -335,7 +335,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); @@ -361,7 +361,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -402,7 +402,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -435,7 +435,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -486,7 +486,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); @@ -519,7 +519,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); @@ -562,7 +562,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.True(result.HasChanges); @@ -605,7 +605,7 @@ public static void Main(Bar x) var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); Assert.True(result.HasChanges); @@ -662,7 +662,7 @@ public class D foreach (var changedDocumentId in changedDocuments) { - result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None)); + result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None)); } Assert.True(result.IsSingle()); @@ -714,7 +714,7 @@ class D foreach (var changedDocumentId in changedDocuments) { - result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None)); + result.Add(await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None)); } Assert.True(result.IsSingle()); @@ -748,7 +748,7 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) } }); - var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None); + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None); var expectedDiagnostic = outOfMemory ? $"ENC0089: {string.Format(FeaturesResources.Modifying_source_file_will_prevent_the_debug_session_from_continuing_because_the_file_is_too_big, "src.cs")}" : diff --git a/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs index 63377aad61c5d..34d88aa0f4ea6 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs @@ -49,6 +49,7 @@ private static EditSession CreateEditSession( var debuggingSession = new DebuggingSession( solution, mockDebuggerService, + EditAndContinueTestHelpers.Net5RuntimeCapabilities, mockCompilationOutputsProvider, SpecializedCollections.EmptyEnumerable>(), new DebuggingSessionTelemetry(), diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index 43da6015528c9..c904da571a825 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -29,6 +29,8 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { internal abstract class EditAndContinueTestHelpers { + public static readonly ManagedEditAndContinueCapabilities Net5RuntimeCapabilities = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition); + public abstract AbstractEditAndContinueAnalyzer Analyzer { get; } public abstract SyntaxNode FindNode(SyntaxNode root, TextSpan span); public abstract SyntaxTree ParseText(string source); @@ -185,7 +187,7 @@ internal void VerifySemantics(EditScript[] editScripts, TargetFramew Contract.ThrowIfNull(oldModel); Contract.ThrowIfNull(newModel); - var result = Analyzer.AnalyzeDocumentAsync(oldProject, oldActiveStatements, newDocument, newActiveStatementSpans, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None).Result; + var result = Analyzer.AnalyzeDocumentAsync(oldProject, oldActiveStatements, newDocument, newActiveStatementSpans, Net5RuntimeCapabilities, CancellationToken.None).Result; var oldText = oldDocument.GetTextSynchronously(default); var newText = newDocument.GetTextSynchronously(default); diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb index e98f4b121bf21..a3fbf6a28291c 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb @@ -470,7 +470,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(ActiveStatementsDescription.CreateActiveStatement(ActiveStatementFlags.IsLeafFrame, oldStatementSpan, DocumentId.CreateNewId(ProjectId.CreateNewId()))) - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None) Assert.True(result.HasChanges) Dim syntaxMap = result.SemanticEdits(0).SyntaxMap @@ -500,7 +500,7 @@ End Class Dim oldDocument = oldProject.Documents.Single() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() Dim analyzer = New VisualBasicEditAndContinueAnalyzer() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None) Assert.False(result.HasChanges) Assert.False(result.HasChangesAndErrors) @@ -534,7 +534,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None) Assert.False(result.HasChanges) Assert.False(result.HasChangesAndErrors) @@ -558,7 +558,7 @@ End Class Dim oldDocument = oldProject.Documents.Single() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() Dim analyzer = New VisualBasicEditAndContinueAnalyzer() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, oldDocument, ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None) Assert.False(result.HasChanges) Assert.False(result.HasChangesAndErrors) @@ -594,7 +594,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None) ' no declaration errors (error in method body is only reported when emitting) Assert.False(result.HasChangesAndErrors) @@ -627,7 +627,7 @@ End Class Dim analyzer = New VisualBasicEditAndContinueAnalyzer() Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() - Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None) + Dim result = Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None) Assert.True(result.HasChanges) @@ -697,7 +697,7 @@ End Class Dim baseActiveStatements = ImmutableArray.Create(Of ActiveStatement)() Dim analyzer = New VisualBasicEditAndContinueAnalyzer() For Each changedDocumentId In changedDocuments - result.Add(Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray(Of TextSpan).Empty, ManagedEditAndContinueCapabilities.Net5CoreCLR, CancellationToken.None)) + result.Add(Await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray(Of TextSpan).Empty, EditAndContinueTestHelpers.Net5RuntimeCapabilities, CancellationToken.None)) Next Assert.True(result.IsSingle()) diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs index 332bf3dec3b6b..4317592f8527e 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs @@ -6,14 +6,10 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal class ManagedEditAndContinueCapabilities { - internal static readonly ManagedEditAndContinueCapabilities Net5CoreCLR = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition); - internal static readonly ManagedEditAndContinueCapabilities Net6CoreCLR = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition | ManagedEditAndContinueCapability.RuntimeEdits); - internal static readonly ManagedEditAndContinueCapabilities Net5MonoVM = new(ManagedEditAndContinueCapability.None); - internal static readonly ManagedEditAndContinueCapabilities Net6MonoVM = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.RuntimeEdits); - private readonly ManagedEditAndContinueCapability _capabilities; - private ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability capabilities) + // For testing purposes + internal ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability capabilities) { _capabilities = capabilities; } From f534ad3d5d5122794ad449ed13574cde3650e52b Mon Sep 17 00:00:00 2001 From: David Wengier Date: Fri, 16 Apr 2021 16:46:02 +1000 Subject: [PATCH 10/32] Block additions in existing types --- .../Helpers/EditAndContinueValidation.cs | 44 ++++++++++++++++--- .../EditAndContinue/TopLevelEditingTests.cs | 13 ++++++ .../EditAndContinueTestHelpers.cs | 5 ++- .../AbstractEditAndContinueAnalyzer.cs | 11 +++++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs index b45ad8c484eaa..ec0ea59496798 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs @@ -32,7 +32,23 @@ internal static void VerifyRudeDiagnostics( this EditScript editScript, params RudeEditDiagnosticDescription[] expectedDiagnostics) { - VerifyRudeDiagnostics(editScript, ActiveStatementsDescription.Empty, expectedDiagnostics); + VerifySemanticDiagnostics( + editScript, + ActiveStatementsDescription.Empty, + capabilities: null, + expectedDiagnostics); + } + + internal static void VerifyRudeDiagnostics( + this EditScript editScript, + ManagedEditAndContinueCapabilities? capabilities = null, + params RudeEditDiagnosticDescription[] expectedDiagnostics) + { + VerifySemanticDiagnostics( + editScript, + ActiveStatementsDescription.Empty, + capabilities, + expectedDiagnostics); } internal static void VerifyRudeDiagnostics( @@ -43,6 +59,7 @@ internal static void VerifyRudeDiagnostics( VerifySemanticDiagnostics( editScript, description, + capabilities: null, expectedDiagnostics); } @@ -68,14 +85,24 @@ internal static void VerifySemanticDiagnostics( new[] { new DocumentAnalysisResultsDescription(diagnostics: expectedDiagnostics) }); } + internal static void VerifySemanticDiagnostics( + this EditScript editScript, + ActiveStatementsDescription activeStatements, + params RudeEditDiagnosticDescription[] expectedDiagnostics) + { + VerifySemanticDiagnostics(editScript, activeStatements, capabilities: null, expectedDiagnostics); + } + internal static void VerifySemanticDiagnostics( this EditScript editScript, ActiveStatementsDescription activeStatements, + ManagedEditAndContinueCapabilities? capabilities = null, params RudeEditDiagnosticDescription[] expectedDiagnostics) { VerifySemantics( new[] { editScript }, - new[] { new DocumentAnalysisResultsDescription(activeStatements: activeStatements, diagnostics: expectedDiagnostics) }); + new[] { new DocumentAnalysisResultsDescription(activeStatements: activeStatements, diagnostics: expectedDiagnostics) }, + capabilities: capabilities); } internal static void VerifySemanticDiagnostics( @@ -92,28 +119,31 @@ internal static void VerifySemanticDiagnostics( internal static void VerifySemantics( this EditScript editScript, ActiveStatementsDescription activeStatements, - SemanticEditDescription[] expectedSemanticEdits) + SemanticEditDescription[] expectedSemanticEdits, + ManagedEditAndContinueCapabilities? capabilities = null) { VerifySemantics( new[] { editScript }, - new[] { new DocumentAnalysisResultsDescription(activeStatements, semanticEdits: expectedSemanticEdits) }); + new[] { new DocumentAnalysisResultsDescription(activeStatements, semanticEdits: expectedSemanticEdits) }, + capabilities: capabilities); } internal static void VerifySemantics( this EditScript editScript, params SemanticEditDescription[] expectedSemanticEdits) { - VerifySemantics(editScript, ActiveStatementsDescription.Empty, expectedSemanticEdits); + VerifySemantics(editScript, ActiveStatementsDescription.Empty, expectedSemanticEdits, capabilities: null); } internal static void VerifySemantics( EditScript[] editScripts, DocumentAnalysisResultsDescription[] expected, - TargetFramework[]? targetFrameworks = null) + TargetFramework[]? targetFrameworks = null, + ManagedEditAndContinueCapabilities? capabilities = null) { foreach (var targetFramework in targetFrameworks ?? new[] { TargetFramework.NetStandard20, TargetFramework.NetCoreApp }) { - new CSharpEditAndContinueTestHelpers().VerifySemantics(editScripts, targetFramework, expected); + new CSharpEditAndContinueTestHelpers().VerifySemantics(editScripts, targetFramework, expected, capabilities); } } } diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 1f189a7c0f65d..63983cb3b77e0 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -9429,6 +9429,19 @@ class C }); } + [Fact] + public void FieldInsert_NotSupportedByRuntime() + { + var src1 = "class C { }"; + var src2 = "class C { public int a = 1; }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "a = 1", "field")); + } + [Fact] public void FieldDelete1() { diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index c904da571a825..529917513d5e6 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -29,6 +29,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { internal abstract class EditAndContinueTestHelpers { + public static readonly ManagedEditAndContinueCapabilities BaselineCapabilities = new(ManagedEditAndContinueCapability.Baseline); public static readonly ManagedEditAndContinueCapabilities Net5RuntimeCapabilities = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition); public abstract AbstractEditAndContinueAnalyzer Analyzer { get; } @@ -145,7 +146,7 @@ internal void VerifyLineEdits( AssertEx.Equal(expectedNodeUpdates, actualNodeUpdates, itemSeparator: ",\r\n"); } - internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults) + internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults, ManagedEditAndContinueCapabilities? capabilities = null) { Assert.True(editScripts.Length == expectedResults.Length); var documentCount = expectedResults.Length; @@ -187,7 +188,7 @@ internal void VerifySemantics(EditScript[] editScripts, TargetFramew Contract.ThrowIfNull(oldModel); Contract.ThrowIfNull(newModel); - var result = Analyzer.AnalyzeDocumentAsync(oldProject, oldActiveStatements, newDocument, newActiveStatementSpans, Net5RuntimeCapabilities, CancellationToken.None).Result; + var result = Analyzer.AnalyzeDocumentAsync(oldProject, oldActiveStatements, newDocument, newActiveStatementSpans, capabilities ?? Net5RuntimeCapabilities, CancellationToken.None).Result; var oldText = oldDocument.GetTextSynchronously(default); var newText = newDocument.GetTextSynchronously(default); diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 3a4f411138ef5..3cc5458371d1c 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -600,6 +600,7 @@ public async Task AnalyzeDocumentAsync( diagnostics, newActiveStatements, newExceptionRegions, + capabilities, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); @@ -2183,6 +2184,7 @@ private async Task> AnalyzeSemanticsAsync( ArrayBuilder diagnostics, ImmutableArray.Builder newActiveStatements, ImmutableArray>.Builder newExceptionRegions, + ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { if (editScript.Edits.Length == 0 && triviaEdits.Count == 0) @@ -2497,6 +2499,15 @@ private async Task> AnalyzeSemanticsAsync( var containingSymbolKey = SymbolKey.Create(newContainingType, cancellationToken); oldContainingType = containingSymbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol as INamedTypeSymbol; + if (oldContainingType != null && !capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) + { + diagnostics.Add(new RudeEditDiagnostic( + RudeEditKind.Insert, + GetDiagnosticSpan(edit.NewNode, EditKind.Insert), + edit.NewNode, + arguments: new[] { GetDisplayName(edit.NewNode, EditKind.Insert) })); + } + // Check rude edits for each member even if it is inserted into a new type. ReportInsertedMemberSymbolRudeEdits(diagnostics, newSymbol, edit.NewNode, insertingIntoExistingContainingType: oldContainingType != null); From d1b0657871176cc9f7a70e52186dbdd89e289d8e Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 19 Apr 2021 09:46:37 +1000 Subject: [PATCH 11/32] Fix default set so tests pass --- .../ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs index 959882094eb90..f1c861644d18a 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs @@ -15,7 +15,7 @@ internal static class ManagedEditAndContinueDebuggerServiceExtensions_REMOVE /// public static ValueTask GetCapabilitiesAsync(this IManagedEditAndContinueDebuggerService _1, CancellationToken _2) { - return new ValueTask("Baseline"); + return new ValueTask("Baseline AddDefinitionToExistingType NewTypeDefinition"); } } } From b3d7bcfe524f25e5e90e6917a7ec17f80fa38c2d Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 19 Apr 2021 10:00:17 +1000 Subject: [PATCH 12/32] Add a couple more tests --- .../EditAndContinue/TopLevelEditingTests.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 63983cb3b77e0..6734375b7b789 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -4118,6 +4118,19 @@ class C Diagnostic(RudeEditKind.Delete, "class C", DeletedSymbolDisplay(FeaturesResources.method, "puts(string)"))); } + [Fact] + public void MethodInsert_NotSupportedByRuntime() + { + var src1 = "class C { }"; + var src2 = "class C { void goo() { } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "void goo()", "method")); + } + [Fact] public void PrivateMethodInsert() { @@ -9907,6 +9920,19 @@ public void PropertyInsert() SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C").GetMember("P"))); } + [Fact] + public void PropertyInsert_NotSupportedByRuntime() + { + var src1 = "class C { }"; + var src2 = "class C { int P { get => 1; set { } } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "int P", "auto-property")); + } + [WorkItem(835827, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/835827")] [Fact] public void PropertyInsert_PInvoke() From 92e9d43a4802eaa3e44e69a2e2962f3fba2e95cd Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 19 Apr 2021 10:27:19 +1000 Subject: [PATCH 13/32] Report rude edit if runtime doesn't support edit and continue baseline --- .../CSharpEditAndContinueAnalyzerTests.cs | 40 +++++++++++++++++++ .../AbstractEditAndContinueAnalyzer.cs | 7 ++++ .../EditAndContinueDiagnosticDescriptors.cs | 2 + .../Portable/EditAndContinue/RudeEditKind.cs | 2 + .../Core/Portable/FeaturesResources.resx | 3 ++ .../Portable/xlf/FeaturesResources.cs.xlf | 5 +++ .../Portable/xlf/FeaturesResources.de.xlf | 5 +++ .../Portable/xlf/FeaturesResources.es.xlf | 5 +++ .../Portable/xlf/FeaturesResources.fr.xlf | 5 +++ .../Portable/xlf/FeaturesResources.it.xlf | 5 +++ .../Portable/xlf/FeaturesResources.ja.xlf | 5 +++ .../Portable/xlf/FeaturesResources.ko.xlf | 5 +++ .../Portable/xlf/FeaturesResources.pl.xlf | 5 +++ .../Portable/xlf/FeaturesResources.pt-BR.xlf | 5 +++ .../Portable/xlf/FeaturesResources.ru.xlf | 5 +++ .../Portable/xlf/FeaturesResources.tr.xlf | 5 +++ .../xlf/FeaturesResources.zh-Hans.xlf | 5 +++ .../xlf/FeaturesResources.zh-Hant.xlf | 5 +++ 18 files changed, 119 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index d0f6fab91a745..aa3510d58e50f 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -759,5 +759,45 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) AssertEx.Equal(new[] { expectedDiagnostic }, result.RudeEditErrors.Select(d => d.ToDiagnostic(newSyntaxTree)) .Select(d => $"{d.Id}: {d.GetMessage().Split(new[] { Environment.NewLine }, StringSplitOptions.None).First()}")); } + + [Fact] + public async Task AnalyzeDocumentAsync_NotSupportedByRuntime() + { + var source1 = @" +class C +{ + public static void Main() + { + System.Console.WriteLine(1); + } +} +"; + var source2 = @" +class C +{ + public static void Main() + { + System.Console.WriteLine(2); + } +} +"; + + using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); + + var oldSolution = workspace.CurrentSolution; + var oldProject = oldSolution.Projects.Single(); + var documentId = oldProject.Documents.Single().Id; + var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); + var newDocument = newSolution.GetDocument(documentId); + + var baseActiveStatements = ImmutableArray.Create(); + var analyzer = new CSharpEditAndContinueAnalyzer(); + + var capabilities = new ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability.None); + + var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, capabilities, CancellationToken.None); + + Assert.Equal(RudeEditKind.NotSupportedByRuntime, result.RudeEditErrors.Single().Kind); + } } } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 3cc5458371d1c..351b0767228bd 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -524,6 +524,13 @@ public async Task AnalyzeDocumentAsync( return DocumentAnalysisResults.Unchanged(newDocument.Id, newActiveStatements.MoveToImmutable(), newExceptionRegions.MoveToImmutable()); } + // If the document has changed at all, lets make sure Edit and Continue is supported + if (!capabilities.HasCapability(ManagedEditAndContinueCapability.Baseline)) + { + return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Create( + new RudeEditDiagnostic(RudeEditKind.NotSupportedByRuntime, default)), hasChanges); + } + // Disallow modification of a file with experimental features enabled. // These features may not be handled well by the analysis below. if (ExperimentalFeaturesEnabled(newTree)) diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index f8758d63b9399..09f578924b9af 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -145,6 +145,8 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.SourceFileTooBig, nameof(FeaturesResources.Modifying_source_file_will_prevent_the_debug_session_from_continuing_because_the_file_is_too_big)); AddRudeEdit(RudeEditKind.InsertIntoGenericType, nameof(FeaturesResources.Adding_0_into_a_generic_type_will_prevent_the_debug_session_from_continuing)); + AddRudeEdit(RudeEditKind.NotSupportedByRuntime, nameof(FeaturesResources.Edit_and_continue_is_not_supported_by_the_runtime)); + // VB specific AddRudeEdit(RudeEditKind.HandlesClauseUpdate, nameof(FeaturesResources.Updating_the_Handles_clause_of_0_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.ImplementsClauseUpdate, nameof(FeaturesResources.Updating_the_Implements_clause_of_a_0_will_prevent_the_debug_session_from_continuing)); diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index c8a5d18c294ad..d084cbdc9c778 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -117,5 +117,7 @@ internal enum RudeEditKind : ushort SourceFileTooBig = 89, MemberBodyTooBig = 90, InsertIntoGenericType = 91, + + NotSupportedByRuntime = 92 } } diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index 5a8e15f7e424c..282860eade64a 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -2840,4 +2840,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Convert to record + + Edit and continue is not supported by the runtime. + \ No newline at end of file diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 3676f4c6da9db..e8848c0dad1d0 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -335,6 +335,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Změny provedené v projektu {0} znemožní relaci ladění pokračovat dále: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Při čtení souboru {0} došlo k chybě: {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 43d654a8f85a7..1cca01e4377b3 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -335,6 +335,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Die im Projekt "{0}" vorgenommenen Änderungen verhindern, dass die Debugsitzung fortgesetzt wird: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Fehler beim Lesen der Datei "{0}": {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index ccdae4720dfb6..ceb70cd183adb 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -335,6 +335,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Los cambios realizados en el proyecto "{0}" impedirán que continúe la sesión de depuración: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Error al leer el archivo "{0}": {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index fa306e3947455..9a3b2a2d3170d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -335,6 +335,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Les changements apportés au projet '{0}' empêchent la session de débogage de se poursuivre : {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Erreur durant la lecture du fichier '{0}' : {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 0b536a2a25cd9..43345f834892c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -335,6 +335,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Le modifiche apportate al progetto '{0}' impediranno la continuazione della sessione di debug: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Si è verificato un errore durante la lettura del file '{0}': {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 8b5db864298a7..fba83e92f4dfa 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -335,6 +335,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma プロジェクト '{0}' で変更を行うと、デバッグ セッションは続行されません。{1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} ファイル {0}' の読み取り中にエラーが発生しました: {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 8fc98c488b435..de1e2ca2254f9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -335,6 +335,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma '{0}' 프로젝트에서 수행한 변경으로 디버그 세션을 계속할 수 없습니다. {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} '{0}' 파일을 읽는 동안 오류가 발생했습니다. {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index c21b2d32b3247..591ff175e3834 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -335,6 +335,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zmiany wprowadzone w projekcie „{0}” uniemożliwią kontynuowanie sesji debugowania: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Błąd podczas odczytywania pliku „{0}”: {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index bb8dba590143d..0eb01d19b6b3a 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -335,6 +335,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess As alterações feitas no projeto '{0}' impedirão que a sessão de depuração continue: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Erro ao ler o arquivo '{0}': {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 274ccab78e18b..675ee714e2d91 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -335,6 +335,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Изменения, внесенные в проект "{0}", препятствуют продолжению сеанса отладки: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} Ошибка при чтении файла "{0}": {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index a99efc879c47c..f17b1d8b4990b 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -335,6 +335,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be '{0}' projesinde yapılan değişiklikler hata ayıklama oturumunun devam etmesini engelleyecek: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} '{0}' dosyası okunurken hata: {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index a8f054401a3d2..db0259fef32c6 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -335,6 +335,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 在项目“{0}”中所作的更改将阻止调试会话继续: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} 读取文件“{0}”时出错: {1} diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 141787394ee24..3ed861b3a481e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -335,6 +335,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 在專案 '{0}' 中所做的變更將使偵錯工作階段無法繼續: {1} + + Edit and continue is not supported by the runtime. + Edit and continue is not supported by the runtime. + + Error while reading file '{0}': {1} 讀取檔案 '{0}' 時發生錯誤: {1} From ddb3c3e1a0aca126235ed358385971ddfb826bdf Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 19 Apr 2021 10:51:19 +1000 Subject: [PATCH 14/32] Rude edit for adding a new type --- .../EditAndContinue/TopLevelEditingTests.cs | 31 +++++++++++++++++++ .../AbstractEditAndContinueAnalyzer.cs | 9 ++++++ 2 files changed, 40 insertions(+) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 6734375b7b789..e1cb97fa4ee83 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -1018,6 +1018,37 @@ public override void H() {} edits.VerifyRudeDiagnostics(); } + [Fact] + public void ClassInsert_NotSupportedByRuntime() + { + var src1 = @" +public class C +{ + void F() + { + } +}"; + var src2 = @" +public class C +{ + void F() + { + } +} + +public class D +{ + void M() + { + } +}"; + + var edits = GetTopEdits(src1, src2); + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "public class D", "class")); + } + [Fact] public void InterfaceInsert() { diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 351b0767228bd..99ce50d6f5bab 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2535,6 +2535,15 @@ private async Task> AnalyzeSemanticsAsync( // adds a new top-level type Contract.ThrowIfFalse(newSymbol is INamedTypeSymbol); + if (!capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition)) + { + diagnostics.Add(new RudeEditDiagnostic( + RudeEditKind.Insert, + GetDiagnosticSpan(edit.NewNode, EditKind.Insert), + edit.NewNode, + arguments: new[] { GetDisplayName(edit.NewNode, EditKind.Insert) })); + } + oldContainingType = null; ReportInsertedMemberSymbolRudeEdits(diagnostics, newSymbol, edit.NewNode, insertingIntoExistingContainingType: false); } From 5a5ae34539ef85207e28868f2eb384ed9652aa14 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 19 Apr 2021 13:59:04 +1000 Subject: [PATCH 15/32] More rude edits for more things that might not be supported --- .../EditAndContinue/StatementEditingTests.cs | 100 ++++++++++++++++++ .../EditAndContinue/TopLevelEditingTests.cs | 39 +++++++ .../AbstractEditAndContinueAnalyzer.cs | 27 +++++ .../EditAndContinueDiagnosticDescriptors.cs | 2 + .../Portable/EditAndContinue/RudeEditKind.cs | 4 +- .../Core/Portable/FeaturesResources.resx | 6 ++ .../Portable/xlf/FeaturesResources.cs.xlf | 10 ++ .../Portable/xlf/FeaturesResources.de.xlf | 10 ++ .../Portable/xlf/FeaturesResources.es.xlf | 10 ++ .../Portable/xlf/FeaturesResources.fr.xlf | 10 ++ .../Portable/xlf/FeaturesResources.it.xlf | 10 ++ .../Portable/xlf/FeaturesResources.ja.xlf | 10 ++ .../Portable/xlf/FeaturesResources.ko.xlf | 10 ++ .../Portable/xlf/FeaturesResources.pl.xlf | 10 ++ .../Portable/xlf/FeaturesResources.pt-BR.xlf | 10 ++ .../Portable/xlf/FeaturesResources.ru.xlf | 10 ++ .../Portable/xlf/FeaturesResources.tr.xlf | 10 ++ .../xlf/FeaturesResources.zh-Hans.xlf | 10 ++ .../xlf/FeaturesResources.zh-Hant.xlf | 10 ++ 19 files changed, 307 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index a68572a77607f..6cf755b93da57 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -2626,6 +2626,72 @@ static void F() ); } + [Fact] + public void Lambdas_Insert_NotSupported() + { + var src1 = @" +using System; + +class C +{ + void F() + { + } +} +"; + var src2 = @" +using System; + +class C +{ + void F() + { + var f = new Func(a => a); + } +} +"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + activeStatements: ActiveStatementsDescription.Empty, + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "a", "lambda")); + } + + [Fact] + public void Lambdas_Insert_Second_NotSupported() + { + var src1 = @" +using System; + +class C +{ + void F() + { + var f = new Func(a => a); + } +} +"; + var src2 = @" +using System; + +class C +{ + void F() + { + var f = new Func(a => a); + var g = new Func(b => b); + } +} +"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + activeStatements: ActiveStatementsDescription.Empty, + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "a", "lambda")); + } + [Fact] public void Lambdas_Update_CeaseCapture_This() { @@ -5484,6 +5550,40 @@ static void F() Diagnostic(RudeEditKind.InsertLambdaWithMultiScopeCapture, "x1", CSharpFeaturesResources.local_function, "x0", "x1")); } + [Fact] + public void LocalFunctions_Insert_NotSupported() + { + var src1 = @" +using System; + +class C +{ + void F() + { + } +} +"; + var src2 = @" +using System; + +class C +{ + void F() + { + void M() + { + } + } +} +"; + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + activeStatements: ActiveStatementsDescription.Empty, + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.Insert, "M", "local function")); + } + [Fact, WorkItem(21499, "https://github.com/dotnet/roslyn/issues/21499")] public void LocalFunctions_Update_CeaseCapture_This() { diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index c3dfbaa00a659..0e1ea57faa6f2 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -5649,6 +5649,32 @@ public async Task WaitAsync() VerifyPreserveLocalVariables(edits, preserveLocalVariables: false); } + [Fact] + public void MethodUpdate_Modifier_Async_Add_NotSupported() + { + var src1 = @" +class Test +{ + public Task WaitAsync() + { + return 1; + } +}"; + var src2 = @" +class Test +{ + public async Task WaitAsync() + { + await Task.Delay(1000); + return 1; + } +}"; + var edits = GetTopEdits(src1, src2); + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.MakeMethodAsync, "public async Task WaitAsync()")); + } + [Fact] public void MethodUpdate_AsyncMethod0() { @@ -6392,6 +6418,19 @@ public void MethodUpdate_AddYieldReturn() VerifyPreserveLocalVariables(edits, preserveLocalVariables: false); } + [Fact] + public void MethodUpdate_AddYieldReturn_NotSupported() + { + var src1 = "class C { IEnumerable M() { return new[] { 1, 2, 3}; } }"; + var src2 = "class C { IEnumerable M() { yield return 2; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + Diagnostic(RudeEditKind.MakeMethodIterator, "IEnumerable M()")); + } + [Fact] public void MethodUpdate_Iterator_YieldBreak() { diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index eaaf7e51cca87..fc8a271690b6c 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -913,6 +913,7 @@ private void AnalyzeChangedMemberBody( ISymbol newSymbol, ImmutableArray oldActiveStatements, ImmutableArray newActiveStatementSpans, + ManagedEditAndContinueCapabilities capabilities, [Out] ImmutableArray.Builder newActiveStatements, [Out] ImmutableArray>.Builder newExceptionRegions, [Out] ArrayBuilder diagnostics, @@ -1017,6 +1018,20 @@ private void AnalyzeChangedMemberBody( { ReportStateMachineRudeEdits(oldModel.Compilation, oldSymbol, newBody, diagnostics); } + else if (newHasStateMachineSuspensionPoint && + !capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition)) + { + // Adding a state machine, either for async or iterator, will require creating a new helper class + // so is a rude edit if the runtime doesn't support it + if (newSymbol is IMethodSymbol { IsAsync: true }) + { + diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.MakeMethodAsync, GetDiagnosticSpan(newDeclaration, EditKind.Insert))); + } + else + { + diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.MakeMethodIterator, GetDiagnosticSpan(newDeclaration, EditKind.Insert))); + } + } ReportLambdaAndClosureRudeEdits( oldModel, @@ -1026,6 +1041,7 @@ private void AnalyzeChangedMemberBody( newSymbol, lazyActiveOrMatchedLambdas, map, + capabilities, diagnostics, out var newBodyHasLambdas, cancellationToken); @@ -2537,6 +2553,7 @@ private async Task> AnalyzeSemanticsAsync( newSymbol, oldActiveStatements: ImmutableArray.Empty, newActiveStatementSpans: ImmutableArray.Empty, + capabilities: capabilities, newActiveStatements, newExceptionRegions, diagnostics, @@ -2702,6 +2719,7 @@ private async Task> AnalyzeSemanticsAsync( newSymbol, oldActiveStatements, newActiveStatementSpans, + capabilities, newActiveStatements, newExceptionRegions, diagnostics, @@ -3383,6 +3401,7 @@ private void ReportLambdaAndClosureRudeEdits( ISymbol newMember, IReadOnlyDictionary? matchedLambdas, BidirectionalMap map, + ManagedEditAndContinueCapabilities capabilities, ArrayBuilder diagnostics, out bool syntaxMapRequired, CancellationToken cancellationToken) @@ -3576,6 +3595,14 @@ select clausesByQuery.First()) { if (!map.Reverse.ContainsKey(newLambda)) { + if ((IsLocalFunction(newLambda) && !capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) || + (!IsLocalFunction(newLambda) && !capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition))) + { + // New local functions mean new methods in existing classes, so need to make sure the runtime supports that + // New lambdas mean creating new helper classes, so need to make sure the runtime supports that + diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.Insert, GetDiagnosticSpan(newLambda, EditKind.Insert), newLambda, new string[] { GetDisplayName(newLambda, EditKind.Insert) })); + } + // TODO: https://github.com/dotnet/roslyn/issues/37128 // Local functions are emitted directly to the type containing the containing method. // Although local functions are non-virtual the Core CLR currently does not support adding any method to an interface. diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index efd8efd1c64a0..c37dd7f98dc40 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -152,6 +152,8 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.ExplicitRecordMethodParameterNamesMustMatch, nameof(FeaturesResources.Explicitly_implemented_methods_of_records_must_have_parameter_names_that_match_the_compiler_generated_equivalent_0)); AddRudeEdit(RudeEditKind.NotSupportedByRuntime, nameof(FeaturesResources.Edit_and_continue_is_not_supported_by_the_runtime)); + AddRudeEdit(RudeEditKind.MakeMethodAsync, nameof(FeaturesResources.Making_a_method_async_will_prevent_the_debug_session_from_continuing)); + AddRudeEdit(RudeEditKind.MakeMethodIterator, nameof(FeaturesResources.Making_a_method_an_iterator_will_prevent_the_debug_session_from_continuing)); // VB specific AddRudeEdit(RudeEditKind.HandlesClauseUpdate, nameof(FeaturesResources.Updating_the_Handles_clause_of_0_will_prevent_the_debug_session_from_continuing)); diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index d701838e5eabe..90cb8d991a561 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -124,6 +124,8 @@ internal enum RudeEditKind : ushort DeleteRecordPositionalParameter = 95, ExplicitRecordMethodParameterNamesMustMatch = 96, - NotSupportedByRuntime = 97 + NotSupportedByRuntime = 97, + MakeMethodAsync = 98, + MakeMethodIterator = 99 } } diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index b154e9df34c82..0832da9dc11e4 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -2858,4 +2858,10 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Edit and continue is not supported by the runtime. + + Making a method an iterator will prevent the debug session from continuing. + + + Making a method 'async' will prevent the debug session from continuing. + \ No newline at end of file diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index a42c10f53963b..16890fcc2c495 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -605,6 +605,16 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Převrátit podmínku + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed chybný formát diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index c7ff882c78e7c..0ca26dd36d72f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -605,6 +605,16 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Bedingten Operator umkehren + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed fehlerhaft diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 5769a736f1dbc..c4eeaf6516511 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -605,6 +605,16 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Invertir condicional + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed con formato incorrecto diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index a6103aa10dd29..9f9c99607e1e2 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -605,6 +605,16 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Inverser un élément conditionnel + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed incorrecte diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index dabb510d5dd6a..6a5ad3d2bf151 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -605,6 +605,16 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Inverti espressione condizionale + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed non valido diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 8b83dfd1c71e2..efcd55f9b7328 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -605,6 +605,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 条件を反転します + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed 不正な形式 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index eef5e154daace..fc0630fe3ccf2 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -605,6 +605,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 조건 반전 + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed 형식이 잘못되었습니다. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 56485885a3177..c161f6f5a3f00 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -605,6 +605,16 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Odwróć warunkowe + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed źle sformułowane diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 2e2a1abdc3a18..ee3e3b4a0da9d 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -605,6 +605,16 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Inverter condicional + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed malformado diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index ae1a2edef6fce..110471324c20b 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -605,6 +605,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Инвертировать условный оператор + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed Ошибка в регулярном выражении diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 3a88e4df1a54d..77c6b65e49ab8 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -605,6 +605,16 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Koşullu öğeyi ters çevir + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed Hatalı biçimlendirilmiş diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 277449e831382..bd6bbf4927eb2 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -605,6 +605,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 反转条件 + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed 格式错误 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index d6bc3d45ee0cd..af78b544ba084 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -605,6 +605,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 反轉條件 + + Making a method an iterator will prevent the debug session from continuing. + Making a method an iterator will prevent the debug session from continuing. + + + + Making a method 'async' will prevent the debug session from continuing. + Making a method 'async' will prevent the debug session from continuing. + + malformed 語式錯誤 From 91d73cb9b4729bbbd76fd29217fa7bbe33710487 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 20 Apr 2021 07:53:21 +1000 Subject: [PATCH 16/32] Fix test --- .../CSharpTest/EditAndContinue/StatementEditingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index 6cf755b93da57..447e9da545971 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -2689,7 +2689,7 @@ void F() edits.VerifySemanticDiagnostics( activeStatements: ActiveStatementsDescription.Empty, capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "a", "lambda")); + Diagnostic(RudeEditKind.Insert, "b", "lambda")); } [Fact] From efc45e1eec21207bced1719f40cfeb91a8233abd Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 20 Apr 2021 07:59:41 +1000 Subject: [PATCH 17/32] Fix test --- .../Test/EditAndContinue/RudeEditDiagnosticTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs b/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs index 63a037312c79f..f46977f745bb9 100644 --- a/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/RudeEditDiagnosticTests.cs @@ -51,6 +51,9 @@ public void ToDiagnostic() RudeEditKind.InsertMethodWithExplicitInterfaceSpecifier, RudeEditKind.AddRecordPositionalParameter, RudeEditKind.DeleteRecordPositionalParameter, + RudeEditKind.NotSupportedByRuntime, + RudeEditKind.MakeMethodAsync, + RudeEditKind.MakeMethodIterator }; var arg2 = new HashSet() From 51a17ad7adaa7e4adbbd9ab358c8722fd2e4a76b Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 20 Apr 2021 11:06:08 +1000 Subject: [PATCH 18/32] Expand the handling of lambdas --- .../EditAndContinue/StatementEditingTests.cs | 40 ++++++++++++++++++- .../AbstractEditAndContinueAnalyzer.cs | 30 ++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index 447e9da545971..06056f5a0ee3c 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -2684,11 +2684,49 @@ void F() } } "; + var capabilities = new ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition); + var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( activeStatements: ActiveStatementsDescription.Empty, - capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + capabilities, + Diagnostic(RudeEditKind.Insert, "b", "lambda")); + } + + [Fact] + public void Lambdas_Insert_FirstInClass_NotSupported() + { + var src1 = @" +using System; + +class C +{ + void F() + { + } +} +"; + var src2 = @" +using System; + +class C +{ + void F() + { + var g = new Func(b => b); + } +} +"; + var capabilities = new ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition); + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + activeStatements: ActiveStatementsDescription.Empty, + capabilities, + // TODO: https://github.com/dotnet/roslyn/issues/52759 + // This is incorrect, there should be no rude edit reported Diagnostic(RudeEditKind.Insert, "b", "lambda")); } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index fc8a271690b6c..89f78c524b845 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -3595,11 +3595,8 @@ select clausesByQuery.First()) { if (!map.Reverse.ContainsKey(newLambda)) { - if ((IsLocalFunction(newLambda) && !capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) || - (!IsLocalFunction(newLambda) && !capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition))) + if (!CanAddNewLambda(newLambda, capabilities, matchedLambdas)) { - // New local functions mean new methods in existing classes, so need to make sure the runtime supports that - // New lambdas mean creating new helper classes, so need to make sure the runtime supports that diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.Insert, GetDiagnosticSpan(newLambda, EditKind.Insert), newLambda, new string[] { GetDisplayName(newLambda, EditKind.Insert) })); } @@ -3643,6 +3640,31 @@ select clausesByQuery.First()) oldCapturesToClosureScopes.Free(); } + private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapabilities capabilities, IReadOnlyDictionary? matchedLambdas) + { + // New local functions mean new methods in existing classes + if (IsLocalFunction(newLambda)) + { + return capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + } + + // New lambdas sometimes mean creating new helper classes, and sometimes mean new methods in exising helper classes + // Unfortunately we are limited here in what we can do here. See: https://github.com/dotnet/roslyn/issues/52759 + + // If there is already a lambda in the method then the new lambda would result in a new method in the existing helper class. + // This check is redundant with the below, once the limitation in the referenced issue is resolved + if (matchedLambdas is { Count: > 0 }) + { + return capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + } + + // If there is already a lambda in the class then the new lambda would result in a new method in the existing helper class. + // If there isn't already a lambda in the class then the new lambda would result in a new helper class. + // Unfortunately right now we can't determine which of these is true so we have to just check both capabilities instead. + return capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition) && + capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + } + private void ReportMultiScopeCaptures( SyntaxNode lambdaBody, SemanticModel model, From cd8970377c7d45a3b95af605508ca5ca6e4926ac Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 20 Apr 2021 12:05:21 +1000 Subject: [PATCH 19/32] Fix Spanish tests --- .../CSharpTest/EditAndContinue/StatementEditingTests.cs | 2 +- .../CSharpTest/EditAndContinue/TopLevelEditingTests.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index 06056f5a0ee3c..36298b9161efb 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -5619,7 +5619,7 @@ void M() edits.VerifySemanticDiagnostics( activeStatements: ActiveStatementsDescription.Empty, capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "M", "local function")); + Diagnostic(RudeEditKind.Insert, "M", FeaturesResources.local_function)); } [Fact, WorkItem(21499, "https://github.com/dotnet/roslyn/issues/21499")] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 0e1ea57faa6f2..ee58f9784a9eb 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -5132,7 +5132,7 @@ public void MethodInsert_NotSupportedByRuntime() edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "void goo()", "method")); + Diagnostic(RudeEditKind.Insert, "void goo()", FeaturesResources.method)); } [Fact] @@ -10517,7 +10517,7 @@ public void FieldInsert_NotSupportedByRuntime() edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "a = 1", "field")); + Diagnostic(RudeEditKind.Insert, "a = 1", FeaturesResources.field)); } [Fact] @@ -11007,7 +11007,7 @@ public void PropertyInsert_NotSupportedByRuntime() edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "int P", "auto-property")); + Diagnostic(RudeEditKind.Insert, "int P", FeaturesResources.auto_property)); } [WorkItem(835827, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/835827")] From ba85d7d234fecd88feeb5902e6734f7053076e59 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 09:50:25 +1000 Subject: [PATCH 20/32] Localize --- .../CSharpTest/EditAndContinue/TopLevelEditingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index ee58f9784a9eb..526f9b70eceb5 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -1062,7 +1062,7 @@ void M() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "public class D", "class")); + Diagnostic(RudeEditKind.Insert, "public class D", FeaturesResources.class_)); } [Fact] From 35bcbd3ac49ef494e25a248370f3202a557ced5e Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 10:41:59 +1000 Subject: [PATCH 21/32] Remove helper class in favour of direct enum usage --- .../CSharpEditAndContinueAnalyzerTests.cs | 2 +- .../Helpers/EditAndContinueValidation.cs | 8 ++-- .../EditAndContinue/StatementEditingTests.cs | 4 +- ...ManagedEditAndContinueCapabilitiesTests.cs | 34 +++++++------- .../EditAndContinueTestHelpers.cs | 6 +-- .../AbstractEditAndContinueAnalyzer.cs | 26 +++++------ .../EditAndContinue/DebuggingSession.cs | 6 +-- .../EditAndContinueDocumentAnalysesCache.cs | 8 ++-- .../EditAndContinueWorkspaceService.cs | 25 +++++++++- .../IEditAndContinueAnalyzer.cs | 2 +- .../ManagedEditAndContinueCapabilities.cs | 46 ------------------- 11 files changed, 72 insertions(+), 95 deletions(-) delete mode 100644 src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index a3e58cc137f7b..2d03454f05eb7 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -796,7 +796,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var capabilities = new ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability.None); + var capabilities = ManagedEditAndContinueCapability.None; var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, capabilities, CancellationToken.None); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs index ec0ea59496798..2c75c6ad93b87 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs @@ -41,7 +41,7 @@ internal static void VerifyRudeDiagnostics( internal static void VerifyRudeDiagnostics( this EditScript editScript, - ManagedEditAndContinueCapabilities? capabilities = null, + ManagedEditAndContinueCapability? capabilities = null, params RudeEditDiagnosticDescription[] expectedDiagnostics) { VerifySemanticDiagnostics( @@ -96,7 +96,7 @@ internal static void VerifySemanticDiagnostics( internal static void VerifySemanticDiagnostics( this EditScript editScript, ActiveStatementsDescription activeStatements, - ManagedEditAndContinueCapabilities? capabilities = null, + ManagedEditAndContinueCapability? capabilities = null, params RudeEditDiagnosticDescription[] expectedDiagnostics) { VerifySemantics( @@ -120,7 +120,7 @@ internal static void VerifySemantics( this EditScript editScript, ActiveStatementsDescription activeStatements, SemanticEditDescription[] expectedSemanticEdits, - ManagedEditAndContinueCapabilities? capabilities = null) + ManagedEditAndContinueCapability? capabilities = null) { VerifySemantics( new[] { editScript }, @@ -139,7 +139,7 @@ internal static void VerifySemantics( EditScript[] editScripts, DocumentAnalysisResultsDescription[] expected, TargetFramework[]? targetFrameworks = null, - ManagedEditAndContinueCapabilities? capabilities = null) + ManagedEditAndContinueCapability? capabilities = null) { foreach (var targetFramework in targetFrameworks ?? new[] { TargetFramework.NetStandard20, TargetFramework.NetCoreApp }) { diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index 36298b9161efb..ad2773136bbfb 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -2684,7 +2684,7 @@ void F() } } "; - var capabilities = new ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition); + var capabilities = ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition; var edits = GetTopEdits(src1, src2); @@ -2718,7 +2718,7 @@ void F() } } "; - var capabilities = new ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition); + var capabilities = ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition; var edits = GetTopEdits(src1, src2); diff --git a/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs b/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs index 244afcbd7b182..f17a29b09e651 100644 --- a/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs @@ -13,10 +13,10 @@ public void Parse() { var capabilities = "Baseline"; - var service = new ManagedEditAndContinueCapabilities(capabilities); + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); - Assert.False(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.False(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); } [Fact] @@ -24,9 +24,9 @@ public void Parse_CaseSensitive() { var capabilities = "BaseLine"; - var service = new ManagedEditAndContinueCapabilities(capabilities); + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.False(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); + Assert.False(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); } [Fact] @@ -34,10 +34,10 @@ public void Parse_IgnoreInvalid() { var capabilities = "Baseline Invalid RuntimeEdits"; - var service = new ManagedEditAndContinueCapabilities(capabilities); + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); } [Fact] @@ -45,10 +45,10 @@ public void Parse_IgnoreInvalidNumeric() { var capabilities = "Baseline 90 RuntimeEdits"; - var service = new ManagedEditAndContinueCapabilities(capabilities); + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); } [Fact] @@ -56,20 +56,20 @@ public void Parse_MultipleSpaces() { var capabilities = " Baseline RuntimeEdits "; - var service = new ManagedEditAndContinueCapabilities(capabilities); + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasCapability(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); } [Fact] - public void HasCapability_IgnoreInvalid() + public void HasFlag_IgnoreInvalid() { var capabilities = "Baseline"; - var service = new ManagedEditAndContinueCapabilities(capabilities); + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.False(service.HasCapability((ManagedEditAndContinueCapability)999)); + Assert.False(service.HasFlag((ManagedEditAndContinueCapability)999)); } } } diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index 529917513d5e6..0c4cfb33271a4 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -29,8 +29,8 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { internal abstract class EditAndContinueTestHelpers { - public static readonly ManagedEditAndContinueCapabilities BaselineCapabilities = new(ManagedEditAndContinueCapability.Baseline); - public static readonly ManagedEditAndContinueCapabilities Net5RuntimeCapabilities = new(ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition); + public static readonly ManagedEditAndContinueCapability BaselineCapabilities = ManagedEditAndContinueCapability.Baseline; + public static readonly ManagedEditAndContinueCapability Net5RuntimeCapabilities = ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition; public abstract AbstractEditAndContinueAnalyzer Analyzer { get; } public abstract SyntaxNode FindNode(SyntaxNode root, TextSpan span); @@ -146,7 +146,7 @@ internal void VerifyLineEdits( AssertEx.Equal(expectedNodeUpdates, actualNodeUpdates, itemSeparator: ",\r\n"); } - internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults, ManagedEditAndContinueCapabilities? capabilities = null) + internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults, ManagedEditAndContinueCapability? capabilities = null) { Assert.True(editScripts.Length == expectedResults.Length); var documentCount = expectedResults.Length; diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 89f78c524b845..049dcc13e7e10 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -451,7 +451,7 @@ public async Task AnalyzeDocumentAsync( ImmutableArray oldActiveStatements, Document newDocument, ImmutableArray newActiveStatementSpans, - ManagedEditAndContinueCapabilities capabilities, + ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) { DocumentAnalysisResults.Log.Write("Analyzing document {0}", newDocument.Name); @@ -537,7 +537,7 @@ public async Task AnalyzeDocumentAsync( } // If the document has changed at all, lets make sure Edit and Continue is supported - if (!capabilities.HasCapability(ManagedEditAndContinueCapability.Baseline)) + if (!capabilities.HasFlag(ManagedEditAndContinueCapability.Baseline)) { return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Create( new RudeEditDiagnostic(RudeEditKind.NotSupportedByRuntime, default)), hasChanges); @@ -913,7 +913,7 @@ private void AnalyzeChangedMemberBody( ISymbol newSymbol, ImmutableArray oldActiveStatements, ImmutableArray newActiveStatementSpans, - ManagedEditAndContinueCapabilities capabilities, + ManagedEditAndContinueCapability capabilities, [Out] ImmutableArray.Builder newActiveStatements, [Out] ImmutableArray>.Builder newExceptionRegions, [Out] ArrayBuilder diagnostics, @@ -1019,7 +1019,7 @@ private void AnalyzeChangedMemberBody( ReportStateMachineRudeEdits(oldModel.Compilation, oldSymbol, newBody, diagnostics); } else if (newHasStateMachineSuspensionPoint && - !capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition)) + !capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)) { // Adding a state machine, either for async or iterator, will require creating a new helper class // so is a rude edit if the runtime doesn't support it @@ -2219,7 +2219,7 @@ private async Task> AnalyzeSemanticsAsync( ArrayBuilder diagnostics, ImmutableArray.Builder newActiveStatements, ImmutableArray>.Builder newExceptionRegions, - ManagedEditAndContinueCapabilities capabilities, + ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) { if (editScript.Edits.Length == 0 && triviaEdits.Count == 0) @@ -2594,7 +2594,7 @@ private async Task> AnalyzeSemanticsAsync( var containingSymbolKey = SymbolKey.Create(newContainingType, cancellationToken); oldContainingType = containingSymbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol as INamedTypeSymbol; - if (oldContainingType != null && !capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) + if (oldContainingType != null && !capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) { diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.Insert, @@ -2633,7 +2633,7 @@ private async Task> AnalyzeSemanticsAsync( // adds a new top-level type Contract.ThrowIfFalse(newSymbol is INamedTypeSymbol); - if (!capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition)) + if (!capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)) { diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.Insert, @@ -3401,7 +3401,7 @@ private void ReportLambdaAndClosureRudeEdits( ISymbol newMember, IReadOnlyDictionary? matchedLambdas, BidirectionalMap map, - ManagedEditAndContinueCapabilities capabilities, + ManagedEditAndContinueCapability capabilities, ArrayBuilder diagnostics, out bool syntaxMapRequired, CancellationToken cancellationToken) @@ -3640,12 +3640,12 @@ select clausesByQuery.First()) oldCapturesToClosureScopes.Free(); } - private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapabilities capabilities, IReadOnlyDictionary? matchedLambdas) + private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapability capabilities, IReadOnlyDictionary? matchedLambdas) { // New local functions mean new methods in existing classes if (IsLocalFunction(newLambda)) { - return capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType); } // New lambdas sometimes mean creating new helper classes, and sometimes mean new methods in exising helper classes @@ -3655,14 +3655,14 @@ private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapabil // This check is redundant with the below, once the limitation in the referenced issue is resolved if (matchedLambdas is { Count: > 0 }) { - return capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType); } // If there is already a lambda in the class then the new lambda would result in a new method in the existing helper class. // If there isn't already a lambda in the class then the new lambda would result in a new helper class. // Unfortunately right now we can't determine which of these is true so we have to just check both capabilities instead. - return capabilities.HasCapability(ManagedEditAndContinueCapability.NewTypeDefinition) && - capabilities.HasCapability(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + return capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition) && + capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType); } private void ReportMultiScopeCaptures( diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 5db988460ee61..9c268f27daa4d 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -98,13 +98,13 @@ internal sealed class DebuggingSession : IDisposable internal readonly IManagedEditAndContinueDebuggerService DebuggerService; private readonly DebuggingSessionTelemetry _telemetry; - private readonly ManagedEditAndContinueCapabilities _capabilities; + private readonly ManagedEditAndContinueCapability _capabilities; internal EditSession EditSession; internal DebuggingSession( Solution solution, IManagedEditAndContinueDebuggerService debuggerService, - ManagedEditAndContinueCapabilities capabilities, + ManagedEditAndContinueCapability capabilities, Func compilationOutputsProvider, IEnumerable> initialDocumentStates, DebuggingSessionTelemetry debuggingSessionTelemetry, @@ -125,7 +125,7 @@ internal DebuggingSession( /// /// Gets the capabilities of the runtime with respect to applying code changes. /// - internal ManagedEditAndContinueCapabilities Capabilities => _capabilities; + internal ManagedEditAndContinueCapability Capabilities => _capabilities; public void Dispose() { diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs index 9afe23240d5ce..abd24533aec7f 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs @@ -30,7 +30,7 @@ public EditAndContinueDocumentAnalysesCache(AsyncLazy baseA _baseActiveStatements = baseActiveStatements; } - public async ValueTask> GetActiveStatementsAsync(Document baseDocument, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) + public async ValueTask> GetActiveStatementsAsync(Document baseDocument, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) { try { @@ -46,7 +46,7 @@ public async ValueTask> GetActiveStatementsAsync public async ValueTask> GetDocumentAnalysesAsync( Project oldProject, IReadOnlyList<(Document newDocument, ImmutableArray newActiveStatementSpans)> documentInfos, - ManagedEditAndContinueCapabilities capabilities, + ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) { try @@ -73,7 +73,7 @@ public async ValueTask> GetDocumentAnaly /// Base project. /// Document snapshot to analyze. /// Active statement spans tracked by the editor. - public async ValueTask GetDocumentAnalysisAsync(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken) + public async ValueTask GetDocumentAnalysisAsync(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) { try { @@ -92,7 +92,7 @@ public async ValueTask GetDocumentAnalysisAsync(Project } } - private AsyncLazy GetDocumentAnalysisNoLock(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapabilities capabilities) + private AsyncLazy GetDocumentAnalysisNoLock(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities) { // Do not reuse an analysis of the document unless its snasphot is exactly the same as was used to calculate the results. // Note that comparing document snapshots in effect compares the entire solution snapshots (when another document is changed a new solution snapshot is created diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index 2dcce26b4d171..8c268f55a0328 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -86,13 +86,36 @@ public async ValueTask StartDebuggingSessionAsync(Solution solution, IManagedEdi SpecializedCollections.EmptyEnumerable>(); var runtimeCapabilities = await debuggerService.GetCapabilitiesAsync(cancellationToken).ConfigureAwait(false); - var capabilities = new ManagedEditAndContinueCapabilities(runtimeCapabilities); + var capabilities = ParseCapabilities(runtimeCapabilities); var newSession = new DebuggingSession(solution, debuggerService, capabilities, _compilationOutputsProvider, initialDocumentStates, _debuggingSessionTelemetry, _editSessionTelemetry); var previousSession = Interlocked.CompareExchange(ref _debuggingSession, newSession, null); Contract.ThrowIfFalse(previousSession == null, "New debugging session can't be started until the existing one has ended."); } + // internal for testing + internal static ManagedEditAndContinueCapability ParseCapabilities(string? capabilities) + { + var caps = ManagedEditAndContinueCapability.None; + + if (!string.IsNullOrEmpty(capabilities)) + { + foreach (var capability in capabilities.Split(' ')) + { + caps |= capability switch + { + "Baseline" => ManagedEditAndContinueCapability.Baseline, + "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, + "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, + "RuntimeEdits" => ManagedEditAndContinueCapability.RuntimeEdits, + + _ => ManagedEditAndContinueCapability.None + }; + } + } + + return caps; + } public void EndDebuggingSession(out ImmutableArray documentsToReanalyze) { var debuggingSession = Interlocked.Exchange(ref _debuggingSession, null); diff --git a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs index 8196b19ab3fad..6af82c4322b7b 100644 --- a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal interface IEditAndContinueAnalyzer : ILanguageService { - Task AnalyzeDocumentAsync(Project baseProject, ImmutableArray baseActiveStatements, Document document, ImmutableArray newActiveStatementSpans, ManagedEditAndContinueCapabilities capabilities, CancellationToken cancellationToken); + Task AnalyzeDocumentAsync(Project baseProject, ImmutableArray baseActiveStatements, Document document, ImmutableArray newActiveStatementSpans, ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken); ImmutableArray GetExceptionRegions(SourceText text, SyntaxNode syntaxRoot, LinePositionSpan activeStatementSpan, bool isLeaf, out bool isCovered); } } diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs deleted file mode 100644 index 4317592f8527e..0000000000000 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapabilities.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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.EditAndContinue -{ - internal class ManagedEditAndContinueCapabilities - { - private readonly ManagedEditAndContinueCapability _capabilities; - - // For testing purposes - internal ManagedEditAndContinueCapabilities(ManagedEditAndContinueCapability capabilities) - { - _capabilities = capabilities; - } - - internal ManagedEditAndContinueCapabilities(string? capabilities) - { - var caps = ManagedEditAndContinueCapability.None; - - if (!string.IsNullOrEmpty(capabilities)) - { - foreach (var capability in capabilities.Split(' ')) - { - caps |= ParseCapability(capability); - } - } - - _capabilities = caps; - } - - private static ManagedEditAndContinueCapability ParseCapability(string capability) - => capability switch - { - "Baseline" => ManagedEditAndContinueCapability.Baseline, - "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, - "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, - "RuntimeEdits" => ManagedEditAndContinueCapability.RuntimeEdits, - - _ => ManagedEditAndContinueCapability.None - }; - - public bool HasCapability(ManagedEditAndContinueCapability capability) - => (_capabilities & capability) == capability; - } -} From 5491751c8249b41e4d116e167151c13411c66192 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 11:21:48 +1000 Subject: [PATCH 22/32] Move tests --- .../EditAndContinueWorkspaceServiceTests.cs | 54 +++++++++++++ ...ManagedEditAndContinueCapabilitiesTests.cs | 75 ------------------- 2 files changed, 54 insertions(+), 75 deletions(-) delete mode 100644 src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index e84925d301667..40de774d3c388 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -3318,5 +3318,59 @@ public async Task WatchHotReloadServiceTest() hotReload.EndSession(); } + + [Fact] + public void ParseCapabilities() + { + var capabilities = "Baseline"; + + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); + + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.False(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void ParseCapabilities_CaseSensitive() + { + var capabilities = "BaseLine"; + + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); + + Assert.False(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + } + + [Fact] + public void ParseCapabilities_IgnoreInvalid() + { + var capabilities = "Baseline Invalid RuntimeEdits"; + + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); + + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void ParseCapabilities_IgnoreInvalidNumeric() + { + var capabilities = "Baseline 90 RuntimeEdits"; + + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); + + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + } + + [Fact] + public void ParseCapabilities_MultipleSpaces() + { + var capabilities = " Baseline RuntimeEdits "; + + var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); + + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + } } } diff --git a/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs b/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs deleted file mode 100644 index f17a29b09e651..0000000000000 --- a/src/EditorFeatures/Test/EditAndContinue/ManagedEditAndContinueCapabilitiesTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests -{ - public class ManagedEditAndContinueCapabilitiesTests - { - [Fact] - public void Parse() - { - var capabilities = "Baseline"; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.False(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); - } - - [Fact] - public void Parse_CaseSensitive() - { - var capabilities = "BaseLine"; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.False(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - } - - [Fact] - public void Parse_IgnoreInvalid() - { - var capabilities = "Baseline Invalid RuntimeEdits"; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); - } - - [Fact] - public void Parse_IgnoreInvalidNumeric() - { - var capabilities = "Baseline 90 RuntimeEdits"; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); - } - - [Fact] - public void Parse_MultipleSpaces() - { - var capabilities = " Baseline RuntimeEdits "; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); - } - - [Fact] - public void HasFlag_IgnoreInvalid() - { - var capabilities = "Baseline"; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.False(service.HasFlag((ManagedEditAndContinueCapability)999)); - } - } -} From aeb8c0743896dd1aa7fa8ff065fb296db944bcbc Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 11:29:29 +1000 Subject: [PATCH 23/32] Just make the field visible, against every fibre of my training --- .../Portable/EditAndContinue/DebuggingSession.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 9c268f27daa4d..e15001116ac72 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -97,8 +97,12 @@ internal sealed class DebuggingSession : IDisposable internal readonly IManagedEditAndContinueDebuggerService DebuggerService; + /// + /// Gets the capabilities of the runtime with respect to applying code changes. + /// + internal readonly ManagedEditAndContinueCapability Capabilities; + private readonly DebuggingSessionTelemetry _telemetry; - private readonly ManagedEditAndContinueCapability _capabilities; internal EditSession EditSession; internal DebuggingSession( @@ -112,8 +116,8 @@ internal DebuggingSession( { _compilationOutputsProvider = compilationOutputsProvider; _telemetry = debuggingSessionTelemetry; - _capabilities = capabilities; + Capabilities = capabilities; DebuggerService = debuggerService; LastCommittedSolution = new CommittedSolution(this, solution, initialDocumentStates); NonRemappableRegions = ImmutableDictionary>.Empty; @@ -122,11 +126,6 @@ internal DebuggingSession( internal CancellationToken CancellationToken => _cancellationSource.Token; - /// - /// Gets the capabilities of the runtime with respect to applying code changes. - /// - internal ManagedEditAndContinueCapability Capabilities => _capabilities; - public void Dispose() { _cancellationSource.Cancel(); From f244048396a90afd88a9fe5afbb77c992adfec2b Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 11:38:41 +1000 Subject: [PATCH 24/32] Update method signature --- .../EditAndContinueWorkspaceServiceTests.cs | 19 ++++------------- .../EditAndContinueWorkspaceService.cs | 21 ++++++++----------- ...ontinueDebuggerServiceExtensions_REMOVE.cs | 5 +++-- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 40de774d3c388..e6a8eac584b13 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -3322,7 +3322,7 @@ public async Task WatchHotReloadServiceTest() [Fact] public void ParseCapabilities() { - var capabilities = "Baseline"; + var capabilities = ImmutableArray.Create("Baseline"); var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); @@ -3333,7 +3333,7 @@ public void ParseCapabilities() [Fact] public void ParseCapabilities_CaseSensitive() { - var capabilities = "BaseLine"; + var capabilities = ImmutableArray.Create("BaseLine"); var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); @@ -3343,7 +3343,7 @@ public void ParseCapabilities_CaseSensitive() [Fact] public void ParseCapabilities_IgnoreInvalid() { - var capabilities = "Baseline Invalid RuntimeEdits"; + var capabilities = ImmutableArray.Create("Baseline", "Invalid", "RuntimeEdits"); var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); @@ -3354,18 +3354,7 @@ public void ParseCapabilities_IgnoreInvalid() [Fact] public void ParseCapabilities_IgnoreInvalidNumeric() { - var capabilities = "Baseline 90 RuntimeEdits"; - - var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); - } - - [Fact] - public void ParseCapabilities_MultipleSpaces() - { - var capabilities = " Baseline RuntimeEdits "; + var capabilities = ImmutableArray.Create("Baseline", "90", "RuntimeEdits"); var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index 8c268f55a0328..fb00cee922583 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -94,24 +94,21 @@ public async ValueTask StartDebuggingSessionAsync(Solution solution, IManagedEdi } // internal for testing - internal static ManagedEditAndContinueCapability ParseCapabilities(string? capabilities) + internal static ManagedEditAndContinueCapability ParseCapabilities(ImmutableArray capabilities) { var caps = ManagedEditAndContinueCapability.None; - if (!string.IsNullOrEmpty(capabilities)) + foreach (var capability in capabilities) { - foreach (var capability in capabilities.Split(' ')) + caps |= capability switch { - caps |= capability switch - { - "Baseline" => ManagedEditAndContinueCapability.Baseline, - "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, - "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, - "RuntimeEdits" => ManagedEditAndContinueCapability.RuntimeEdits, + "Baseline" => ManagedEditAndContinueCapability.Baseline, + "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, + "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, + "RuntimeEdits" => ManagedEditAndContinueCapability.RuntimeEdits, - _ => ManagedEditAndContinueCapability.None - }; - } + _ => ManagedEditAndContinueCapability.None + }; } return caps; diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs index f1c861644d18a..aa8cfe1b00e6f 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueDebuggerServiceExtensions_REMOVE.cs @@ -2,6 +2,7 @@ // 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.VisualStudio.Debugger.Contracts.EditAndContinue; @@ -13,9 +14,9 @@ internal static class ManagedEditAndContinueDebuggerServiceExtensions_REMOVE /// /// This will be removed when IManagedEditAndContinueDebuggerService gets the method for real /// - public static ValueTask GetCapabilitiesAsync(this IManagedEditAndContinueDebuggerService _1, CancellationToken _2) + public static ValueTask> GetCapabilitiesAsync(this IManagedEditAndContinueDebuggerService _1, CancellationToken _2) { - return new ValueTask("Baseline AddDefinitionToExistingType NewTypeDefinition"); + return new(ImmutableArray.Create("Baseline", "AddDefinitionToExistingType", "NewTypeDefinition")); } } } From 90cf9a971cc595c70b0e49390260874c24d1dc7e Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 11:39:29 +1000 Subject: [PATCH 25/32] Remove RuntimeEdits --- .../EditAndContinueWorkspaceServiceTests.cs | 10 +++++----- .../EditAndContinue/EditAndContinueWorkspaceService.cs | 1 - .../ManagedEditAndContinueCapability.cs | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index e6a8eac584b13..bd6bd533d39ef 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -3327,7 +3327,7 @@ public void ParseCapabilities() var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.False(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.False(service.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)); } [Fact] @@ -3343,23 +3343,23 @@ public void ParseCapabilities_CaseSensitive() [Fact] public void ParseCapabilities_IgnoreInvalid() { - var capabilities = ImmutableArray.Create("Baseline", "Invalid", "RuntimeEdits"); + var capabilities = ImmutableArray.Create("Baseline", "Invalid", "NewTypeDefinition"); var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)); } [Fact] public void ParseCapabilities_IgnoreInvalidNumeric() { - var capabilities = ImmutableArray.Create("Baseline", "90", "RuntimeEdits"); + var capabilities = ImmutableArray.Create("Baseline", "90", "NewTypeDefinition"); var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.RuntimeEdits)); + Assert.True(service.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)); } } } diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index fb00cee922583..d55d3f4b27f8d 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -105,7 +105,6 @@ internal static ManagedEditAndContinueCapability ParseCapabilities(ImmutableArra "Baseline" => ManagedEditAndContinueCapability.Baseline, "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, - "RuntimeEdits" => ManagedEditAndContinueCapability.RuntimeEdits, _ => ManagedEditAndContinueCapability.None }; diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs index 405a2dde5a12a..6a1605ef0d088 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs @@ -17,6 +17,5 @@ internal enum ManagedEditAndContinueCapability Baseline = 1 << 0, AddDefinitionToExistingType = 1 << 1, NewTypeDefinition = 1 << 2, - RuntimeEdits = 1 << 3, } } From 10f94b95d6304d461329b3d23e6fa40af4df02d9 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 11:47:57 +1000 Subject: [PATCH 26/32] Doc --- .../ManagedEditAndContinueCapability.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs index 6a1605ef0d088..3aa5191f6eeda 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs @@ -14,8 +14,19 @@ internal enum ManagedEditAndContinueCapability { None = 0, + /// + /// Edit and continue is generally with the set of capabilities that Mono 6, .NET Framework and .NET 5 have in common. + /// Baseline = 1 << 0, + + /// + /// A new field/property/method definition can be added to an existing type. + /// AddDefinitionToExistingType = 1 << 1, + + /// + /// A new type definition can be created. + /// NewTypeDefinition = 1 << 2, } } From 8105a5e556ef5e13bdd24cfb96f5283382767ab9 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 11:53:05 +1000 Subject: [PATCH 27/32] Cache capabilities --- .../EditAndContinueDocumentAnalysesCache.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs index abd24533aec7f..2992854978b51 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue internal sealed class EditAndContinueDocumentAnalysesCache { private readonly object _guard = new(); - private readonly Dictionary results, Project baseProject, Document document, ImmutableArray activeStatementSpans)> _analyses = new(); + private readonly Dictionary results, Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities)> _analyses = new(); private readonly AsyncLazy _baseActiveStatements; public EditAndContinueDocumentAnalysesCache(AsyncLazy baseActiveStatements) @@ -105,13 +105,11 @@ private AsyncLazy GetDocumentAnalysisNoLock(Project bas // For example, when analyzing a partial class we can record all documents its declaration spans. However, in other cases the analysis // checks for absence of a top-level type symbol. Adding a symbol to any document thus invalidates such analysis. It'd be possible // to keep track of which type symbols an analysis is conditional upon, if it was worth the extra complexity. - // - // Note that this doesn't check the runtime capabilities on the asusmption that they can't change without at least a project change, - // though possibly they can't change at all. if (_analyses.TryGetValue(document.Id, out var analysis) && analysis.baseProject == baseProject && analysis.document == document && - analysis.activeStatementSpans.SequenceEqual(activeStatementSpans)) + analysis.activeStatementSpans.SequenceEqual(activeStatementSpans) && + analysis.capabilities == capabilities) { return analysis.results; } @@ -142,7 +140,7 @@ private AsyncLazy GetDocumentAnalysisNoLock(Project bas // The only relevant analysis is for the latest base and document snapshots. // Note that the base snapshot may evolve if documents are dicovered that were previously // out-of-sync with the compiled outputs and are now up-to-date. - _analyses[document.Id] = (lazyResults, baseProject, document, activeStatementSpans); + _analyses[document.Id] = (lazyResults, baseProject, document, activeStatementSpans, capabilities); return lazyResults; } From 3eb2ee4fceea9dbfea0f836b4fa9dc583044e490 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 12:08:11 +1000 Subject: [PATCH 28/32] Use specific rude edit kind for telemetry purposes --- .../EditAndContinue/AbstractEditAndContinueAnalyzer.cs | 6 +++--- .../EditAndContinue/EditAndContinueDiagnosticDescriptors.cs | 1 + src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 049dcc13e7e10..9d7ca006d1c50 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2597,7 +2597,7 @@ private async Task> AnalyzeSemanticsAsync( if (oldContainingType != null && !capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) { diagnostics.Add(new RudeEditDiagnostic( - RudeEditKind.Insert, + RudeEditKind.InsertNotSupportedByRuntime, GetDiagnosticSpan(edit.NewNode, EditKind.Insert), edit.NewNode, arguments: new[] { GetDisplayName(edit.NewNode, EditKind.Insert) })); @@ -2636,7 +2636,7 @@ private async Task> AnalyzeSemanticsAsync( if (!capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)) { diagnostics.Add(new RudeEditDiagnostic( - RudeEditKind.Insert, + RudeEditKind.InsertNotSupportedByRuntime, GetDiagnosticSpan(edit.NewNode, EditKind.Insert), edit.NewNode, arguments: new[] { GetDisplayName(edit.NewNode, EditKind.Insert) })); @@ -3597,7 +3597,7 @@ select clausesByQuery.First()) { if (!CanAddNewLambda(newLambda, capabilities, matchedLambdas)) { - diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.Insert, GetDiagnosticSpan(newLambda, EditKind.Insert), newLambda, new string[] { GetDisplayName(newLambda, EditKind.Insert) })); + diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.InsertNotSupportedByRuntime, GetDiagnosticSpan(newLambda, EditKind.Insert), newLambda, new string[] { GetDisplayName(newLambda, EditKind.Insert) })); } // TODO: https://github.com/dotnet/roslyn/issues/37128 diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index c37dd7f98dc40..ca3206918b2bc 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -154,6 +154,7 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.NotSupportedByRuntime, nameof(FeaturesResources.Edit_and_continue_is_not_supported_by_the_runtime)); AddRudeEdit(RudeEditKind.MakeMethodAsync, nameof(FeaturesResources.Making_a_method_async_will_prevent_the_debug_session_from_continuing)); AddRudeEdit(RudeEditKind.MakeMethodIterator, nameof(FeaturesResources.Making_a_method_an_iterator_will_prevent_the_debug_session_from_continuing)); + AddRudeEdit(RudeEditKind.InsertNotSupportedByRuntime, nameof(FeaturesResources.Adding_0_will_prevent_the_debug_session_from_continuing)); // VB specific AddRudeEdit(RudeEditKind.HandlesClauseUpdate, nameof(FeaturesResources.Updating_the_Handles_clause_of_0_will_prevent_the_debug_session_from_continuing)); diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index 90cb8d991a561..6e1b6ff1db8bd 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -126,6 +126,7 @@ internal enum RudeEditKind : ushort NotSupportedByRuntime = 97, MakeMethodAsync = 98, - MakeMethodIterator = 99 + MakeMethodIterator = 99, + InsertNotSupportedByRuntime = 100 } } From ab781548d2cfa75245ef52fefce0ced3572ec159 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 13:45:53 +1000 Subject: [PATCH 29/32] Update tests --- .../CSharpTest/EditAndContinue/StatementEditingTests.cs | 8 ++++---- .../CSharpTest/EditAndContinue/TopLevelEditingTests.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index ad2773136bbfb..270c0ad7cb7c4 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -2655,7 +2655,7 @@ void F() edits.VerifySemanticDiagnostics( activeStatements: ActiveStatementsDescription.Empty, capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "a", "lambda")); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "a", CSharpFeaturesResources.lambda)); } [Fact] @@ -2691,7 +2691,7 @@ void F() edits.VerifySemanticDiagnostics( activeStatements: ActiveStatementsDescription.Empty, capabilities, - Diagnostic(RudeEditKind.Insert, "b", "lambda")); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "b", CSharpFeaturesResources.lambda)); } [Fact] @@ -2727,7 +2727,7 @@ void F() capabilities, // TODO: https://github.com/dotnet/roslyn/issues/52759 // This is incorrect, there should be no rude edit reported - Diagnostic(RudeEditKind.Insert, "b", "lambda")); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "b", CSharpFeaturesResources.lambda)); } [Fact] @@ -5619,7 +5619,7 @@ void M() edits.VerifySemanticDiagnostics( activeStatements: ActiveStatementsDescription.Empty, capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "M", FeaturesResources.local_function)); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "M", FeaturesResources.local_function)); } [Fact, WorkItem(21499, "https://github.com/dotnet/roslyn/issues/21499")] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 526f9b70eceb5..f7e6b98ec2a86 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -1062,7 +1062,7 @@ void M() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "public class D", FeaturesResources.class_)); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "public class D", FeaturesResources.class_)); } [Fact] @@ -5132,7 +5132,7 @@ public void MethodInsert_NotSupportedByRuntime() edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "void goo()", FeaturesResources.method)); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "void goo()", FeaturesResources.method)); } [Fact] @@ -10517,7 +10517,7 @@ public void FieldInsert_NotSupportedByRuntime() edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "a = 1", FeaturesResources.field)); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "a = 1", FeaturesResources.field)); } [Fact] @@ -11007,7 +11007,7 @@ public void PropertyInsert_NotSupportedByRuntime() edits.VerifyRudeDiagnostics( capabilities: EditAndContinueTestHelpers.BaselineCapabilities, - Diagnostic(RudeEditKind.Insert, "int P", FeaturesResources.auto_property)); + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "int P", FeaturesResources.auto_property)); } [WorkItem(835827, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/835827")] From 77fed63f58dd89a0e97338d5c362c5579bbd7892 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 26 Apr 2021 14:46:56 +1000 Subject: [PATCH 30/32] Expand runtime capability for adding new defintions --- .../EditAndContinue/TopLevelEditingTests.cs | 15 ++++++++++- .../EditAndContinueTestHelpers.cs | 6 ++++- .../AbstractEditAndContinueAnalyzer.cs | 27 ++++++++++++++++--- .../EditAndContinueWorkspaceService.cs | 7 ++++- .../ManagedEditAndContinueCapability.cs | 18 ++++++++++--- 5 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index f7e6b98ec2a86..190b7ea65e1ca 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -10516,7 +10516,20 @@ public void FieldInsert_NotSupportedByRuntime() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( - capabilities: EditAndContinueTestHelpers.BaselineCapabilities, + capabilities: EditAndContinueTestHelpers.BaselineCapabilities | ManagedEditAndContinueCapability.AddStaticFieldToExistingType, + Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "a = 1", FeaturesResources.field)); + } + + [Fact] + public void FieldInsert_Static_NotSupportedByRuntime() + { + var src1 = "class C { }"; + var src2 = "class C { public static int a = 1; }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyRudeDiagnostics( + capabilities: EditAndContinueTestHelpers.BaselineCapabilities | ManagedEditAndContinueCapability.AddInstanceFieldToExistingType, Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "a = 1", FeaturesResources.field)); } diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index 0c4cfb33271a4..a02001f96a489 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -30,7 +30,11 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests internal abstract class EditAndContinueTestHelpers { public static readonly ManagedEditAndContinueCapability BaselineCapabilities = ManagedEditAndContinueCapability.Baseline; - public static readonly ManagedEditAndContinueCapability Net5RuntimeCapabilities = ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.AddDefinitionToExistingType | ManagedEditAndContinueCapability.NewTypeDefinition; + public static readonly ManagedEditAndContinueCapability Net5RuntimeCapabilities = ManagedEditAndContinueCapability.Baseline | + ManagedEditAndContinueCapability.AddInstanceFieldToExistingType | + ManagedEditAndContinueCapability.AddStaticFieldToExistingType | + ManagedEditAndContinueCapability.AddMethodToExistingType | + ManagedEditAndContinueCapability.NewTypeDefinition; public abstract AbstractEditAndContinueAnalyzer Analyzer { get; } public abstract SyntaxNode FindNode(SyntaxNode root, TextSpan span); diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 9d7ca006d1c50..c1333910546a6 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2594,7 +2594,7 @@ private async Task> AnalyzeSemanticsAsync( var containingSymbolKey = SymbolKey.Create(newContainingType, cancellationToken); oldContainingType = containingSymbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true, cancellationToken).Symbol as INamedTypeSymbol; - if (oldContainingType != null && !capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType)) + if (oldContainingType != null && !CanAddNewMember(newSymbol, capabilities)) { diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.InsertNotSupportedByRuntime, @@ -2881,6 +2881,25 @@ private async Task> AnalyzeSemanticsAsync( return semanticEdits.ToImmutable(); } + private static bool CanAddNewMember(ISymbol newSymbol, ManagedEditAndContinueCapability capabilities) + { + if (newSymbol is IMethodSymbol or IPropertySymbol) // Properties are just get_ and set_ methods + { + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); + } + else if (newSymbol is IFieldSymbol field) + { + if (field.IsStatic) + { + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddStaticFieldToExistingType); + } + + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddInstanceFieldToExistingType); + } + + return true; + } + private static void AddEditsForSynthesizedRecordMembers(Compilation compilation, INamedTypeSymbol recordType, ArrayBuilder semanticEdits) { foreach (var member in GetRecordUpdatedSynthesizedMembers(compilation, recordType)) @@ -3645,7 +3664,7 @@ private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapabil // New local functions mean new methods in existing classes if (IsLocalFunction(newLambda)) { - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); } // New lambdas sometimes mean creating new helper classes, and sometimes mean new methods in exising helper classes @@ -3655,14 +3674,14 @@ private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapabil // This check is redundant with the below, once the limitation in the referenced issue is resolved if (matchedLambdas is { Count: > 0 }) { - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + return capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); } // If there is already a lambda in the class then the new lambda would result in a new method in the existing helper class. // If there isn't already a lambda in the class then the new lambda would result in a new helper class. // Unfortunately right now we can't determine which of these is true so we have to just check both capabilities instead. return capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition) && - capabilities.HasFlag(ManagedEditAndContinueCapability.AddDefinitionToExistingType); + capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); } private void ReportMultiScopeCaptures( diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index d55d3f4b27f8d..193daeb72e242 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -103,9 +103,14 @@ internal static ManagedEditAndContinueCapability ParseCapabilities(ImmutableArra caps |= capability switch { "Baseline" => ManagedEditAndContinueCapability.Baseline, - "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddDefinitionToExistingType, + "AddMethodToExistingType" => ManagedEditAndContinueCapability.AddMethodToExistingType, + "AddStaticFieldToExistingType" => ManagedEditAndContinueCapability.AddStaticFieldToExistingType, + "AddInstanceFieldToExistingType" => ManagedEditAndContinueCapability.AddInstanceFieldToExistingType, "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, + // To make it eaiser for runtimes to specify more broad capabilities + "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddMethodToExistingType | ManagedEditAndContinueCapability.AddStaticFieldToExistingType | ManagedEditAndContinueCapability.AddInstanceFieldToExistingType, + _ => ManagedEditAndContinueCapability.None }; } diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs index 3aa5191f6eeda..a7f3af07de323 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs @@ -20,13 +20,23 @@ internal enum ManagedEditAndContinueCapability Baseline = 1 << 0, /// - /// A new field/property/method definition can be added to an existing type. + /// Adding a static or instance method to an existing type. /// - AddDefinitionToExistingType = 1 << 1, + AddMethodToExistingType = 1 << 1, /// - /// A new type definition can be created. + /// Adding a static field to an existing type. /// - NewTypeDefinition = 1 << 2, + AddStaticFieldToExistingType = 1 << 2, + + /// + /// Adding an instance field to an existing type. + /// + AddInstanceFieldToExistingType = 1 << 3, + + /// + /// Creating a new type definition. + /// + NewTypeDefinition = 1 << 2 } } From c412d3b2e0231a2dd21f0e902fa9b612b7ea50b7 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 27 Apr 2021 06:00:26 +1000 Subject: [PATCH 31/32] Missed a word --- .../EditAndContinue/ManagedEditAndContinueCapability.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs index a7f3af07de323..c3c12e4a15413 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs +++ b/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs @@ -15,7 +15,7 @@ internal enum ManagedEditAndContinueCapability None = 0, /// - /// Edit and continue is generally with the set of capabilities that Mono 6, .NET Framework and .NET 5 have in common. + /// Edit and continue is generally available with the set of capabilities that Mono 6, .NET Framework and .NET 5 have in common. /// Baseline = 1 << 0, From b26dcad103e1eb1500fbaa90d0c0ff490c1d3b14 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 27 Apr 2021 06:09:50 +1000 Subject: [PATCH 32/32] Rename --- .../CSharpEditAndContinueAnalyzerTests.cs | 2 +- .../Helpers/EditAndContinueValidation.cs | 8 ++--- .../EditAndContinue/StatementEditingTests.cs | 4 +-- .../EditAndContinue/TopLevelEditingTests.cs | 4 +-- .../EditAndContinueWorkspaceServiceTests.cs | 14 ++++---- .../EditAndContinueTestHelpers.cs | 14 ++++---- .../AbstractEditAndContinueAnalyzer.cs | 32 +++++++++---------- .../EditAndContinue/DebuggingSession.cs | 4 +-- ...lity.cs => EditAndContinueCapabilities.cs} | 2 +- .../EditAndContinueDocumentAnalysesCache.cs | 10 +++--- .../EditAndContinueWorkspaceService.cs | 18 +++++------ .../IEditAndContinueAnalyzer.cs | 2 +- 12 files changed, 57 insertions(+), 57 deletions(-) rename src/Features/Core/Portable/EditAndContinue/{ManagedEditAndContinueCapability.cs => EditAndContinueCapabilities.cs} (96%) diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index 2d03454f05eb7..c9170321bc2cf 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -796,7 +796,7 @@ public static void Main() var baseActiveStatements = ImmutableArray.Create(); var analyzer = new CSharpEditAndContinueAnalyzer(); - var capabilities = ManagedEditAndContinueCapability.None; + var capabilities = EditAndContinueCapabilities.None; var result = await analyzer.AnalyzeDocumentAsync(oldProject, baseActiveStatements, newDocument, ImmutableArray.Empty, capabilities, CancellationToken.None); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs index 2c75c6ad93b87..7d06ca85b30a2 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditAndContinueValidation.cs @@ -41,7 +41,7 @@ internal static void VerifyRudeDiagnostics( internal static void VerifyRudeDiagnostics( this EditScript editScript, - ManagedEditAndContinueCapability? capabilities = null, + EditAndContinueCapabilities? capabilities = null, params RudeEditDiagnosticDescription[] expectedDiagnostics) { VerifySemanticDiagnostics( @@ -96,7 +96,7 @@ internal static void VerifySemanticDiagnostics( internal static void VerifySemanticDiagnostics( this EditScript editScript, ActiveStatementsDescription activeStatements, - ManagedEditAndContinueCapability? capabilities = null, + EditAndContinueCapabilities? capabilities = null, params RudeEditDiagnosticDescription[] expectedDiagnostics) { VerifySemantics( @@ -120,7 +120,7 @@ internal static void VerifySemantics( this EditScript editScript, ActiveStatementsDescription activeStatements, SemanticEditDescription[] expectedSemanticEdits, - ManagedEditAndContinueCapability? capabilities = null) + EditAndContinueCapabilities? capabilities = null) { VerifySemantics( new[] { editScript }, @@ -139,7 +139,7 @@ internal static void VerifySemantics( EditScript[] editScripts, DocumentAnalysisResultsDescription[] expected, TargetFramework[]? targetFrameworks = null, - ManagedEditAndContinueCapability? capabilities = null) + EditAndContinueCapabilities? capabilities = null) { foreach (var targetFramework in targetFrameworks ?? new[] { TargetFramework.NetStandard20, TargetFramework.NetCoreApp }) { diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index 270c0ad7cb7c4..672d583157694 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -2684,7 +2684,7 @@ void F() } } "; - var capabilities = ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition; + var capabilities = EditAndContinueCapabilities.Baseline | EditAndContinueCapabilities.NewTypeDefinition; var edits = GetTopEdits(src1, src2); @@ -2718,7 +2718,7 @@ void F() } } "; - var capabilities = ManagedEditAndContinueCapability.Baseline | ManagedEditAndContinueCapability.NewTypeDefinition; + var capabilities = EditAndContinueCapabilities.Baseline | EditAndContinueCapabilities.NewTypeDefinition; var edits = GetTopEdits(src1, src2); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 190b7ea65e1ca..c99c831ff6c7a 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -10516,7 +10516,7 @@ public void FieldInsert_NotSupportedByRuntime() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( - capabilities: EditAndContinueTestHelpers.BaselineCapabilities | ManagedEditAndContinueCapability.AddStaticFieldToExistingType, + capabilities: EditAndContinueTestHelpers.BaselineCapabilities | EditAndContinueCapabilities.AddStaticFieldToExistingType, Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "a = 1", FeaturesResources.field)); } @@ -10529,7 +10529,7 @@ public void FieldInsert_Static_NotSupportedByRuntime() var edits = GetTopEdits(src1, src2); edits.VerifyRudeDiagnostics( - capabilities: EditAndContinueTestHelpers.BaselineCapabilities | ManagedEditAndContinueCapability.AddInstanceFieldToExistingType, + capabilities: EditAndContinueTestHelpers.BaselineCapabilities | EditAndContinueCapabilities.AddInstanceFieldToExistingType, Diagnostic(RudeEditKind.InsertNotSupportedByRuntime, "a = 1", FeaturesResources.field)); } diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index bd6bd533d39ef..d9e3b9b4dca14 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -3326,8 +3326,8 @@ public void ParseCapabilities() var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.False(service.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)); + Assert.True(service.HasFlag(EditAndContinueCapabilities.Baseline)); + Assert.False(service.HasFlag(EditAndContinueCapabilities.NewTypeDefinition)); } [Fact] @@ -3337,7 +3337,7 @@ public void ParseCapabilities_CaseSensitive() var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.False(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); + Assert.False(service.HasFlag(EditAndContinueCapabilities.Baseline)); } [Fact] @@ -3347,8 +3347,8 @@ public void ParseCapabilities_IgnoreInvalid() var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)); + Assert.True(service.HasFlag(EditAndContinueCapabilities.Baseline)); + Assert.True(service.HasFlag(EditAndContinueCapabilities.NewTypeDefinition)); } [Fact] @@ -3358,8 +3358,8 @@ public void ParseCapabilities_IgnoreInvalidNumeric() var service = EditAndContinueWorkspaceService.ParseCapabilities(capabilities); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.Baseline)); - Assert.True(service.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)); + Assert.True(service.HasFlag(EditAndContinueCapabilities.Baseline)); + Assert.True(service.HasFlag(EditAndContinueCapabilities.NewTypeDefinition)); } } } diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index a02001f96a489..518683dd6e38f 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -29,12 +29,12 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { internal abstract class EditAndContinueTestHelpers { - public static readonly ManagedEditAndContinueCapability BaselineCapabilities = ManagedEditAndContinueCapability.Baseline; - public static readonly ManagedEditAndContinueCapability Net5RuntimeCapabilities = ManagedEditAndContinueCapability.Baseline | - ManagedEditAndContinueCapability.AddInstanceFieldToExistingType | - ManagedEditAndContinueCapability.AddStaticFieldToExistingType | - ManagedEditAndContinueCapability.AddMethodToExistingType | - ManagedEditAndContinueCapability.NewTypeDefinition; + public static readonly EditAndContinueCapabilities BaselineCapabilities = EditAndContinueCapabilities.Baseline; + public static readonly EditAndContinueCapabilities Net5RuntimeCapabilities = EditAndContinueCapabilities.Baseline | + EditAndContinueCapabilities.AddInstanceFieldToExistingType | + EditAndContinueCapabilities.AddStaticFieldToExistingType | + EditAndContinueCapabilities.AddMethodToExistingType | + EditAndContinueCapabilities.NewTypeDefinition; public abstract AbstractEditAndContinueAnalyzer Analyzer { get; } public abstract SyntaxNode FindNode(SyntaxNode root, TextSpan span); @@ -150,7 +150,7 @@ internal void VerifyLineEdits( AssertEx.Equal(expectedNodeUpdates, actualNodeUpdates, itemSeparator: ",\r\n"); } - internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults, ManagedEditAndContinueCapability? capabilities = null) + internal void VerifySemantics(EditScript[] editScripts, TargetFramework targetFramework, DocumentAnalysisResultsDescription[] expectedResults, EditAndContinueCapabilities? capabilities = null) { Assert.True(editScripts.Length == expectedResults.Length); var documentCount = expectedResults.Length; diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index c1333910546a6..b9061cb1fe236 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -451,7 +451,7 @@ public async Task AnalyzeDocumentAsync( ImmutableArray oldActiveStatements, Document newDocument, ImmutableArray newActiveStatementSpans, - ManagedEditAndContinueCapability capabilities, + EditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { DocumentAnalysisResults.Log.Write("Analyzing document {0}", newDocument.Name); @@ -537,7 +537,7 @@ public async Task AnalyzeDocumentAsync( } // If the document has changed at all, lets make sure Edit and Continue is supported - if (!capabilities.HasFlag(ManagedEditAndContinueCapability.Baseline)) + if (!capabilities.HasFlag(EditAndContinueCapabilities.Baseline)) { return DocumentAnalysisResults.SyntaxErrors(newDocument.Id, ImmutableArray.Create( new RudeEditDiagnostic(RudeEditKind.NotSupportedByRuntime, default)), hasChanges); @@ -913,7 +913,7 @@ private void AnalyzeChangedMemberBody( ISymbol newSymbol, ImmutableArray oldActiveStatements, ImmutableArray newActiveStatementSpans, - ManagedEditAndContinueCapability capabilities, + EditAndContinueCapabilities capabilities, [Out] ImmutableArray.Builder newActiveStatements, [Out] ImmutableArray>.Builder newExceptionRegions, [Out] ArrayBuilder diagnostics, @@ -1019,7 +1019,7 @@ private void AnalyzeChangedMemberBody( ReportStateMachineRudeEdits(oldModel.Compilation, oldSymbol, newBody, diagnostics); } else if (newHasStateMachineSuspensionPoint && - !capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)) + !capabilities.HasFlag(EditAndContinueCapabilities.NewTypeDefinition)) { // Adding a state machine, either for async or iterator, will require creating a new helper class // so is a rude edit if the runtime doesn't support it @@ -2219,7 +2219,7 @@ private async Task> AnalyzeSemanticsAsync( ArrayBuilder diagnostics, ImmutableArray.Builder newActiveStatements, ImmutableArray>.Builder newExceptionRegions, - ManagedEditAndContinueCapability capabilities, + EditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { if (editScript.Edits.Length == 0 && triviaEdits.Count == 0) @@ -2633,7 +2633,7 @@ private async Task> AnalyzeSemanticsAsync( // adds a new top-level type Contract.ThrowIfFalse(newSymbol is INamedTypeSymbol); - if (!capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition)) + if (!capabilities.HasFlag(EditAndContinueCapabilities.NewTypeDefinition)) { diagnostics.Add(new RudeEditDiagnostic( RudeEditKind.InsertNotSupportedByRuntime, @@ -2881,20 +2881,20 @@ private async Task> AnalyzeSemanticsAsync( return semanticEdits.ToImmutable(); } - private static bool CanAddNewMember(ISymbol newSymbol, ManagedEditAndContinueCapability capabilities) + private static bool CanAddNewMember(ISymbol newSymbol, EditAndContinueCapabilities capabilities) { if (newSymbol is IMethodSymbol or IPropertySymbol) // Properties are just get_ and set_ methods { - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); + return capabilities.HasFlag(EditAndContinueCapabilities.AddMethodToExistingType); } else if (newSymbol is IFieldSymbol field) { if (field.IsStatic) { - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddStaticFieldToExistingType); + return capabilities.HasFlag(EditAndContinueCapabilities.AddStaticFieldToExistingType); } - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddInstanceFieldToExistingType); + return capabilities.HasFlag(EditAndContinueCapabilities.AddInstanceFieldToExistingType); } return true; @@ -3420,7 +3420,7 @@ private void ReportLambdaAndClosureRudeEdits( ISymbol newMember, IReadOnlyDictionary? matchedLambdas, BidirectionalMap map, - ManagedEditAndContinueCapability capabilities, + EditAndContinueCapabilities capabilities, ArrayBuilder diagnostics, out bool syntaxMapRequired, CancellationToken cancellationToken) @@ -3659,12 +3659,12 @@ select clausesByQuery.First()) oldCapturesToClosureScopes.Free(); } - private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapability capabilities, IReadOnlyDictionary? matchedLambdas) + private bool CanAddNewLambda(SyntaxNode newLambda, EditAndContinueCapabilities capabilities, IReadOnlyDictionary? matchedLambdas) { // New local functions mean new methods in existing classes if (IsLocalFunction(newLambda)) { - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); + return capabilities.HasFlag(EditAndContinueCapabilities.AddMethodToExistingType); } // New lambdas sometimes mean creating new helper classes, and sometimes mean new methods in exising helper classes @@ -3674,14 +3674,14 @@ private bool CanAddNewLambda(SyntaxNode newLambda, ManagedEditAndContinueCapabil // This check is redundant with the below, once the limitation in the referenced issue is resolved if (matchedLambdas is { Count: > 0 }) { - return capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); + return capabilities.HasFlag(EditAndContinueCapabilities.AddMethodToExistingType); } // If there is already a lambda in the class then the new lambda would result in a new method in the existing helper class. // If there isn't already a lambda in the class then the new lambda would result in a new helper class. // Unfortunately right now we can't determine which of these is true so we have to just check both capabilities instead. - return capabilities.HasFlag(ManagedEditAndContinueCapability.NewTypeDefinition) && - capabilities.HasFlag(ManagedEditAndContinueCapability.AddMethodToExistingType); + return capabilities.HasFlag(EditAndContinueCapabilities.NewTypeDefinition) && + capabilities.HasFlag(EditAndContinueCapabilities.AddMethodToExistingType); } private void ReportMultiScopeCaptures( diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index e15001116ac72..8984b580e3a12 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -100,7 +100,7 @@ internal sealed class DebuggingSession : IDisposable /// /// Gets the capabilities of the runtime with respect to applying code changes. /// - internal readonly ManagedEditAndContinueCapability Capabilities; + internal readonly EditAndContinueCapabilities Capabilities; private readonly DebuggingSessionTelemetry _telemetry; internal EditSession EditSession; @@ -108,7 +108,7 @@ internal sealed class DebuggingSession : IDisposable internal DebuggingSession( Solution solution, IManagedEditAndContinueDebuggerService debuggerService, - ManagedEditAndContinueCapability capabilities, + EditAndContinueCapabilities capabilities, Func compilationOutputsProvider, IEnumerable> initialDocumentStates, DebuggingSessionTelemetry debuggingSessionTelemetry, diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs similarity index 96% rename from src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs rename to src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs index c3c12e4a15413..02978f6882471 100644 --- a/src/Features/Core/Portable/EditAndContinue/ManagedEditAndContinueCapability.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue /// The capabilities that the runtime has with respect to edit and continue /// [Flags] - internal enum ManagedEditAndContinueCapability + internal enum EditAndContinueCapabilities { None = 0, diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs index 2992854978b51..7cf43a6c5f469 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue internal sealed class EditAndContinueDocumentAnalysesCache { private readonly object _guard = new(); - private readonly Dictionary results, Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities)> _analyses = new(); + private readonly Dictionary results, Project baseProject, Document document, ImmutableArray activeStatementSpans, EditAndContinueCapabilities capabilities)> _analyses = new(); private readonly AsyncLazy _baseActiveStatements; public EditAndContinueDocumentAnalysesCache(AsyncLazy baseActiveStatements) @@ -30,7 +30,7 @@ public EditAndContinueDocumentAnalysesCache(AsyncLazy baseA _baseActiveStatements = baseActiveStatements; } - public async ValueTask> GetActiveStatementsAsync(Document baseDocument, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) + public async ValueTask> GetActiveStatementsAsync(Document baseDocument, Document document, ImmutableArray activeStatementSpans, EditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { try { @@ -46,7 +46,7 @@ public async ValueTask> GetActiveStatementsAsync public async ValueTask> GetDocumentAnalysesAsync( Project oldProject, IReadOnlyList<(Document newDocument, ImmutableArray newActiveStatementSpans)> documentInfos, - ManagedEditAndContinueCapability capabilities, + EditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { try @@ -73,7 +73,7 @@ public async ValueTask> GetDocumentAnaly /// Base project. /// Document snapshot to analyze. /// Active statement spans tracked by the editor. - public async ValueTask GetDocumentAnalysisAsync(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken) + public async ValueTask GetDocumentAnalysisAsync(Project baseProject, Document document, ImmutableArray activeStatementSpans, EditAndContinueCapabilities capabilities, CancellationToken cancellationToken) { try { @@ -92,7 +92,7 @@ public async ValueTask GetDocumentAnalysisAsync(Project } } - private AsyncLazy GetDocumentAnalysisNoLock(Project baseProject, Document document, ImmutableArray activeStatementSpans, ManagedEditAndContinueCapability capabilities) + private AsyncLazy GetDocumentAnalysisNoLock(Project baseProject, Document document, ImmutableArray activeStatementSpans, EditAndContinueCapabilities capabilities) { // Do not reuse an analysis of the document unless its snasphot is exactly the same as was used to calculate the results. // Note that comparing document snapshots in effect compares the entire solution snapshots (when another document is changed a new solution snapshot is created diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index 193daeb72e242..02a1146aad429 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -94,24 +94,24 @@ public async ValueTask StartDebuggingSessionAsync(Solution solution, IManagedEdi } // internal for testing - internal static ManagedEditAndContinueCapability ParseCapabilities(ImmutableArray capabilities) + internal static EditAndContinueCapabilities ParseCapabilities(ImmutableArray capabilities) { - var caps = ManagedEditAndContinueCapability.None; + var caps = EditAndContinueCapabilities.None; foreach (var capability in capabilities) { caps |= capability switch { - "Baseline" => ManagedEditAndContinueCapability.Baseline, - "AddMethodToExistingType" => ManagedEditAndContinueCapability.AddMethodToExistingType, - "AddStaticFieldToExistingType" => ManagedEditAndContinueCapability.AddStaticFieldToExistingType, - "AddInstanceFieldToExistingType" => ManagedEditAndContinueCapability.AddInstanceFieldToExistingType, - "NewTypeDefinition" => ManagedEditAndContinueCapability.NewTypeDefinition, + "Baseline" => EditAndContinueCapabilities.Baseline, + "AddMethodToExistingType" => EditAndContinueCapabilities.AddMethodToExistingType, + "AddStaticFieldToExistingType" => EditAndContinueCapabilities.AddStaticFieldToExistingType, + "AddInstanceFieldToExistingType" => EditAndContinueCapabilities.AddInstanceFieldToExistingType, + "NewTypeDefinition" => EditAndContinueCapabilities.NewTypeDefinition, // To make it eaiser for runtimes to specify more broad capabilities - "AddDefinitionToExistingType" => ManagedEditAndContinueCapability.AddMethodToExistingType | ManagedEditAndContinueCapability.AddStaticFieldToExistingType | ManagedEditAndContinueCapability.AddInstanceFieldToExistingType, + "AddDefinitionToExistingType" => EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddStaticFieldToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType, - _ => ManagedEditAndContinueCapability.None + _ => EditAndContinueCapabilities.None }; } diff --git a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs index 6af82c4322b7b..c4a277d2a788b 100644 --- a/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.EditAndContinue { internal interface IEditAndContinueAnalyzer : ILanguageService { - Task AnalyzeDocumentAsync(Project baseProject, ImmutableArray baseActiveStatements, Document document, ImmutableArray newActiveStatementSpans, ManagedEditAndContinueCapability capabilities, CancellationToken cancellationToken); + Task AnalyzeDocumentAsync(Project baseProject, ImmutableArray baseActiveStatements, Document document, ImmutableArray newActiveStatementSpans, EditAndContinueCapabilities capabilities, CancellationToken cancellationToken); ImmutableArray GetExceptionRegions(SourceText text, SyntaxNode syntaxRoot, LinePositionSpan activeStatementSpan, bool isLeaf, out bool isCovered); } }