From c4a24b3065eb403e378a34f95aec7dc006404c05 Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 3 Mar 2023 17:11:32 -0800 Subject: [PATCH 01/11] Use exception with specific type and HResult to aid tracking in telemetry --- .../EditAndContinueLanguageService.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs index bb383613c794f..f7f95a0841c98 100644 --- a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs @@ -25,6 +25,16 @@ namespace Microsoft.CodeAnalysis.EditAndContinue [ExportMetadata("UIContext", EditAndContinueUIContext.EncCapableProjectExistsInWorkspaceUIContextString)] internal sealed class EditAndContinueLanguageService : IManagedHotReloadLanguageService, IEditAndContinueSolutionProvider { + private sealed class NoSessionException : InvalidOperationException + { + public NoSessionException() + : base("Internal error: no session.") + { + // unique enough HResult to distinguish from other exceptions + HResult = unchecked((int)0x801315087); + } + } + private readonly PdbMatchingSourceTextProvider _sourceTextProvider; private readonly Lazy _debuggerService; private readonly IDiagnosticAnalyzerService _diagnosticService; @@ -69,11 +79,7 @@ private Solution GetCurrentCompileTimeSolution(Solution? currentDesignTimeSoluti } private RemoteDebuggingSessionProxy GetDebuggingSession() - { - var debuggingSession = _debuggingSession; - Contract.ThrowIfNull(debuggingSession); - return debuggingSession; - } + => _debuggingSession ?? throw new NoSessionException(); private IActiveStatementTrackingService GetActiveStatementTrackingService() => WorkspaceProvider.Value.Workspace.Services.GetRequiredService(); From a37be08de38e5e2538b537468ac31c79ac87fff5 Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 3 Mar 2023 17:42:10 -0800 Subject: [PATCH 02/11] Associate rude edits with project id --- .../EditAndContinueWorkspaceServiceTests.cs | 40 +++++++++++-------- .../EditAndContinue/DebuggingSession.cs | 2 +- .../DebuggingSessionTelemetry.cs | 8 +++- .../Portable/EditAndContinue/EditSession.cs | 2 +- .../EditAndContinue/EditSessionTelemetry.cs | 8 ++-- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 3106342dbe8e8..bfd9ff5c1b9d7 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -112,6 +112,22 @@ private static (Solution, Document) AddDefaultTestProject( return (solution, solution.Projects.Single().Documents.Single()); } + private static Project AddEmptyTestProject(Solution solution) + { + var projectId = ProjectId.CreateNewId(); + + return solution. + AddProject(ProjectInfo.Create( + projectId, + VersionStamp.Create(), + "proj", + "proj", + LanguageNames.CSharp, + parseOptions: CSharpParseOptions.Default.WithNoRefSafetyRulesAttribute()) + .WithTelemetryId(s_defaultProjectTelemetryId)).GetProject(projectId). + WithMetadataReferences(TargetFrameworkUtil.GetReferences(DefaultTargetFramework)); + } + private static Solution AddDefaultTestProject( Solution solution, string[] sources, @@ -119,12 +135,7 @@ private static Solution AddDefaultTestProject( string additionalFileText = null, (string key, string value)[] analyzerConfig = null) { - var projectId = ProjectId.CreateNewId(); - - var project = solution. - AddProject(ProjectInfo.Create(projectId, VersionStamp.Create(), "proj", "proj", LanguageNames.CSharp, parseOptions: CSharpParseOptions.Default.WithNoRefSafetyRulesAttribute()).WithTelemetryId(s_defaultProjectTelemetryId)).GetProject(projectId). - WithMetadataReferences(TargetFrameworkUtil.GetReferences(DefaultTargetFramework)); - + var project = AddEmptyTestProject(solution); solution = project.Solution; if (generator != null) @@ -1428,7 +1439,7 @@ public async Task RudeEdits(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } else @@ -1437,7 +1448,7 @@ public async Task RudeEdits(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } } @@ -1563,10 +1574,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) using var _ = CreateWorkspace(out var solution, out var service); - var project = solution. - AddProject("test", "test", LanguageNames.CSharp). - AddMetadataReferences(TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib40)); - + var project = AddEmptyTestProject(solution); solution = project.Solution; // compile with source0: @@ -1645,8 +1653,8 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } else @@ -1655,8 +1663,8 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } } diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 4e03d5f8979e9..649eeb0045f94 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -501,7 +501,7 @@ CommittedSolution.DocumentState.Indeterminate or return ImmutableArray.Empty; } - EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors); + EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, project.State.Attributes.TelemetryId); // track the document, so that we can refresh or clean diagnostics at the end of edit session: EditSession.TrackDocumentWithReportedDiagnostics(document.Id); diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs index 0366e479042a7..6b2f60ec6c0b3 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs @@ -127,7 +127,7 @@ public static void Log(Data data, Action log, Func map["Capabilities"] = (int)editSessionData.Capabilities; // Ids of all projects whose binaries were successfully updated during the session. - map["ProjectIdsWithAppliedChanges"] = editSessionData.Committed ? editSessionData.ProjectsWithValidDelta.Select(id => new PiiValue(id.ToString("B").ToUpperInvariant())) : ""; + map["ProjectIdsWithAppliedChanges"] = editSessionData.Committed ? editSessionData.ProjectsWithValidDelta.Select(ProjectIdToPii) : ""; })); foreach (var errorId in editSessionData.EmitErrorIds) @@ -140,7 +140,7 @@ public static void Log(Data data, Action log, Func })); } - foreach (var (editKind, syntaxKind) in editSessionData.RudeEdits) + foreach (var (editKind, syntaxKind, projectId) in editSessionData.RudeEdits) { log(FunctionId.Debugging_EncSession_EditSession_RudeEdit, KeyValueLogMessage.Create(map => { @@ -150,8 +150,12 @@ public static void Log(Data data, Action log, Func map["RudeEditKind"] = editKind; map["RudeEditSyntaxKind"] = syntaxKind; map["RudeEditBlocking"] = editSessionData.HadRudeEdits; + map["RudeEditProjectId"] = ProjectIdToPii(projectId); })); } + + static PiiValue ProjectIdToPii(Guid projectId) + => new(projectId.ToString("B").ToUpperInvariant()); } } } diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index e04d9cdf7e119..dc10a2f8a3e04 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -925,7 +925,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution if (analysis.RudeEditErrors.Length > 0) { documentsWithRudeEdits.Add((analysis.DocumentId, analysis.RudeEditErrors)); - Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors); + Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, newProject.State.Attributes.TelemetryId); } } diff --git a/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs b/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs index c0eb7ceceab3e..aad5c85fdfc9f 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs @@ -15,7 +15,7 @@ internal sealed class EditSessionTelemetry { internal readonly struct Data { - public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind)> RudeEdits; + public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind, Guid projectId)> RudeEdits; public readonly ImmutableArray EmitErrorIds; public readonly ImmutableArray ProjectsWithValidDelta; public readonly EditAndContinueCapabilities Capabilities; @@ -50,7 +50,7 @@ public Data(EditSessionTelemetry telemetry) // Limit the number of reported items to limit the size of the telemetry event (max total size is 64K). private const int MaxReportedProjectIds = 20; - private readonly HashSet<(ushort, ushort)> _rudeEdits = new(); + private readonly HashSet<(ushort, ushort, Guid)> _rudeEdits = new(); private readonly HashSet _emitErrorIds = new(); private readonly HashSet _projectsWithValidDelta = new(); @@ -129,13 +129,13 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid proje public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid projectTelemetryId, ImmutableArray emitDiagnostics) => LogProjectAnalysisSummary(summary, projectTelemetryId, emitDiagnostics.SelectAsArray(d => d.Severity == DiagnosticSeverity.Error, d => d.Id)); - public void LogRudeEditDiagnostics(ImmutableArray diagnostics) + public void LogRudeEditDiagnostics(ImmutableArray diagnostics, Guid projectTelemetryId) { lock (_guard) { foreach (var diagnostic in diagnostics) { - _rudeEdits.Add(((ushort)diagnostic.Kind, diagnostic.SyntaxKind)); + _rudeEdits.Add(((ushort)diagnostic.Kind, diagnostic.SyntaxKind, projectTelemetryId)); } } } From df678c8a45e315d054997e3316d856a2aa847a7f Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 4 Apr 2023 12:19:34 -0700 Subject: [PATCH 03/11] Update the packages and add fix --- eng/Versions.props | 27 ++++++++------- .../Squiggles/ErrorSquiggleProducerTests.cs | 5 +++ ...dChangeConfigurationNotificationHandler.cs | 7 ++++ ...rationNotificationHandler_OnInitialized.cs | 1 + ...ngeConfigurationNotificationHandlerTest.cs | 34 ++++++++++++++++++- .../BuildActionTelemetryTable.csproj | 1 + 6 files changed, 61 insertions(+), 14 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 867ec06641f7c..10fffb5ce7d8e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -25,15 +25,15 @@ 0.1.149-beta 4.3.0-1.final - 17.6.76-preview + 17.6.252 $(VisualStudioEditorPackagesVersion) 6.0.0-rtm.21518.12 6.0.0-rtm.21518.12 17.6.26-preview - 17.6.15-preview - 17.5.33422.76 + 17.6.22 + 17.6.35829 16.10.0 - 13.0.1 - 2.14.24 + 13.0.3 + 2.15.26 4.1.0 7.0.0-alpha.1.22060.1 - 4.1.3100 17.6.40 17.4.0-preview-20220707-01 @@ -129,7 +128,7 @@ 2.0.0-alpha-20170405-2 0.1.0 0.1.2-dev - $(MicrosoftServiceHubVersion) + 4.1.3100 4.2.87-beta 1.1.1-beta-21566-01 16.170.0 From dd8fdbda2e748fa3d10267369a613cf6929b39fa Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 4 Apr 2023 12:47:02 -0700 Subject: [PATCH 05/11] Fix null warning --- .../DidChangeConfigurationNotificationHandler_OnInitialized.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OnInitialized.cs b/src/Features/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OnInitialized.cs index c148a05f36017..3c8a1c98199ba 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OnInitialized.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OnInitialized.cs @@ -27,7 +27,7 @@ await _clientLanguageServerManager.SendRequestAsync cancellationToken).ConfigureAwait(false); } - _supportWorkspaceConfiguration = clientCapabilities.Workspace?.Configuration ?? false; + _supportWorkspaceConfiguration = clientCapabilities?.Workspace?.Configuration ?? false; await RefreshOptionsAsync(cancellationToken).ConfigureAwait(false); } } From 0e0741d4de68af5be39e5304f9ced62650b92b2d Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Tue, 4 Apr 2023 12:58:16 -0700 Subject: [PATCH 06/11] Fix nullable warning --- .../New.IntegrationTests/InProcess/EditorVerifierInProcess.cs | 1 + src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs | 2 +- src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs index 07ff3200a9135..a71c8f225550f 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs @@ -266,6 +266,7 @@ await TestServices.Workspace.WaitForAllAsyncOperationsAsync( var actualTaggedText = actualTaggedSpan.Span.GetText(); Assert.Equal(expectedTag.taggedText, actualTaggedText); + AssertEx.NotNull(actualTaggedSpan.Tag.ToolTipContent); var containerElement = (ContainerElement)actualTaggedSpan.Tag.ToolTipContent; var actualTooltipText = CollectTextInRun(containerElement); Assert.Equal(expectedTag.tooltipText, actualTooltipText); diff --git a/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs b/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs index 7b59fcbab923d..342d8f72bd313 100644 --- a/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs +++ b/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs @@ -259,7 +259,7 @@ private sealed class SimpleAssemblyLoader : IAssemblyLoader public Assembly LoadAssembly(AssemblyName assemblyName) => Assembly.Load(assemblyName); - public Assembly LoadAssembly(string assemblyFullName, string codeBasePath) + public Assembly LoadAssembly(string assemblyFullName, string? codeBasePath) { var assemblyName = new AssemblyName(assemblyFullName); if (!string.IsNullOrEmpty(codeBasePath)) diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs index 952030ff96008..b149b702620d6 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs @@ -147,7 +147,7 @@ private sealed class SimpleAssemblyLoader : IAssemblyLoader public Assembly LoadAssembly(AssemblyName assemblyName) => Assembly.Load(assemblyName); - public Assembly LoadAssembly(string assemblyFullName, string codeBasePath) + public Assembly LoadAssembly(string assemblyFullName, string? codeBasePath) { var assemblyName = new AssemblyName(assemblyFullName); if (!string.IsNullOrEmpty(codeBasePath)) From ce420eba9e136cd1e7be92f5e87187a6e7a0193c Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 5 Apr 2023 10:48:27 -0700 Subject: [PATCH 07/11] Downgrade MicrosoftVisualStudioCompositionVersion to maintain analyzer compatibility --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 11ec81bce6ce4..43b3f3163a0f6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -139,7 +139,7 @@ 15.8.27812-alpha 15.8.27812-alpha 17.6.199-preview - 17.6.17 + 17.6.6 $(VisualStudioEditorPackagesVersion) 17.4.0-beta.22368.1 17.4.0-beta.22368.1 From 00770db428fc0b856eca50a38bd4afe81f09f388 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 5 Apr 2023 12:37:33 -0700 Subject: [PATCH 08/11] Change servicehub package version to maintain the same version of servicehub analyzer --- eng/Versions.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 43b3f3163a0f6..e4bde4000fbc1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -128,8 +128,8 @@ 2.0.0-alpha-20170405-2 0.1.0 0.1.2-dev - 4.1.3100 - 4.2.87-beta + 4.2.1009 + 4.2.100 1.1.1-beta-21566-01 16.170.0 $(MicrosoftTestPlatformVersion) From 0c249195943b3df552f6a989d919435a48f75c12 Mon Sep 17 00:00:00 2001 From: Shen Chen Date: Wed, 5 Apr 2023 13:59:50 -0700 Subject: [PATCH 09/11] Fix nullable warning --- .../Remote/Core/Serialization/MessagePackFormatters.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs b/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs index 5e84344ffa380..2c8b9f80fe6bc 100644 --- a/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs +++ b/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs @@ -146,7 +146,12 @@ internal sealed class EncodingFormatter : IMessagePackFormatter } var name = reader.ReadString(); - return Encoding.GetEncoding(name); + if (name != null) + { + return Encoding.GetEncoding(name); + } + + return null; } catch (Exception e) when (e is not MessagePackSerializationException) { From a6aeb3180f25f122c0927fcbe683adf4d729e739 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Wed, 12 Apr 2023 00:36:21 +0200 Subject: [PATCH 10/11] [17.6] Cache source generator node tables only if their state counts match (#66992) * Add tests * Check count before reusing batched items * Add missing assert * Fix local function name casing * Fix notation in comment * Revert "Check count before reusing batched items" This reverts commit 2984b5f172f002c76b278f67b2ebee250031bf0b. * Check state table counts before caching * Clarify doc comment * Add a test Co-authored-by: Chris Sienkiewicz * Compute `IsCached` flag only in the builder --------- Co-authored-by: Chris Sienkiewicz --- .../SourceGeneration/GeneratorDriverTests.cs | 124 ++++++++++++++++++ .../SourceGeneration/StateTableTests.cs | 39 ++++++ .../SourceGeneration/Nodes/NodeStateTable.cs | 13 +- 3 files changed, 170 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 4f3db6d4cd2d7..7de5877aeba56 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -2053,6 +2053,130 @@ class C { } }); } + [Fact, WorkItem(61162, "https://github.com/dotnet/roslyn/issues/61162")] + public void IncrementalGenerator_Collect_SyntaxProvider_01() + { + var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(static ctx => + { + var invokedMethodsProvider = ctx.SyntaxProvider + .CreateSyntaxProvider( + static (node, _) => node is InvocationExpressionSyntax, + static (ctx, ct) => ctx.SemanticModel.GetSymbolInfo(ctx.Node, ct).Symbol?.Name ?? "(method not found)") + .Collect(); + + ctx.RegisterSourceOutput(invokedMethodsProvider, static (spc, invokedMethods) => + { + spc.AddSource("InvokedMethods.g.cs", string.Join(Environment.NewLine, + invokedMethods.Select(m => $"// {m}"))); + }); + })); + + var source = """ + System.Console.WriteLine(); + System.Console.WriteLine(); + System.Console.WriteLine(); + System.Console.WriteLine(); + """; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugExeThrowing, parseOptions: parseOptions); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions); + verify(ref driver, compilation, """ + // WriteLine + // WriteLine + // WriteLine + // WriteLine + """); + + replace(ref compilation, parseOptions, """ + System.Console.WriteLine(); + System.Console.WriteLine(); + """); + verify(ref driver, compilation, """ + // WriteLine + // WriteLine + """); + + replace(ref compilation, parseOptions, "_ = 0;"); + verify(ref driver, compilation, ""); + + static void verify(ref GeneratorDriver driver, Compilation compilation, string generatedContent) + { + driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics); + outputCompilation.VerifyDiagnostics(); + generatorDiagnostics.Verify(); + var generatedTree = driver.GetRunResult().GeneratedTrees.Single(); + AssertEx.EqualOrDiff(generatedContent, generatedTree.ToString()); + } + + static void replace(ref Compilation compilation, CSharpParseOptions parseOptions, string source) + { + compilation = compilation.ReplaceSyntaxTree(compilation.SyntaxTrees.Single(), CSharpSyntaxTree.ParseText(source, parseOptions)); + } + } + + [Fact, WorkItem(61162, "https://github.com/dotnet/roslyn/issues/61162")] + public void IncrementalGenerator_Collect_SyntaxProvider_02() + { + var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(static ctx => + { + var invokedMethodsProvider = ctx.SyntaxProvider + .CreateSyntaxProvider( + static (node, _) => node is InvocationExpressionSyntax, + static (ctx, ct) => ctx.SemanticModel.GetSymbolInfo(ctx.Node, ct).Symbol?.Name ?? "(method not found)") + .Select((n, _) => n); + + ctx.RegisterSourceOutput(invokedMethodsProvider, static (spc, invokedMethod) => + { + spc.AddSource(invokedMethod, "// " + invokedMethod); + }); + })); + + var source = """ + System.Console.WriteLine(); + System.Console.ReadLine(); + """; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugExeThrowing, parseOptions: parseOptions); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions); + verify(ref driver, compilation, new[] + { + "// WriteLine", + "// ReadLine" + }); + + replace(ref compilation, parseOptions, """ + System.Console.WriteLine(); + """); + + verify(ref driver, compilation, new[] + { + "// WriteLine" + }); + + replace(ref compilation, parseOptions, "_ = 0;"); + verify(ref driver, compilation, Array.Empty()); + + static void verify(ref GeneratorDriver driver, Compilation compilation, string[] generatedContent) + { + driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics); + outputCompilation.VerifyDiagnostics(); + generatorDiagnostics.Verify(); + var trees = driver.GetRunResult().GeneratedTrees; + Assert.Equal(generatedContent.Length, trees.Length); + for (int i = 0; i < generatedContent.Length; i++) + { + AssertEx.EqualOrDiff(generatedContent[i], trees[i].ToString()); + } + } + + static void replace(ref Compilation compilation, CSharpParseOptions parseOptions, string source) + { + compilation = compilation.ReplaceSyntaxTree(compilation.SyntaxTrees.Single(), CSharpSyntaxTree.ParseText(source, parseOptions)); + } + } + [Fact] public void IncrementalGenerator_Register_End_Node_Only_Once_Through_Combines() { diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs index e19feab7f40b8..e48ce6a86981d 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs @@ -585,6 +585,45 @@ public void Batch_Node_Records_InputModified_Step_When_Inputs_Are_Changed() }); } + [Fact, WorkItem(61162, "https://github.com/dotnet/roslyn/issues/61162")] + public void Batch_Node_Remove_From_Beginning() + { + // [A], [B] + var input = new[] { ("A", EntryState.Added), ("B", EntryState.Added) }; + var inputNode = new CallbackNode((_, _) => + { + // Simulate syntax node. + var builder = NodeStateTable.Empty.ToBuilder(null, false); + foreach (var (value, state) in input) + { + builder.AddEntry(value, state, TimeSpan.Zero, default, state); + } + return builder.ToImmutableAndFree(); + }); + var dstBuilder = GetBuilder(DriverStateTable.Empty); + var table1 = dstBuilder.GetLatestStateTableForNode(inputNode); + AssertTableEntries(table1, new[] { ("A", EntryState.Added, 0), ("B", EntryState.Added, 0) }); + AssertTableEntries(table1.AsCached(), new[] { ("A", EntryState.Cached, 0), ("B", EntryState.Cached, 0) }); + + // batch => [[A], [B]] + var batchNode = new BatchNode(inputNode); + var table2 = dstBuilder.GetLatestStateTableForNode(batchNode); + AssertTableEntries(table2, new[] { (ImmutableArray.Create("A", "B"), EntryState.Added, 0) }); + AssertTableEntries(table2.AsCached(), new[] { (ImmutableArray.Create("A", "B"), EntryState.Cached, 0) }); + + // [B] + input = new[] { ("B", EntryState.Cached) }; + dstBuilder = GetBuilder(dstBuilder.ToImmutable()); + table1 = dstBuilder.GetLatestStateTableForNode(inputNode); + AssertTableEntries(table1, new[] { ("B", EntryState.Cached, 0) }); + AssertTableEntries(table1.AsCached(), new[] { ("B", EntryState.Cached, 0) }); + + // batch => [[B]] + table2 = dstBuilder.GetLatestStateTableForNode(batchNode); + AssertTableEntries(table2, new[] { (ImmutableArray.Create("B"), EntryState.Modified, 0) }); + AssertTableEntries(table2.AsCached(), new[] { (ImmutableArray.Create("B"), EntryState.Cached, 0) }); + } + [Fact] [WorkItem(54832, "https://github.com/dotnet/roslyn/issues/54832")] public void Transform_Node_Records_NewInput_OnFirst_Run() diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs index 190f2dbf9d94e..3d51341f109ae 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs @@ -60,24 +60,24 @@ internal interface IStateTable /// The type of the items tracked by this table internal sealed class NodeStateTable : IStateTable { - internal static NodeStateTable Empty { get; } = new NodeStateTable(ImmutableArray.Empty, ImmutableArray.Empty, hasTrackedSteps: true); + internal static NodeStateTable Empty { get; } = new NodeStateTable(ImmutableArray.Empty, ImmutableArray.Empty, hasTrackedSteps: true, isCached: false); private readonly ImmutableArray _states; - private NodeStateTable(ImmutableArray states, ImmutableArray steps, bool hasTrackedSteps) + private NodeStateTable(ImmutableArray states, ImmutableArray steps, bool hasTrackedSteps, bool isCached) { Debug.Assert(!hasTrackedSteps || steps.Length == states.Length); _states = states; Steps = steps; - IsCached = !states.IsEmpty && states.All(s => s.IsCached); + IsCached = isCached; HasTrackedSteps = hasTrackedSteps; } public int Count => _states.Length; /// - /// Indicates if every entry in this table has a state of + /// Indicates that this table is unchanged from the previous version. /// public bool IsCached { get; } @@ -126,7 +126,7 @@ public NodeStateTable AsCached() // Ensure we are completely full so that ToImmutable translates to a MoveToImmutable Debug.Assert(compacted.Count == nonRemovedCount); - return new NodeStateTable(compacted.ToImmutableAndFree(), ImmutableArray.Empty, hasTrackedSteps: false); + return new NodeStateTable(compacted.ToImmutableAndFree(), ImmutableArray.Empty, hasTrackedSteps: false, isCached: true); } IStateTable IStateTable.AsCached() => AsCached(); @@ -451,7 +451,8 @@ public NodeStateTable ToImmutableAndFree() return new NodeStateTable( finalStates, TrackIncrementalSteps ? _steps.ToImmutableAndFree() : default, - hasTrackedSteps: TrackIncrementalSteps); + hasTrackedSteps: TrackIncrementalSteps, + isCached: finalStates.All(static s => s.IsCached) && _previous.GetTotalEntryItemCount() == finalStates.Sum(static s => s.Count)); } private static (T chosen, EntryState state, bool chosePrevious) GetModifiedItemAndState(T previous, T replacement, IEqualityComparer comparer) From 6181785d850a75a01f4653b7029d20569289f3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Tue, 11 Apr 2023 16:25:01 -0700 Subject: [PATCH 11/11] Port EnC telemetry improvements to 17.6 (#67752) * Use exception with specific type and HResult to aid tracking in telemetry * Associate rude edits with project id --- .../EditAndContinueLanguageService.cs | 16 +++++--- .../EditAndContinueWorkspaceServiceTests.cs | 40 +++++++++++-------- .../AbstractEditAndContinueAnalyzer.cs | 14 ++++--- .../EditAndContinue/DebuggingSession.cs | 2 +- .../DebuggingSessionTelemetry.cs | 8 +++- .../Portable/EditAndContinue/EditSession.cs | 2 +- .../EditAndContinue/EditSessionTelemetry.cs | 8 ++-- 7 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs index 333f4394d8d40..29230d656dbd9 100644 --- a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs @@ -25,6 +25,16 @@ namespace Microsoft.CodeAnalysis.EditAndContinue [ExportMetadata("UIContext", EditAndContinueUIContext.EncCapableProjectExistsInWorkspaceUIContextString)] internal sealed class EditAndContinueLanguageService : IManagedHotReloadLanguageService, IEditAndContinueSolutionProvider { + private sealed class NoSessionException : InvalidOperationException + { + public NoSessionException() + : base("Internal error: no session.") + { + // unique enough HResult to distinguish from other exceptions + HResult = unchecked((int)0x801315087); + } + } + private readonly PdbMatchingSourceTextProvider _sourceTextProvider; private readonly Lazy _debuggerService; private readonly IDiagnosticAnalyzerService _diagnosticService; @@ -85,11 +95,7 @@ private Solution GetCurrentCompileTimeSolution(Solution? currentDesignTimeSoluti } private RemoteDebuggingSessionProxy GetDebuggingSession() - { - var debuggingSession = _debuggingSession; - Contract.ThrowIfNull(debuggingSession); - return debuggingSession; - } + => _debuggingSession ?? throw new NoSessionException(); private IActiveStatementTrackingService GetActiveStatementTrackingService() => WorkspaceProvider.Value.Workspace.Services.GetRequiredService(); diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 4c183e9773cab..6940acb44a878 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -112,6 +112,22 @@ private static (Solution, Document) AddDefaultTestProject( return (solution, solution.Projects.Single().Documents.Single()); } + private static Project AddEmptyTestProject(Solution solution) + { + var projectId = ProjectId.CreateNewId(); + + return solution. + AddProject(ProjectInfo.Create( + projectId, + VersionStamp.Create(), + "proj", + "proj", + LanguageNames.CSharp, + parseOptions: CSharpParseOptions.Default.WithNoRefSafetyRulesAttribute()) + .WithTelemetryId(s_defaultProjectTelemetryId)).GetProject(projectId). + WithMetadataReferences(TargetFrameworkUtil.GetReferences(DefaultTargetFramework)); + } + private static Solution AddDefaultTestProject( Solution solution, string[] sources, @@ -119,12 +135,7 @@ private static Solution AddDefaultTestProject( string additionalFileText = null, (string key, string value)[] analyzerConfig = null) { - var projectId = ProjectId.CreateNewId(); - - var project = solution. - AddProject(ProjectInfo.Create(projectId, VersionStamp.Create(), "proj", "proj", LanguageNames.CSharp, parseOptions: CSharpParseOptions.Default.WithNoRefSafetyRulesAttribute()).WithTelemetryId(s_defaultProjectTelemetryId)).GetProject(projectId). - WithMetadataReferences(TargetFrameworkUtil.GetReferences(DefaultTargetFramework)); - + var project = AddEmptyTestProject(solution); solution = project.Solution; if (generator != null) @@ -1428,7 +1439,7 @@ public async Task RudeEdits(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } else @@ -1437,7 +1448,7 @@ public async Task RudeEdits(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } } @@ -1563,10 +1574,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) using var _ = CreateWorkspace(out var solution, out var service); - var project = solution. - AddProject("test", "test", LanguageNames.CSharp). - AddMetadataReferences(TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib40)); - + var project = AddEmptyTestProject(solution); solution = project.Solution; // compile with source0: @@ -1645,8 +1653,8 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } else @@ -1655,8 +1663,8 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) { "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=2|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True", - "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True" + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=38|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}", + "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=21|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={00000000-AAAA-AAAA-AAAA-111111111111}" }, _telemetryLog); } } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 2ea77484145e6..8128d166a300c 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2427,16 +2427,16 @@ private async Task> AnalyzeSemanticsAsync( PooledDictionary? instanceConstructorEdits = null; PooledDictionary? staticConstructorEdits = null; - var oldModel = (oldDocument != null) ? await oldDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false) : null; - var newModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var oldCompilation = oldModel?.Compilation ?? await oldProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - var newCompilation = newModel.Compilation; - using var _1 = PooledHashSet.GetInstance(out var processedSymbols); using var _2 = ArrayBuilder.GetInstance(out var semanticEdits); try { + var oldModel = (oldDocument != null) ? await oldDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false) : null; + var newModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var oldCompilation = oldModel?.Compilation ?? await oldProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + var newCompilation = newModel.Compilation; + INamedTypeSymbol? lazyLayoutAttribute = null; foreach (var edit in editScript.Edits) @@ -3324,6 +3324,10 @@ private async Task> AnalyzeSemanticsAsync( cancellationToken); } } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) + { + throw ExceptionUtilities.Unreachable(); + } finally { instanceConstructorEdits?.Free(); diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 61cd18beadb3c..6b8f1c7e8d34c 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -506,7 +506,7 @@ CommittedSolution.DocumentState.Indeterminate or return ImmutableArray.Empty; } - EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors); + EditSession.Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, project.State.Attributes.TelemetryId); // track the document, so that we can refresh or clean diagnostics at the end of edit session: EditSession.TrackDocumentWithReportedDiagnostics(document.Id); diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs index 0366e479042a7..6b2f60ec6c0b3 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs @@ -127,7 +127,7 @@ public static void Log(Data data, Action log, Func map["Capabilities"] = (int)editSessionData.Capabilities; // Ids of all projects whose binaries were successfully updated during the session. - map["ProjectIdsWithAppliedChanges"] = editSessionData.Committed ? editSessionData.ProjectsWithValidDelta.Select(id => new PiiValue(id.ToString("B").ToUpperInvariant())) : ""; + map["ProjectIdsWithAppliedChanges"] = editSessionData.Committed ? editSessionData.ProjectsWithValidDelta.Select(ProjectIdToPii) : ""; })); foreach (var errorId in editSessionData.EmitErrorIds) @@ -140,7 +140,7 @@ public static void Log(Data data, Action log, Func })); } - foreach (var (editKind, syntaxKind) in editSessionData.RudeEdits) + foreach (var (editKind, syntaxKind, projectId) in editSessionData.RudeEdits) { log(FunctionId.Debugging_EncSession_EditSession_RudeEdit, KeyValueLogMessage.Create(map => { @@ -150,8 +150,12 @@ public static void Log(Data data, Action log, Func map["RudeEditKind"] = editKind; map["RudeEditSyntaxKind"] = syntaxKind; map["RudeEditBlocking"] = editSessionData.HadRudeEdits; + map["RudeEditProjectId"] = ProjectIdToPii(projectId); })); } + + static PiiValue ProjectIdToPii(Guid projectId) + => new(projectId.ToString("B").ToUpperInvariant()); } } } diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 9b2f3bddc571c..36deaf267a0ad 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -925,7 +925,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution if (analysis.RudeEditErrors.Length > 0) { documentsWithRudeEdits.Add((analysis.DocumentId, analysis.RudeEditErrors)); - Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors); + Telemetry.LogRudeEditDiagnostics(analysis.RudeEditErrors, newProject.State.Attributes.TelemetryId); } } diff --git a/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs b/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs index c0eb7ceceab3e..aad5c85fdfc9f 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs @@ -15,7 +15,7 @@ internal sealed class EditSessionTelemetry { internal readonly struct Data { - public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind)> RudeEdits; + public readonly ImmutableArray<(ushort EditKind, ushort SyntaxKind, Guid projectId)> RudeEdits; public readonly ImmutableArray EmitErrorIds; public readonly ImmutableArray ProjectsWithValidDelta; public readonly EditAndContinueCapabilities Capabilities; @@ -50,7 +50,7 @@ public Data(EditSessionTelemetry telemetry) // Limit the number of reported items to limit the size of the telemetry event (max total size is 64K). private const int MaxReportedProjectIds = 20; - private readonly HashSet<(ushort, ushort)> _rudeEdits = new(); + private readonly HashSet<(ushort, ushort, Guid)> _rudeEdits = new(); private readonly HashSet _emitErrorIds = new(); private readonly HashSet _projectsWithValidDelta = new(); @@ -129,13 +129,13 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid proje public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid projectTelemetryId, ImmutableArray emitDiagnostics) => LogProjectAnalysisSummary(summary, projectTelemetryId, emitDiagnostics.SelectAsArray(d => d.Severity == DiagnosticSeverity.Error, d => d.Id)); - public void LogRudeEditDiagnostics(ImmutableArray diagnostics) + public void LogRudeEditDiagnostics(ImmutableArray diagnostics, Guid projectTelemetryId) { lock (_guard) { foreach (var diagnostic in diagnostics) { - _rudeEdits.Add(((ushort)diagnostic.Kind, diagnostic.SyntaxKind)); + _rudeEdits.Add(((ushort)diagnostic.Kind, diagnostic.SyntaxKind, projectTelemetryId)); } } }