提交 e846ff7a 编写于 作者: H Heejae Chang

stop exposing Workspace from WorkspaceAnalyzerOptions.

exposing workspace directly cause people to depends on data/service analyzer is not supposed to depend on, also, it sometime access mutable data instead of snapshot of it which analyzer is not supposed to use.

this cut the connection, and expose specific info analyzer is allowed to use in IDE case.
上级 c7856e8f
......@@ -120,28 +120,15 @@ public static string GetAnalyzerAssemblyName(this DiagnosticAnalyzer analyzer)
return typeInfo.Assembly.GetName().Name;
}
public static async Task<OptionSet> GetDocumentOptionSetAsync(this AnalyzerOptions analyzerOptions, SyntaxTree syntaxTree, CancellationToken cancellationToken)
public static Task<OptionSet> GetDocumentOptionSetAsync(this AnalyzerOptions analyzerOptions, SyntaxTree syntaxTree, CancellationToken cancellationToken)
{
var workspace = (analyzerOptions as WorkspaceAnalyzerOptions)?.Workspace;
if (workspace == null)
var workspaceAnalyzerOptions = analyzerOptions as WorkspaceAnalyzerOptions;
if (workspaceAnalyzerOptions == null)
{
return null;
}
var documentId = workspace.CurrentSolution.GetDocumentId(syntaxTree);
if (documentId == null)
{
return workspace.Options;
}
var document = workspace.CurrentSolution.GetDocument(documentId);
if (document == null)
{
return workspace.Options;
return SpecializedTasks.Default<OptionSet>();
}
var documentOptionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
return documentOptionSet ?? workspace.Options;
return workspaceAnalyzerOptions.GetDocumentOptionSetAsync(syntaxTree, cancellationToken);
}
internal static void OnAnalyzerException_NoTelemetryLogging(
......
......@@ -118,7 +118,7 @@ public Task<CompilationWithAnalyzers> CreateAnalyzerDriverAsync(Project project,
// in IDE, we always set concurrentAnalysis == false otherwise, we can get into thread starvation due to
// async being used with syncronous blocking concurrency.
return new CompilationWithAnalyzersOptions(
options: new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution.Workspace),
options: new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution.Workspace, project.Solution.Options),
onAnalyzerException: GetOnAnalyzerException(project.Id),
analyzerExceptionFilter: GetAnalyzerExceptionFilter(project),
concurrentAnalysis: false,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
......@@ -10,13 +14,35 @@ namespace Microsoft.CodeAnalysis.Diagnostics
/// </summary>
internal sealed class WorkspaceAnalyzerOptions : AnalyzerOptions
{
public WorkspaceAnalyzerOptions(AnalyzerOptions options, Workspace workspace)
private readonly Workspace _workspace;
private readonly OptionSet _optionSet;
public WorkspaceAnalyzerOptions(AnalyzerOptions options, Workspace workspace, OptionSet optionSet)
: base(options.AdditionalFiles)
{
this.Workspace = workspace;
_workspace = workspace;
_optionSet = optionSet;
}
public Workspace Workspace { get; }
public HostWorkspaceServices Services => _workspace.Services;
public async Task<OptionSet> GetDocumentOptionSetAsync(SyntaxTree syntaxTree, CancellationToken cancellationToken)
{
var documentId = _workspace.CurrentSolution.GetDocumentId(syntaxTree);
if (documentId == null)
{
return _optionSet;
}
var document = _workspace.CurrentSolution.GetDocument(documentId);
if (document == null)
{
return _optionSet;
}
var documentOptionSet = await document.GetOptionsAsync(_optionSet, cancellationToken).ConfigureAwait(false);
return documentOptionSet ?? _optionSet;
}
public override bool Equals(object obj)
{
......@@ -27,13 +53,13 @@ public override bool Equals(object obj)
var other = obj as WorkspaceAnalyzerOptions;
return other != null &&
this.Workspace == other.Workspace &&
_workspace == other._workspace &&
base.Equals(other);
}
public override int GetHashCode()
{
return Hash.Combine(this.Workspace, base.GetHashCode());
return Hash.Combine(_workspace, base.GetHashCode());
}
}
}
......@@ -69,9 +69,8 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
return;
}
var workspace = workspaceOptions.Workspace;
var service = workspace.Services.GetLanguageServices(context.SemanticModel.Compilation.Language)
.GetService<IUnnecessaryImportsService>();
var service = workspaceOptions.Services.GetLanguageServices(context.SemanticModel.Compilation.Language)
.GetService<IUnnecessaryImportsService>();
var unnecessaryImports = service.GetUnnecessaryImports(context.SemanticModel, cancellationToken);
if (unnecessaryImports.Any())
......
......@@ -464,13 +464,22 @@ private string GetDebuggerDisplay()
/// </remarks>
public Task<DocumentOptionSet> GetOptionsAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return GetOptionsAsync(Project.Solution.Options, cancellationToken);
}
internal Task<DocumentOptionSet> GetOptionsAsync(OptionSet globalOptionSet, CancellationToken cancellationToken = default(CancellationToken))
{
// TODO: we have this workaround since Solution.Options is not actually snapshot but just return Workspace.Options which violate snapshot model.
// this doesn't validate whether same optionset is given to invalidate the cache or not. this is not new since existing implementation
// also didn't check whether Workspace.Option is same as before or not. all wierd-ness come from the root cause of Solution.Options violating
// snapshot model. once that is fixed, we can remove this workaround
if (_cachedOptions == null)
{
var newAsyncLazy = new AsyncLazy<DocumentOptionSet>(async c =>
{
var optionsService = Project.Solution.Workspace.Services.GetRequiredService<IOptionService>();
var optionSet = await optionsService.GetUpdatedOptionSetForDocumentAsync(this, Project.Solution.Options, c).ConfigureAwait(false);
return new DocumentOptionSet(optionSet, Project.Language);
var documentOptionSet = await optionsService.GetUpdatedOptionSetForDocumentAsync(this, globalOptionSet, c).ConfigureAwait(false);
return new DocumentOptionSet(documentOptionSet, Project.Language);
}, cacheResult: true);
Interlocked.CompareExchange(ref _cachedOptions, newAsyncLazy, comparand: null);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册