-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support semantic errors for script files in misc projects. #31134
Changes from 3 commits
ce29cf0
4a571bd
73f242e
415755f
2b847e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
// 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; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Composition; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Options; | ||
|
@@ -18,12 +18,14 @@ namespace Microsoft.CodeAnalysis.Diagnostics | |
[ExportIncrementalAnalyzerProvider(WellKnownSolutionCrawlerAnalyzers.Diagnostic, workspaceKinds: null)] | ||
internal partial class DefaultDiagnosticAnalyzerService : IIncrementalAnalyzerProvider, IDiagnosticUpdateSource | ||
{ | ||
private const int Syntax = 1; | ||
private const int Semantic = 2; | ||
private readonly IDiagnosticAnalyzerService _analyzerService; | ||
|
||
[ImportingConstructor] | ||
public DefaultDiagnosticAnalyzerService(IDiagnosticUpdateSourceRegistrationService registrationService) | ||
public DefaultDiagnosticAnalyzerService( | ||
IDiagnosticAnalyzerService analyzerService, | ||
IDiagnosticUpdateSourceRegistrationService registrationService) | ||
{ | ||
_analyzerService = analyzerService; | ||
registrationService.Register(this); | ||
} | ||
|
||
|
@@ -34,14 +36,13 @@ public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) | |
return null; | ||
} | ||
|
||
return new CompilerDiagnosticAnalyzer(this, workspace); | ||
return new DefaultDiagnosticIncrementalAnalyzer(this, workspace); | ||
} | ||
|
||
public event EventHandler<DiagnosticsUpdatedArgs> DiagnosticsUpdated; | ||
|
||
public bool SupportGetDiagnostics => | ||
// this only support push model, pull model will be provided by DiagnosticService by caching everything this one pushed | ||
false; | ||
// this only support push model, pull model will be provided by DiagnosticService by caching everything this one pushed | ||
public bool SupportGetDiagnostics => false; | ||
|
||
public ImmutableArray<DiagnosticData> GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) | ||
{ | ||
|
@@ -54,12 +55,12 @@ internal void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs state) | |
this.DiagnosticsUpdated?.Invoke(this, state); | ||
} | ||
|
||
private class CompilerDiagnosticAnalyzer : IIncrementalAnalyzer | ||
private class DefaultDiagnosticIncrementalAnalyzer : IIncrementalAnalyzer | ||
{ | ||
private readonly DefaultDiagnosticAnalyzerService _service; | ||
private readonly Workspace _workspace; | ||
|
||
public CompilerDiagnosticAnalyzer(DefaultDiagnosticAnalyzerService service, Workspace workspace) | ||
public DefaultDiagnosticIncrementalAnalyzer(DefaultDiagnosticAnalyzerService service, Workspace workspace) | ||
{ | ||
_service = service; | ||
_workspace = workspace; | ||
|
@@ -68,7 +69,8 @@ public CompilerDiagnosticAnalyzer(DefaultDiagnosticAnalyzerService service, Work | |
public bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e) | ||
{ | ||
if (e.Option == InternalRuntimeDiagnosticOptions.Syntax || | ||
e.Option == InternalRuntimeDiagnosticOptions.Semantic) | ||
e.Option == InternalRuntimeDiagnosticOptions.Semantic || | ||
e.Option == InternalRuntimeDiagnosticOptions.ScriptSemantic) | ||
{ | ||
return true; | ||
} | ||
|
@@ -78,53 +80,73 @@ public bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs | |
|
||
public async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) | ||
{ | ||
Debug.Assert(document.Project.Solution.Workspace == _workspace); | ||
|
||
// right now, there is no way to observe diagnostics for closed file. | ||
if (!_workspace.IsDocumentOpen(document.Id) || | ||
!_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Syntax) || | ||
!document.SupportsSyntaxTree) | ||
!_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Syntax)) | ||
{ | ||
return; | ||
} | ||
|
||
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); | ||
var diagnostics = tree.GetDiagnostics(cancellationToken); | ||
|
||
Debug.Assert(document.Project.Solution.Workspace == _workspace); | ||
|
||
var diagnosticData = diagnostics == null ? ImmutableArray<DiagnosticData>.Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty(); | ||
|
||
_service.RaiseDiagnosticsUpdated( | ||
DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, Syntax, document.Id), | ||
_workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); | ||
await AnalyzeForKind(document, AnalysisKind.Syntax, cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
public async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken) | ||
{ | ||
// right now, there is no way to observe diagnostics for closed file. | ||
if (!_workspace.IsDocumentOpen(document.Id) || | ||
!_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Semantic)) | ||
Debug.Assert(document.Project.Solution.Workspace == _workspace); | ||
|
||
if (!IsSemanticAnalysisOn()) | ||
{ | ||
return; | ||
} | ||
|
||
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); | ||
var diagnostics = model.GetMethodBodyDiagnostics(span: null, cancellationToken: cancellationToken).Concat( | ||
model.GetDeclarationDiagnostics(span: null, cancellationToken: cancellationToken)); | ||
await AnalyzeForKind(document, AnalysisKind.Semantic, cancellationToken).ConfigureAwait(false); | ||
|
||
Debug.Assert(document.Project.Solution.Workspace == _workspace); | ||
bool IsSemanticAnalysisOn() | ||
{ | ||
// right now, there is no way to observe diagnostics for closed file. | ||
if (!_workspace.IsDocumentOpen(document.Id)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Semantic)) | ||
{ | ||
return true; | ||
} | ||
|
||
return _workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.ScriptSemantic) && document.SourceCodeKind == SourceCodeKind.Script; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what are the implications of this for CSX? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can this be answered? |
||
} | ||
} | ||
|
||
var diagnosticData = diagnostics == null ? ImmutableArray<DiagnosticData>.Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty(); | ||
private async Task AnalyzeForKind(Document document, AnalysisKind kind, CancellationToken cancellationToken) | ||
{ | ||
var diagnosticData = await _service._analyzerService.GetDiagnosticsAsync(document, GetAnalyzers(), kind, cancellationToken).ConfigureAwait(false); | ||
|
||
_service.RaiseDiagnosticsUpdated( | ||
DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, Semantic, document.Id), | ||
_workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); | ||
DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, kind, document.Id), | ||
_workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData.ToImmutableArrayOrEmpty())); | ||
|
||
IEnumerable<DiagnosticAnalyzer> GetAnalyzers() | ||
{ | ||
// C# or VB document that supports compiler | ||
var compilerAnalyzer = _service._analyzerService.GetCompilerDiagnosticAnalyzer(document.Project.Language); | ||
if (compilerAnalyzer != null) | ||
{ | ||
return SpecializedCollections.SingletonEnumerable(compilerAnalyzer); | ||
} | ||
|
||
// document that doesn't support compiler diagnostics such as fsharp or typescript | ||
return _service._analyzerService.GetDiagnosticAnalyzers(document.Project); | ||
} | ||
} | ||
|
||
public void RemoveDocument(DocumentId documentId) | ||
{ | ||
// a file is removed from misc project | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is this comment still relevant? This shouldn't have any assumption of misc workspace, correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is ScriptSemantic missing here? If not I'd add a comment why. In reply to: 238470136 [](ancestors = 238470136) |
||
RaiseEmptyDiagnosticUpdated(Syntax, documentId); | ||
RaiseEmptyDiagnosticUpdated(Semantic, documentId); | ||
RaiseEmptyDiagnosticUpdated(AnalysisKind.Syntax, documentId); | ||
RaiseEmptyDiagnosticUpdated(AnalysisKind.Semantic, documentId); | ||
} | ||
|
||
public Task DocumentResetAsync(Document document, CancellationToken cancellationToken) | ||
|
@@ -139,7 +161,7 @@ public Task DocumentCloseAsync(Document document, CancellationToken cancellation | |
return DocumentResetAsync(document, cancellationToken); | ||
} | ||
|
||
private void RaiseEmptyDiagnosticUpdated(int kind, DocumentId documentId) | ||
private void RaiseEmptyDiagnosticUpdated(AnalysisKind kind, DocumentId documentId) | ||
{ | ||
_service.RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs.DiagnosticsRemoved( | ||
new DefaultUpdateArgsId(_workspace.Kind, kind, documentId), _workspace, null, documentId.ProjectId, documentId)); | ||
|
@@ -168,7 +190,7 @@ private class DefaultUpdateArgsId : BuildToolId.Base<int, DocumentId>, ISupportL | |
{ | ||
private readonly string _workspaceKind; | ||
|
||
public DefaultUpdateArgsId(string workspaceKind, int type, DocumentId documentId) : base(type, documentId) | ||
public DefaultUpdateArgsId(string workspaceKind, AnalysisKind kind, DocumentId documentId) : base((int)kind, documentId) | ||
{ | ||
_workspaceKind = workspaceKind; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
namespace Microsoft.CodeAnalysis.Diagnostics | ||
{ | ||
/// <summary> | ||
/// enum for each analysis kind. | ||
/// </summary> | ||
internal enum AnalysisKind | ||
{ | ||
Syntax, | ||
Semantic, | ||
NonLocal | ||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure i understand this. Why is semantic analysis not on for closed files? Isn't that what FSA is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this be answered?