diff --git a/azure-pipelines-integration.yml b/azure-pipelines-integration.yml
index 87a597c974b14..00a7dc616910e 100644
--- a/azure-pipelines-integration.yml
+++ b/azure-pipelines-integration.yml
@@ -22,14 +22,22 @@ jobs:
strategy:
maxParallel: 2
matrix:
- debug_async:
+ debug_32:
_configuration: Debug
- release_async:
+ _oop64bit: false
+ debug_64:
+ _configuration: Debug
+ _oop64bit: true
+ release_32:
+ _configuration: Release
+ _oop64bit: false
+ release_64:
_configuration: Release
+ _oop64bit: true
timeoutInMinutes: 135
steps:
- - script: eng/cibuild.cmd -configuration $(_configuration) -prepareMachine -testVsi
+ - script: eng/cibuild.cmd -configuration $(_configuration) -prepareMachine -testVsi -oop64bit:$$(_oop64bit)
displayName: Build and Test
- task: PublishTestResults@2
@@ -38,14 +46,14 @@ jobs:
testRunner: XUnit
testResultsFiles: $(Build.SourcesDirectory)\artifacts\TestResults\$(_configuration)\*.xml
mergeTestResults: true
- testRunTitle: '$(System.JobAttempt)-Integration $(_configuration)'
+ testRunTitle: '$(System.JobAttempt)-Integration $(_configuration) OOP64_$(_oop64bit)'
condition: always()
- task: PublishBuildArtifacts@1
displayName: Publish Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(_configuration)'
- ArtifactName: '$(System.JobAttempt)-Logs $(_configuration) $(Build.BuildNumber)'
+ ArtifactName: '$(System.JobAttempt)-Logs $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
@@ -54,7 +62,7 @@ jobs:
displayName: Publish Secondary Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log2\$(_configuration)'
- ArtifactName: '$(System.JobAttempt)-Secondary Logs $(_configuration) $(Build.BuildNumber)'
+ ArtifactName: '$(System.JobAttempt)-Secondary Logs $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
@@ -63,7 +71,7 @@ jobs:
displayName: Publish Screenshots
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\bin\Microsoft.VisualStudio.LanguageServices.IntegrationTests\$(_configuration)\net472\xUnitResults'
- ArtifactName: '$(System.JobAttempt)-Screenshots $(_configuration) $(Build.BuildNumber)'
+ ArtifactName: '$(System.JobAttempt)-Screenshots $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
diff --git a/eng/build.ps1 b/eng/build.ps1
index 333a81660516a..41704096180c8 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -43,6 +43,7 @@ param (
[switch]$useGlobalNuGetCache = $true,
[switch]$warnAsError = $false,
[switch]$sourceBuild = $false,
+ [switch]$oop64bit = $true,
# official build settings
[string]$officialBuildId = "",
@@ -594,6 +595,8 @@ function Setup-IntegrationTestRun() {
# Make sure we can capture a screenshot. An exception at this point will fail-fast the build.
Capture-Screenshot $screenshotPath
}
+
+ $env:ROSLYN_OOP64BIT = "$oop64bit"
}
function Prepare-TempDir() {
diff --git a/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTag.cs b/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTag.cs
index 4f43e0b3131fd..9a78e64674674 100644
--- a/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTag.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTag.cs
@@ -13,12 +13,13 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
-using Microsoft.CodeAnalysis.Text;
+using System.Windows.Media;
using Microsoft.CodeAnalysis.DocumentationComments;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Editor;
@@ -65,11 +66,11 @@ private InlineParameterNameHintsTag(FrameworkElement adornment, ITextView textVi
/// The view of the editor
/// The span that has the location of the hint
/// The symbolkey associated with each parameter
- public static InlineParameterNameHintsTag Create(string text, double lineHeight, TextFormattingRunProperties format,
- ITextView textView, SnapshotSpan span, SymbolKey key,
+ public static InlineParameterNameHintsTag Create(string text, TextFormattingRunProperties format,
+ IWpfTextView textView, SnapshotSpan span, SymbolKey key,
InlineParameterNameHintsTaggerProvider taggerProvider)
{
- return new InlineParameterNameHintsTag(CreateElement(text, lineHeight, format), textView,
+ return new InlineParameterNameHintsTag(CreateElement(text, textView, format), textView,
span, key, taggerProvider);
}
@@ -119,7 +120,7 @@ public async Task> CreateDescriptionAsync(Cancellati
return uiCollection;
}
- private static FrameworkElement CreateElement(string text, double lineHeight, TextFormattingRunProperties format)
+ private static FrameworkElement CreateElement(string text, IWpfTextView textView, TextFormattingRunProperties format)
{
// Constructs the hint block which gets assigned parameter name and fontstyles according to the options
// page. Calculates a font size 1/4 smaller than the font size of the rest of the editor
@@ -145,13 +146,23 @@ private static FrameworkElement CreateElement(string text, double lineHeight, Te
Background = format.BackgroundBrush,
Child = block,
CornerRadius = new CornerRadius(2),
- Height = lineHeight - (0.25 * lineHeight),
+ Height = textView.LineHeight - (0.25 * textView.LineHeight),
HorizontalAlignment = HorizontalAlignment.Center,
- Margin = new Thickness(left: 0, top: -0.20 * lineHeight, right: 5, bottom: 0),
+ Margin = new Thickness(left: 0, top: -0.20 * textView.LineHeight, right: 5, bottom: 0),
Padding = new Thickness(1),
- VerticalAlignment = VerticalAlignment.Center,
+
+ // Need to set SnapsToDevicePixels and UseLayoutRounding to avoid unnecessary reformatting
+ SnapsToDevicePixels = textView.VisualElement.SnapsToDevicePixels,
+ UseLayoutRounding = textView.VisualElement.UseLayoutRounding,
+ VerticalAlignment = VerticalAlignment.Center
};
+ // Need to set these properties to avoid unnecessary reformatting because some dependancy properties
+ // affect layout
+ TextOptions.SetTextFormattingMode(border, TextOptions.GetTextFormattingMode(textView.VisualElement));
+ TextOptions.SetTextHintingMode(border, TextOptions.GetTextHintingMode(textView.VisualElement));
+ TextOptions.SetTextRenderingMode(border, TextOptions.GetTextRenderingMode(textView.VisualElement));
+
border.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
return border;
}
diff --git a/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTagger.cs b/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTagger.cs
index 774324f75f259..277dba7b609c0 100644
--- a/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTagger.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTagger.cs
@@ -6,10 +6,8 @@
using System;
using System.Collections.Generic;
-using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.Text;
-using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
@@ -48,11 +46,11 @@ internal sealed class InlineParameterNameHintsTagger : ITagger? TagsChanged;
- public InlineParameterNameHintsTagger(InlineParameterNameHintsTaggerProvider taggerProvider, ITextView textView, ITextBuffer buffer, ITagAggregator tagAggregator)
+ public InlineParameterNameHintsTagger(InlineParameterNameHintsTaggerProvider taggerProvider, IWpfTextView textView, ITextBuffer buffer, ITagAggregator tagAggregator)
{
_cache = new List>();
@@ -128,7 +126,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSp
{
var dataTagSpan = dataTagSpans[0];
var parameterHintSnapshotSpan = new SnapshotSpan(dataTagSpan.Start, 0);
- var parameterHintUITag = InlineParameterNameHintsTag.Create(textTag.ParameterName, _textView.LineHeight,
+ var parameterHintUITag = InlineParameterNameHintsTag.Create(textTag.ParameterName,
Format, _textView, dataTagSpan, textTag.ParameterSymbolKey, _inlineParameterNameHintsTaggerProvider);
_cache.Add(new TagSpan(parameterHintSnapshotSpan, parameterHintUITag));
diff --git a/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTaggerProvider.cs
index 5902c9c18ff87..fc58cd076cd04 100644
--- a/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTaggerProvider.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineParameterNameHints/InlineParameterNameHintsTaggerProvider.cs
@@ -60,7 +60,7 @@ public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where
}
var tagAggregator = _viewTagAggregatorFactoryService.CreateTagAggregator(textView);
- return new InlineParameterNameHintsTagger(this, textView, buffer, tagAggregator) as ITagger;
+ return new InlineParameterNameHintsTagger(this, (IWpfTextView)textView, buffer, tagAggregator) as ITagger;
}
}
}
diff --git a/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs
new file mode 100644
index 0000000000000..42ba15597de0a
--- /dev/null
+++ b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs
@@ -0,0 +1,190 @@
+// 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.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.DesignerAttribute;
+using Microsoft.CodeAnalysis.ErrorReporting;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.SolutionCrawler;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.DesignerAttribute
+{
+ internal abstract partial class AbstractDesignerAttributeIncrementalAnalyzer : IncrementalAnalyzerBase
+ {
+ private const string DataKey = "DesignerAttributeData";
+
+ private readonly IPersistentStorageService _storageService;
+
+ protected AbstractDesignerAttributeIncrementalAnalyzer(Workspace workspace)
+ {
+ _storageService = workspace.Services.GetRequiredService();
+ }
+
+ protected abstract Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken);
+
+ protected abstract Task ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken);
+
+ public override Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken)
+ => ReportProjectRemovedAsync(projectId, cancellationToken);
+
+ public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken)
+ => AnalyzeProjectAsync(project, specificDocument: null, cancellationToken);
+
+ public override Task AnalyzeDocumentAsync(Document document, SyntaxNode? body, InvocationReasons reasons, CancellationToken cancellationToken)
+ {
+ // don't need to reanalyze file if just a method body was edited. That can't
+ // affect designer attributes.
+ if (body != null)
+ return Task.CompletedTask;
+
+ // When we register our analyzer we will get called into for every document to
+ // 'reanalyze' them all. Ignore those as we would prefer to analyze the project
+ // en-mass.
+ if (reasons.Contains(PredefinedInvocationReasons.Reanalyze))
+ return Task.CompletedTask;
+
+ return AnalyzeProjectAsync(document.Project, document, cancellationToken);
+ }
+
+ private async Task AnalyzeProjectAsync(Project project, Document? specificDocument, CancellationToken cancellationToken)
+ {
+ if (!project.SupportsCompilation)
+ return;
+
+ // We need to reanalyze the project whenever it (or any of its dependencies) have
+ // changed. We need to know about dependencies since if a downstream project adds the
+ // DesignerCategory attribute to a class, that can affect us when we examine the classes
+ // in this project.
+ var projectVersion = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);
+
+ var latestInfos = await ComputeLatestInfosAsync(
+ project, projectVersion, specificDocument, cancellationToken).ConfigureAwait(false);
+
+ // Now get all the values that actually changed and notify VS about them. We don't need
+ // to tell it about the ones that didn't change since that will have no effect on the
+ // user experience.
+ //
+ // ! is safe here as `i.changed` implies `i.info` is non-null.
+ var changedInfos = latestInfos.Where(i => i.changed).Select(i => i.data!.Value).ToList();
+ if (changedInfos.Count > 0)
+ {
+ await ReportDesignerAttributeDataAsync(changedInfos, cancellationToken).ConfigureAwait(false);
+ }
+
+ // now that we've notified VS, persist all the infos we have (changed or otherwise) back
+ // to disk. We want to do this even when the data is unchanged so that our version
+ // stamps will be correct for the next time we come around to analyze this project.
+ //
+ // Note: we have a potential race condition here. Specifically, for simplicity, the VS
+ // side will return immediately, without actually notifying the project system. That
+ // means that we could persist the data to local storage that isn't in sync with what
+ // the project system knows about. i.e. if VS is closed or crashes before that
+ // information is persisted, then these two systems will be in disagreement. this is
+ // believed to not be a big issue given how small a time window this would be and how
+ // easy it would be to get out of that state (just edit the file).
+
+ await PersistLatestInfosAsync(project.Solution, projectVersion, latestInfos, cancellationToken).ConfigureAwait(false);
+ }
+
+ private async Task PersistLatestInfosAsync(
+ Solution solution, VersionStamp projectVersion, (Document, DesignerAttributeData? daa, bool changed)[] latestInfos, CancellationToken cancellationToken)
+ {
+ using var storage = _storageService.GetStorage(solution);
+
+ foreach (var (doc, info, _) in latestInfos)
+ {
+ // Skip documents that didn't change contents/version at all. No point in writing
+ // back out the exact same data as before.
+ if (info == null)
+ continue;
+
+ using var memoryStream = new MemoryStream();
+ using var writer = new ObjectWriter(memoryStream);
+
+ PersistInfoTo(writer, info.Value, projectVersion);
+
+ memoryStream.Position = 0;
+ await storage.WriteStreamAsync(
+ doc, DataKey, memoryStream, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task<(Document, DesignerAttributeData? data, bool changed)[]> ComputeLatestInfosAsync(
+ Project project, VersionStamp projectVersion,
+ Document? specificDocument, CancellationToken cancellationToken)
+ {
+ using var storage = _storageService.GetStorage(project.Solution);
+
+ var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
+ var designerCategoryType = compilation.DesignerCategoryAttributeType();
+
+ using var _ = ArrayBuilder>.GetInstance(out var tasks);
+ foreach (var document in project.Documents)
+ {
+ // If we're only analyzing a specific document, then skip the rest.
+ if (specificDocument != null && document != specificDocument)
+ continue;
+
+ tasks.Add(ComputeDesignerAttributeDataAsync(
+ storage, projectVersion, designerCategoryType, document, cancellationToken));
+ }
+
+ return await Task.WhenAll(tasks).ConfigureAwait(false);
+ }
+
+ private static async Task<(Document, DesignerAttributeData?, bool changed)> ComputeDesignerAttributeDataAsync(
+ IPersistentStorage storage, VersionStamp projectVersion, INamedTypeSymbol? designerCategoryType,
+ Document document, CancellationToken cancellationToken)
+ {
+ try
+ {
+ // If we don't have a path for this document, we cant proceed with it.
+ // We need that path to inform the project system which file we're referring to.
+ if (document.FilePath == null)
+ return default;
+
+ // First check and see if we have stored information for this doc and if that
+ // information is up to date.
+ using var stream = await storage.ReadStreamAsync(document, DataKey, cancellationToken).ConfigureAwait(false);
+ using var reader = ObjectReader.TryGetReader(stream, cancellationToken: cancellationToken);
+ var persisted = TryReadPersistedInfo(reader);
+ if (persisted.category != null && persisted.projectVersion == projectVersion)
+ {
+ // We were able to read out the old data, and it matches our current project
+ // version. Just return back that nothing changed here. We won't tell VS about
+ // this, and we won't re-persist this later.
+ return default;
+ }
+
+ // We either haven't computed the designer info, or our data was out of date. We need
+ // So recompute here. Figure out what the current category is, and if that's different
+ // from what we previously stored.
+ var category = await DesignerAttributeHelpers.ComputeDesignerAttributeCategoryAsync(
+ designerCategoryType, document, cancellationToken).ConfigureAwait(false);
+ var data = new DesignerAttributeData
+ {
+ Category = category,
+ DocumentId = document.Id,
+ FilePath = document.FilePath,
+ };
+
+ return (document, data, changed: category != persisted.category);
+ }
+ catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
+ {
+ return default;
+ }
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer_Serialization.cs b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer_Serialization.cs
similarity index 94%
rename from src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer_Serialization.cs
rename to src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer_Serialization.cs
index 29d4b94947c62..9155f0a20cfe7 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer_Serialization.cs
+++ b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer_Serialization.cs
@@ -9,9 +9,9 @@
using Microsoft.CodeAnalysis.ErrorReporting;
using Roslyn.Utilities;
-namespace Microsoft.CodeAnalysis.Remote
+namespace Microsoft.CodeAnalysis.DesignerAttribute
{
- internal partial class RemoteDesignerAttributeIncrementalAnalyzer
+ internal partial class AbstractDesignerAttributeIncrementalAnalyzer
{
///
/// Our current serialization format. Increment whenever it changes so that we don't read
diff --git a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs
new file mode 100644
index 0000000000000..a91157e8b5b3b
--- /dev/null
+++ b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs
@@ -0,0 +1,89 @@
+// 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.
+
+#nullable enable
+
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments;
+using Microsoft.CodeAnalysis.Options;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.SolutionCrawler;
+
+namespace Microsoft.CodeAnalysis.TodoComments
+{
+ internal abstract partial class AbstractTodoCommentsIncrementalAnalyzer : IncrementalAnalyzerBase
+ {
+ private readonly object _gate = new object();
+ private string? _lastOptionText = null;
+ private ImmutableArray _lastDescriptors = default;
+
+ protected AbstractTodoCommentsIncrementalAnalyzer()
+ {
+ }
+
+ protected abstract Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken);
+
+ public override bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e)
+ => e.Option == TodoCommentOptions.TokenList;
+
+ public override Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken)
+ {
+ // Just report this back as there being no more comments for this document.
+ return ReportTodoCommentDataAsync(documentId, ImmutableArray.Empty, cancellationToken);
+ }
+
+ private ImmutableArray GetTodoCommentDescriptors(Document document)
+ {
+ var optionText = document.Project.Solution.Options.GetOption(TodoCommentOptions.TokenList);
+
+ lock (_gate)
+ {
+ if (optionText != _lastOptionText)
+ {
+ _lastDescriptors = TodoCommentDescriptor.Parse(optionText);
+ _lastOptionText = optionText;
+ }
+
+ return _lastDescriptors;
+ }
+ }
+
+ public override async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken)
+ {
+ var todoCommentService = document.GetLanguageService();
+ if (todoCommentService == null)
+ return;
+
+ var descriptors = GetTodoCommentDescriptors(document);
+
+ // We're out of date. Recompute this info.
+ var todoComments = await todoCommentService.GetTodoCommentsAsync(
+ document, descriptors, cancellationToken).ConfigureAwait(false);
+
+ // Convert the roslyn-level results to the more VS oriented line/col data.
+ using var _ = ArrayBuilder.GetInstance(out var converted);
+ await ConvertAsync(
+ document, todoComments, converted, cancellationToken).ConfigureAwait(false);
+
+ // Now inform VS about this new information
+ await ReportTodoCommentDataAsync(document.Id, converted.ToImmutable(), cancellationToken).ConfigureAwait(false);
+ }
+
+ private static async Task ConvertAsync(
+ Document document,
+ ImmutableArray todoComments,
+ ArrayBuilder converted,
+ CancellationToken cancellationToken)
+ {
+ var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
+ var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
+
+ foreach (var comment in todoComments)
+ converted.Add(comment.CreateSerializableData(document, sourceText, syntaxTree));
+ }
+ }
+}
diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml
index 6d753064edced..06bee807237e7 100644
--- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml
+++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml
@@ -29,6 +29,8 @@
+ ServicesVSResources.Enable_navigation_to_decompiled_sources;
+ public static string Option_use_64bit_analysis_process
+ => ServicesVSResources.Use_64_bit_process_for_code_analysis_requires_restart;
+
public static string Option_Display_inline_parameter_name_hints
=> ServicesVSResources.Display_inline_parameter_name_hints;
diff --git a/src/VisualStudio/Core/Def/ExternalAccess/UnitTesting/Api/UnitTestingRemoteHostOptionsAccessor.cs b/src/VisualStudio/Core/Def/ExternalAccess/UnitTesting/Api/UnitTestingRemoteHostOptionsAccessor.cs
index 8ca0d49008af3..84a7c1bbc2591 100644
--- a/src/VisualStudio/Core/Def/ExternalAccess/UnitTesting/Api/UnitTestingRemoteHostOptionsAccessor.cs
+++ b/src/VisualStudio/Core/Def/ExternalAccess/UnitTesting/Api/UnitTestingRemoteHostOptionsAccessor.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.Linq;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote;
@@ -9,10 +10,8 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api
{
internal static class UnitTestingRemoteHostOptionsAccessor
{
- private const string LocalRegistryPath = @"Roslyn\Internal\RemoteServices\";
-
public static Option OOP64Bit => new Option(
- nameof(RemoteHostOptions), nameof(OOP64Bit), defaultValue: false,
- storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OOP64Bit)));
+ RemoteHostOptions.OOP64Bit.Feature, RemoteHostOptions.OOP64Bit.Name, defaultValue: RemoteHostOptions.OOP64Bit.DefaultValue,
+ storageLocations: RemoteHostOptions.OOP64Bit.StorageLocations.ToArray());
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzer.cs b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzer.cs
new file mode 100644
index 0000000000000..7ae9157b36202
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzer.cs
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.DesignerAttribute;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
+{
+ internal sealed class InProcDesignerAttributeIncrementalAnalyzer : AbstractDesignerAttributeIncrementalAnalyzer
+ {
+ private readonly IDesignerAttributeListener _listener;
+
+ public InProcDesignerAttributeIncrementalAnalyzer(Workspace workspace, IDesignerAttributeListener listener)
+ : base(workspace)
+ {
+ _listener = listener;
+ }
+
+ protected override Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken)
+ => _listener.OnProjectRemovedAsync(projectId, cancellationToken);
+
+ protected override Task ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken)
+ => _listener.ReportDesignerAttributeDataAsync(data.ToImmutableArray(), cancellationToken);
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzerProvider.cs b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzerProvider.cs
new file mode 100644
index 0000000000000..7ff4fb0884adc
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzerProvider.cs
@@ -0,0 +1,28 @@
+// 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 Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.DesignerAttribute;
+using Microsoft.CodeAnalysis.SolutionCrawler;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute
+{
+ /// Note: this is explicitly not exported. We don't want the Workspace
+ /// to automatically load this. Instead, VS waits until it is ready
+ /// and then calls into the service to tell it to start analyzing the solution. At that point we'll get
+ /// created and added to the solution crawler.
+ ///
+ internal sealed class InProcDesignerAttributeIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider
+ {
+ private readonly IDesignerAttributeListener _listener;
+
+ public InProcDesignerAttributeIncrementalAnalyzerProvider(IDesignerAttributeListener listener)
+ {
+ _listener = listener;
+ }
+
+ public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace)
+ => new InProcDesignerAttributeIncrementalAnalyzer(workspace, _listener);
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
index 9c29ba92c59d9..1e28a1f8879c7 100644
--- a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
@@ -21,6 +21,7 @@
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.TestHooks;
+using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.VisualStudio.Designer.Interfaces;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell.Interop;
@@ -114,7 +115,10 @@ private async Task StartWorkerAsync(CancellationToken cancellationToken)
var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false);
if (client == null)
+ {
+ StartScanningForDesignerAttributesInCurrentProcess(cancellationToken);
return;
+ }
// Pass ourselves in as the callback target for the OOP service. As it discovers
// designer attributes it will call back into us to notify VS about it.
@@ -130,6 +134,19 @@ await _connection.RunRemoteAsync(
cancellationToken).ConfigureAwait(false);
}
+ public void StartScanningForDesignerAttributesInCurrentProcess(CancellationToken cancellation)
+ {
+ var registrationService = _workspace.Services.GetRequiredService();
+ var analyzerProvider = new InProcDesignerAttributeIncrementalAnalyzerProvider(this);
+
+ registrationService.AddAnalyzerProvider(
+ analyzerProvider,
+ new IncrementalAnalyzerProviderMetadata(
+ nameof(InProcDesignerAttributeIncrementalAnalyzerProvider),
+ highPriorityForActiveFile: false,
+ workspaceKinds: WorkspaceKind.Host));
+ }
+
private async Task NotifyProjectSystemAsync(
ImmutableArray data, CancellationToken cancellationToken)
{
diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/DefaultRemoteHostClientProvider.cs b/src/VisualStudio/Core/Def/Implementation/Remote/DefaultRemoteHostClientProvider.cs
new file mode 100644
index 0000000000000..662925a48762b
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/Remote/DefaultRemoteHostClientProvider.cs
@@ -0,0 +1,26 @@
+// 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.
+
+#nullable enable
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Remote;
+using Roslyn.Utilities;
+
+namespace Microsoft.VisualStudio.LanguageServices.Remote
+{
+ internal sealed class DefaultRemoteHostClientProvider : IRemoteHostClientProvider
+ {
+ [Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
+ public DefaultRemoteHostClientProvider()
+ {
+ }
+
+ public Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken)
+ => SpecializedTasks.Null();
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs b/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs
index 68329e7172ff0..8eb21289dbfbb 100644
--- a/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs
@@ -28,14 +28,24 @@ public Factory()
{
}
+ [Obsolete(MefConstruction.FactoryMethodMessage, error: true)]
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
- => new VisualStudioRemoteHostClientProvider(workspaceServices);
+ {
+ if (!RemoteHostOptions.IsUsingServiceHubOutOfProcess(workspaceServices)
+ || workspaceServices.Workspace is not VisualStudioWorkspace)
+ {
+ // Run code in the current process
+ return new DefaultRemoteHostClientProvider();
+ }
+
+ return new VisualStudioRemoteHostClientProvider(workspaceServices);
+ }
}
private readonly HostWorkspaceServices _services;
private readonly AsyncLazy _lazyClient;
- public VisualStudioRemoteHostClientProvider(HostWorkspaceServices services)
+ private VisualStudioRemoteHostClientProvider(HostWorkspaceServices services)
{
_services = services;
_lazyClient = new AsyncLazy(CreateHostClientAsync, cacheResult: true);
@@ -60,6 +70,6 @@ await client.RunRemoteAsync(
}
public Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken)
- => (_services.Workspace is VisualStudioWorkspace) ? _lazyClient.GetValueAsync(cancellationToken).AsNullable() : SpecializedTasks.Null();
+ => _lazyClient.GetValueAsync(cancellationToken).AsNullable();
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs
new file mode 100644
index 0000000000000..ffced79472572
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs
@@ -0,0 +1,25 @@
+// 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.
+
+#nullable enable
+
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.TodoComments;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments
+{
+ internal sealed class InProcTodoCommentsIncrementalAnalyzer : AbstractTodoCommentsIncrementalAnalyzer
+ {
+ private readonly ITodoCommentsListener _listener;
+
+ public InProcTodoCommentsIncrementalAnalyzer(ITodoCommentsListener listener)
+ => _listener = listener;
+
+ protected override Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken)
+ => _listener.ReportTodoCommentDataAsync(documentId, data, cancellationToken);
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzerProvider.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzerProvider.cs
new file mode 100644
index 0000000000000..d866a9c0ec915
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzerProvider.cs
@@ -0,0 +1,28 @@
+// 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.
+
+#nullable enable
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.SolutionCrawler;
+using Microsoft.CodeAnalysis.TodoComments;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments
+{
+ /// Note: this is explicitly not exported. We don't want the workspace
+ /// to automatically load this. Instead, VS waits until it is ready
+ /// and then calls into the service to tell it to start analyzing the solution. At that point we'll get
+ /// created and added to the solution crawler.
+ ///
+ internal sealed class InProcTodoCommentsIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider
+ {
+ private readonly ITodoCommentsListener _listener;
+
+ public InProcTodoCommentsIncrementalAnalyzerProvider(ITodoCommentsListener listener)
+ => _listener = listener;
+
+ public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace)
+ => new InProcTodoCommentsIncrementalAnalyzer(_listener);
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
index e83f57821ea3a..39fcc7156d0b0 100644
--- a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
@@ -21,6 +21,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.TodoComments;
using Microsoft.VisualStudio.LanguageServices.ExternalAccess.VSTypeScript.Api;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
@@ -101,7 +102,10 @@ private async Task StartWorkerAsync(CancellationToken cancellationToken)
var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false);
if (client == null)
+ {
+ ComputeTodoCommentsInCurrentProcess(cancellationToken);
return;
+ }
// Pass ourselves in as the callback target for the OOP service. As it discovers
// todo comments it will call back into us to notify VS about it.
@@ -120,6 +124,19 @@ await _connection.RunRemoteAsync(
cancellationToken).ConfigureAwait(false);
}
+ private void ComputeTodoCommentsInCurrentProcess(CancellationToken cancellationToken)
+ {
+ var registrationService = _workspace.Services.GetRequiredService();
+ var analyzerProvider = new InProcTodoCommentsIncrementalAnalyzerProvider(this);
+
+ registrationService.AddAnalyzerProvider(
+ analyzerProvider,
+ new IncrementalAnalyzerProviderMetadata(
+ nameof(InProcTodoCommentsIncrementalAnalyzerProvider),
+ highPriorityForActiveFile: false,
+ workspaceKinds: WorkspaceKind.Host));
+ }
+
private Task ProcessTodoCommentInfosAsync(
ImmutableArray docAndCommentsArray, CancellationToken cancellationToken)
{
diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx
index 2d4efb29171ac..e871d21ef6363 100644
--- a/src/VisualStudio/Core/Def/ServicesVSResources.resx
+++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx
@@ -1532,4 +1532,7 @@ I agree to all of the foregoing:
64-bit
+
+ Use 64-bit process for code analysis (requires restart)
+
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf
index 4116d596814a6..e85724a5036b2 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf
@@ -802,6 +802,11 @@
Aktualizuje se závažnost.
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Pro výrazy lambda používat text výrazu
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf
index 7211ef460a88d..c225c18360fd3 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf
@@ -802,6 +802,11 @@
Der Schweregrad wird aktualisiert.
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Ausdruckskörper für Lambdaausdrücke verwenden
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf
index b21cee3da316d..1e2c843fb3a3e 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf
@@ -802,6 +802,11 @@
Actualizando la gravedad
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Usar cuerpo de expresión para lambdas
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf
index d195a28d98feb..6e14c2be671f0 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf
@@ -802,6 +802,11 @@
Mise à jour de la gravité
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Utiliser un corps d'expression pour les expressions lambda
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf
index f02afccd4ccec..219281382d10d 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf
@@ -802,6 +802,11 @@
Aggiornamento della gravità
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Usa il corpo dell'espressione per le espressioni lambda
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf
index dc71d2c7b1c06..d260d62ab7f64 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf
@@ -802,6 +802,11 @@
重要度を更新しています
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ ラムダに式本体を使用します
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf
index 90f7e75c5fcbc..a06da8b676ded 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf
@@ -802,6 +802,11 @@
심각도를 업데이트하는 중
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ 람다에 식 본문 사용
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf
index 991ce5c5b2cc1..20a0c90f2566b 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf
@@ -802,6 +802,11 @@
Aktualizowanie ważności
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Użyj treści wyrażenia dla wyrażeń lambda
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf
index ca479e03e6cb3..76ec37967a169 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf
@@ -802,6 +802,11 @@
Atualizando a severidade
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Usar o corpo da expressão para lambdas
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf
index 349118bac0964..d420d0c031b91 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf
@@ -802,6 +802,11 @@
Обновление уровня серьезности
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Использовать тело выражения для лямбда-выражений
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf
index 7ad37e8615ca1..6449db3897263 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf
@@ -802,6 +802,11 @@
Önem derecesi güncelleştiriliyor
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ Lambdalar için ifade gövdesi kullan
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf
index b916017b03dd5..b0c7631b5e3ca 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf
@@ -802,6 +802,11 @@
正在更新严重性
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ 使用 lambdas 的表达式主体
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf
index 1aef149101426..42ac7c3f4dc4f 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf
@@ -802,6 +802,11 @@
正在更新嚴重性
+
+
+ Use 64-bit process for code analysis (requires restart)
+
+ 使用 lambda 的運算式主體
diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs
index 8a83992105dd8..0dea824e6bc37 100644
--- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs
+++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs
@@ -340,6 +340,12 @@ private static Process StartNewVisualStudioProcess(string installationPath, int
// custom handler or fail silently and continue testing.
Process.Start(CreateSilentStartInfo(vsRegEditExeFile, $"set \"{installationPath}\" {Settings.Default.VsRootSuffix} HKCU \"Text Editor\" \"Report Exceptions\" dword 0")).WaitForExit();
+ // Configure RemoteHostOptions.OOP64Bit for testing
+ if (string.Equals(Environment.GetEnvironmentVariable("ROSLYN_OOP64BIT"), "false", StringComparison.OrdinalIgnoreCase))
+ {
+ Process.Start(CreateSilentStartInfo(vsRegEditExeFile, $"set \"{installationPath}\" {Settings.Default.VsRootSuffix} HKCU \"Roslyn\\Internal\\OnOff\\Features\" OOP64Bit dword 0")).WaitForExit();
+ }
+
_firstLaunch = false;
}
diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml
index 25574137a8311..9e6f8945a85c4 100644
--- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml
+++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml
@@ -28,6 +28,8 @@
x:Name="Background_analysis_scope_full_solution"
Content="{x:Static local:AdvancedOptionPageStrings.Option_Background_Analysis_Scope_Full_Solution}"/>
+
+
+
diff --git a/src/Workspaces/Remote/Core/RemoteHostOptions.cs b/src/Workspaces/Remote/Core/RemoteHostOptions.cs
index 445af2ed5fa8e..1eb6883bd5d5d 100644
--- a/src/Workspaces/Remote/Core/RemoteHostOptions.cs
+++ b/src/Workspaces/Remote/Core/RemoteHostOptions.cs
@@ -5,7 +5,6 @@
using System;
using System.Collections.Immutable;
using System.Composition;
-using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
@@ -30,13 +29,40 @@ internal static class RemoteHostOptions
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(SolutionChecksumMonitorBackOffTimeSpanInMS)));
// use 64bit OOP
- public static readonly Option OOP64Bit = new Option(
- FeatureName, nameof(OOP64Bit), defaultValue: false,
+ public static readonly Option2 OOP64Bit = new Option2(
+ FeatureName, nameof(OOP64Bit), defaultValue: true,
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OOP64Bit)));
+ // Override 64-bit OOP option to force use of a 32-bit process. This option exists as a registry-based
+ // workaround for cases where the new 64-bit mode fails and 32-bit in-process fails to provide a viable
+ // fallback.
+ public static readonly Option2 OOP32BitOverride = new Option2(
+ FeatureName, nameof(OOP32BitOverride), defaultValue: false,
+ storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OOP32BitOverride)));
+
public static bool IsServiceHubProcess64Bit(HostWorkspaceServices services)
- => services.GetRequiredService().GetOption(OOP64Bit) ||
- services.GetRequiredService().IsExperimentEnabled(WellKnownExperimentNames.RoslynOOP64bit);
+ => IsUsingServiceHubOutOfProcess(services) && !services.GetRequiredService().GetOption(OOP32BitOverride);
+
+ ///
+ /// Determines whether ServiceHub out-of-process execution is enabled for Roslyn.
+ ///
+ public static bool IsUsingServiceHubOutOfProcess(HostWorkspaceServices services)
+ {
+ var optionService = services.GetRequiredService();
+ if (Environment.Is64BitOperatingSystem && optionService.GetOption(OOP64Bit))
+ {
+ // OOP64Bit is set and supported
+ return true;
+ }
+
+ if (optionService.GetOption(OOP32BitOverride))
+ {
+ // Hidden fallback to 32-bit OOP is set
+ return true;
+ }
+
+ return false;
+ }
}
[ExportOptionProvider, Shared]
diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs
index c775ca3a2d0d7..f98a5fde47d91 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs
@@ -4,39 +4,27 @@
#nullable enable
-using System;
-using System.IO;
-using System.Linq;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.DesignerAttribute;
-using Microsoft.CodeAnalysis.ErrorReporting;
-using Microsoft.CodeAnalysis.Host;
-using Microsoft.CodeAnalysis.PooledObjects;
-using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.CodeAnalysis.SolutionCrawler;
-using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote
{
- internal sealed partial class RemoteDesignerAttributeIncrementalAnalyzer : IncrementalAnalyzerBase
+ internal sealed class RemoteDesignerAttributeIncrementalAnalyzer : AbstractDesignerAttributeIncrementalAnalyzer
{
- private const string DataKey = "DesignerAttributeData";
-
///
/// Channel back to VS to inform it of the designer attributes we discover.
///
private readonly RemoteEndPoint _endPoint;
- private readonly IPersistentStorageService _storageService;
-
public RemoteDesignerAttributeIncrementalAnalyzer(Workspace workspace, RemoteEndPoint endPoint)
+ : base(workspace)
{
_endPoint = endPoint;
- _storageService = workspace.Services.GetRequiredService();
}
- public override Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken)
+ protected override Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken)
{
return _endPoint.InvokeAsync(
nameof(IDesignerAttributeListener.OnProjectRemovedAsync),
@@ -44,156 +32,12 @@ public override Task RemoveProjectAsync(ProjectId projectId, CancellationToken c
cancellationToken);
}
- public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken)
- => AnalyzeProjectAsync(project, specificDocument: null, cancellationToken);
-
- public override Task AnalyzeDocumentAsync(Document document, SyntaxNode? body, InvocationReasons reasons, CancellationToken cancellationToken)
- {
- // don't need to reanalyze file if just a method body was edited. That can't
- // affect designer attributes.
- if (body != null)
- return Task.CompletedTask;
-
- // When we register our analyzer we will get called into for every document to
- // 'reanalyze' them all. Ignore those as we would prefer to analyze the project
- // en-mass.
- if (reasons.Contains(PredefinedInvocationReasons.Reanalyze))
- return Task.CompletedTask;
-
- return AnalyzeProjectAsync(document.Project, document, cancellationToken);
- }
-
- private async Task AnalyzeProjectAsync(Project project, Document? specificDocument, CancellationToken cancellationToken)
- {
- if (!project.SupportsCompilation)
- return;
-
- // We need to reanalyze the project whenever it (or any of its dependencies) have
- // changed. We need to know about dependencies since if a downstream project adds the
- // DesignerCategory attribute to a class, that can affect us when we examine the classes
- // in this project.
- var projectVersion = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);
-
- var latestInfos = await ComputeLatestInfosAsync(
- project, projectVersion, specificDocument, cancellationToken).ConfigureAwait(false);
-
- // Now get all the values that actually changed and notify VS about them. We don't need
- // to tell it about the ones that didn't change since that will have no effect on the
- // user experience.
- //
- // ! is safe here as `i.changed` implies `i.info` is non-null.
- var changedInfos = latestInfos.Where(i => i.changed).Select(i => i.data!.Value).ToList();
- if (changedInfos.Count > 0)
- {
- await _endPoint.InvokeAsync(
- nameof(IDesignerAttributeListener.ReportDesignerAttributeDataAsync),
- new object[] { changedInfos },
- cancellationToken).ConfigureAwait(false);
- }
-
- // now that we've notified VS, persist all the infos we have (changed or otherwise) back
- // to disk. We want to do this even when the data is unchanged so that our version
- // stamps will be correct for the next time we come around to analyze this project.
- //
- // Note: we have a potential race condition here. Specifically, for simplicity, the VS
- // side will return immediately, without actually notifying the project system. That
- // means that we could persist the data to local storage that isn't in sync with what
- // the project system knows about. i.e. if VS is closed or crashes before that
- // information is persisted, then these two systems will be in disagreement. this is
- // believed to not be a big issue given how small a time window this would be and how
- // easy it would be to get out of that state (just edit the file).
-
- await PersistLatestInfosAsync(project.Solution, projectVersion, latestInfos, cancellationToken).ConfigureAwait(false);
- }
-
- private async Task PersistLatestInfosAsync(
- Solution solution, VersionStamp projectVersion, (Document, DesignerAttributeData? daa, bool changed)[] latestInfos, CancellationToken cancellationToken)
+ protected override Task ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken)
{
- using var storage = _storageService.GetStorage(solution);
-
- foreach (var (doc, info, _) in latestInfos)
- {
- // Skip documents that didn't change contents/version at all. No point in writing
- // back out the exact same data as before.
- if (info == null)
- continue;
-
- using var memoryStream = new MemoryStream();
- using var writer = new ObjectWriter(memoryStream);
-
- PersistInfoTo(writer, info.Value, projectVersion);
-
- memoryStream.Position = 0;
- await storage.WriteStreamAsync(
- doc, DataKey, memoryStream, cancellationToken).ConfigureAwait(false);
- }
- }
-
- private async Task<(Document, DesignerAttributeData? data, bool changed)[]> ComputeLatestInfosAsync(
- Project project, VersionStamp projectVersion,
- Document? specificDocument, CancellationToken cancellationToken)
- {
- using var storage = _storageService.GetStorage(project.Solution);
-
- var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
- var designerCategoryType = compilation.DesignerCategoryAttributeType();
-
- using var _ = ArrayBuilder>.GetInstance(out var tasks);
- foreach (var document in project.Documents)
- {
- // If we're only analyzing a specific document, then skip the rest.
- if (specificDocument != null && document != specificDocument)
- continue;
-
- tasks.Add(ComputeDesignerAttributeDataAsync(
- storage, projectVersion, designerCategoryType, document, cancellationToken));
- }
-
- return await Task.WhenAll(tasks).ConfigureAwait(false);
- }
-
- private static async Task<(Document, DesignerAttributeData?, bool changed)> ComputeDesignerAttributeDataAsync(
- IPersistentStorage storage, VersionStamp projectVersion, INamedTypeSymbol? designerCategoryType,
- Document document, CancellationToken cancellationToken)
- {
- try
- {
- // If we don't have a path for this document, we cant proceed with it.
- // We need that path to inform the project system which file we're referring to.
- if (document.FilePath == null)
- return default;
-
- // First check and see if we have stored information for this doc and if that
- // information is up to date.
- using var stream = await storage.ReadStreamAsync(document, DataKey, cancellationToken).ConfigureAwait(false);
- using var reader = ObjectReader.TryGetReader(stream, cancellationToken: cancellationToken);
- var persisted = TryReadPersistedInfo(reader);
- if (persisted.category != null && persisted.projectVersion == projectVersion)
- {
- // We were able to read out the old data, and it matches our current project
- // version. Just return back that nothing changed here. We won't tell VS about
- // this, and we won't re-persist this later.
- return default;
- }
-
- // We either haven't computed the designer info, or our data was out of date. We need
- // So recompute here. Figure out what the current category is, and if that's different
- // from what we previously stored.
- var category = await DesignerAttributeHelpers.ComputeDesignerAttributeCategoryAsync(
- designerCategoryType, document, cancellationToken).ConfigureAwait(false);
- var data = new DesignerAttributeData
- {
- Category = category,
- DocumentId = document.Id,
- FilePath = document.FilePath,
- };
-
- return (document, data, changed: category != persisted.category);
- }
- catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e))
- {
- return default;
- }
+ return _endPoint.InvokeAsync(
+ nameof(IDesignerAttributeListener.ReportDesignerAttributeDataAsync),
+ new object[] { data },
+ cancellationToken);
}
}
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs
index faf9f9f6b241c..3b5caf13be6b6 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs
@@ -4,99 +4,29 @@
#nullable enable
-using System;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments;
-using Microsoft.CodeAnalysis.Host;
-using Microsoft.CodeAnalysis.Options;
-using Microsoft.CodeAnalysis.PooledObjects;
-using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.TodoComments;
namespace Microsoft.CodeAnalysis.Remote
{
- internal partial class RemoteTodoCommentsIncrementalAnalyzer : IncrementalAnalyzerBase
+ internal sealed class RemoteTodoCommentsIncrementalAnalyzer : AbstractTodoCommentsIncrementalAnalyzer
{
- private const string DataKey = "TodoComment";
-
///
/// Channel back to VS to inform it of the designer attributes we discover.
///
private readonly RemoteEndPoint _endPoint;
- private readonly object _gate = new object();
- private string? _lastOptionText = null;
- private ImmutableArray _lastDescriptors = default;
-
public RemoteTodoCommentsIncrementalAnalyzer(RemoteEndPoint endPoint)
=> _endPoint = endPoint;
- public override bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e)
- => e.Option == TodoCommentOptions.TokenList;
-
- public override Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken)
+ protected override Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken)
{
- // Just report this back as there being no more comments for this document.
return _endPoint.InvokeAsync(
nameof(ITodoCommentsListener.ReportTodoCommentDataAsync),
- new object[] { documentId, Array.Empty() },
+ new object[] { documentId, data },
cancellationToken);
}
-
- private ImmutableArray GetTodoCommentDescriptors(Document document)
- {
- var optionText = document.Project.Solution.Options.GetOption(TodoCommentOptions.TokenList);
-
- lock (_gate)
- {
- if (optionText != _lastOptionText)
- {
- _lastDescriptors = TodoCommentDescriptor.Parse(optionText);
- _lastOptionText = optionText;
- }
-
- return _lastDescriptors;
- }
- }
-
- public override async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken)
- {
- var todoCommentService = document.GetLanguageService();
- if (todoCommentService == null)
- return;
-
- var descriptors = GetTodoCommentDescriptors(document);
-
- // We're out of date. Recompute this info.
- var todoComments = await todoCommentService.GetTodoCommentsAsync(
- document, descriptors, cancellationToken).ConfigureAwait(false);
-
- // Convert the roslyn-level results to the more VS oriented line/col data.
- using var _ = ArrayBuilder.GetInstance(out var converted);
- await ConvertAsync(
- document, todoComments, converted, cancellationToken).ConfigureAwait(false);
-
- // Now inform VS about this new information
- await _endPoint.InvokeAsync(
- nameof(ITodoCommentsListener.ReportTodoCommentDataAsync),
- new object[] { document.Id, converted },
- cancellationToken).ConfigureAwait(false);
- }
-
- private static async Task ConvertAsync(
- Document document,
- ImmutableArray todoComments,
- ArrayBuilder converted,
- CancellationToken cancellationToken)
- {
- var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
- var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
-
- foreach (var comment in todoComments)
- converted.Add(comment.CreateSerializableData(document, sourceText, syntaxTree));
- }
}
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs
index c8a6a72cc7fec..c75616fb64c01 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs
@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Remote
/// and then calls into OOP to tell it to start analyzing the solution. At that point we'll get
/// created and added to the solution crawler.
///
- internal class RemoteTodoCommentsIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider
+ internal sealed class RemoteTodoCommentsIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider
{
private readonly RemoteEndPoint _endPoint;