public void OnAnalyzerLoadFailed(object sender, AnalyzerLoadFailureEventArgs e) { if (!(sender is AnalyzerFileReference reference)) { return; } var diagnostic = AnalyzerHelper.CreateAnalyzerLoadFailureDiagnostic(e, reference.FullPath, projectId: null, language: null); // diagnostic from host analyzer can never go away var args = DiagnosticsUpdatedArgs.DiagnosticsCreated( id: Tuple.Create(this, reference.FullPath, e.ErrorCode, e.TypeName), workspace: _primaryWorkspace.Workspace, solution: null, projectId: null, documentId: null, diagnostics: ImmutableArray.Create <DiagnosticData>(diagnostic)); // this can be null in test. but in product code, this should never be null. _hostUpdateSource?.RaiseDiagnosticsUpdated(args); }
public async Task AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken) { // right now, there is no way to observe diagnostics for closed file. if (!_workspace.IsDocumentOpen(document.Id) || !_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Syntax)) { return; } var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var diagnostics = tree.GetDiagnostics(cancellationToken); Contract.Requires(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)); }
private void RaiseDiagnosticsCreated( TextDocument document, StateSet stateSet, AnalysisKind kind, ImmutableArray <DiagnosticData> items, Action <DiagnosticsUpdatedArgs> raiseEvents ) { Contract.ThrowIfFalse(document.Project.Solution.Workspace == Workspace); raiseEvents( DiagnosticsUpdatedArgs.DiagnosticsCreated( CreateId(stateSet, document.Id, kind), document.Project.Solution.Workspace, document.Project.Solution, document.Project.Id, document.Id, items ) ); }
public async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, CancellationToken cancellationToken) { // right now, there is no way to observe diagnostics for closed file. if (!_workspace.IsDocumentOpen(document.Id) || !_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Semantic)) { return; } var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var diagnostics = model.GetMethodBodyDiagnostics(span: null, cancellationToken: cancellationToken).Concat( model.GetDeclarationDiagnostics(span: null, cancellationToken: cancellationToken)); Contract.Requires(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, Semantic, document.Id), _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); }
private void RaiseEvents(Project project, ImmutableArray <DiagnosticData> diagnostics) { var groups = diagnostics.GroupBy(d => d.DocumentId); var solution = project.Solution; var workspace = solution.Workspace; foreach (var kv in groups) { if (kv.Key == null) { Owner.RaiseDiagnosticsUpdated( this, DiagnosticsUpdatedArgs.DiagnosticsCreated( ValueTuple.Create(this, project.Id), workspace, solution, project.Id, null, kv.ToImmutableArrayOrEmpty())); continue; } Owner.RaiseDiagnosticsUpdated( this, DiagnosticsUpdatedArgs.DiagnosticsCreated( ValueTuple.Create(this, kv.Key), workspace, solution, project.Id, kv.Key, kv.ToImmutableArrayOrEmpty())); } }
private void OnDiagnosticsUpdatedOnForeground( DiagnosticsUpdatedArgs e, SourceText sourceText, ITextSnapshot editorSnapshot) { this.AssertIsForeground(); Debug.Assert(!_disposed); // Find the appropriate async tagger for this diagnostics id, and let it know that // there were new diagnostics produced for it. var id = e.Id; ValueTuple <TaggerProvider, IAccurateTagger <TTag> > providerAndTagger; if (!_idToProviderAndTagger.TryGetValue(id, out providerAndTagger)) { // We didn't have an existing tagger for this diagnostic id. If there are no actual // diagnostics being reported, then don't bother actually doing anything. This saves // us from creating a lot of objects, and subscribing to tons of events that we don't // actually need (since we don't even have any diagnostics to show!). if (e.Diagnostics.Length == 0) { return; } // Didn't have an existing tagger for this diagnostic id. Make a new one // and cache it so we can use it in the future. var taggerProvider = new TaggerProvider(_owner); var tagger = taggerProvider.CreateTagger <TTag>(_subjectBuffer); providerAndTagger = ValueTuple.Create(taggerProvider, tagger); _idToProviderAndTagger[id] = providerAndTagger; // Register for changes from the underlying tagger. When it tells us about // changes, we'll let anyone know who is registered with us. tagger.TagsChanged += OnUnderlyingTaggerTagsChanged; } // Let the provider know that there are new diagnostics. It will then // handle all the async processing of those diagnostics. providerAndTagger.Item1.OnDiagnosticsUpdated(e, sourceText, editorSnapshot); }
async void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) { if (!enabled) { return; } var doc = DocumentContext.ParsedDocument; if (doc == null || DocumentContext.IsAdHocProject) { return; } var cad = DocumentContext.AnalysisDocument; if (cad == null || cad.Project == null) { return; } if (e.DocumentId != cad.Id || e.ProjectId != cad.Project.Id) { return; } var token = CancelUpdateTimeout(e.Id); var ad = new AnalysisDocument(Editor, DocumentContext); try { var result = await CodeDiagnosticRunner.Check(ad, token, e.Diagnostics).ConfigureAwait(false); if (result is IReadOnlyList <Result> resultList) { var updater = new ResultsUpdater(this, resultList, e.Id, token); updater.Update(); } } catch (Exception) { } }
private void DiagnosticService_DiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) { // LSP doesnt support diagnostics without a document. So if we get project level diagnostics without a document, ignore them. if (e.DocumentId != null && e.Solution != null) { var document = e.Solution.GetDocument(e.DocumentId); if (document == null || document.FilePath == null) { return; } // Only publish document diagnostics for the languages this provider supports. if (document.Project.Language != CodeAnalysis.LanguageNames.CSharp && document.Project.Language != CodeAnalysis.LanguageNames.VisualBasic) { return; } // LSP does not currently support publishing diagnostics incrememntally, so we re-publish all diagnostics. var asyncToken = _listener.BeginAsyncOperation(nameof(PublishDiagnosticsAsync)); Task.Run(() => PublishDiagnosticsAsync(document)) .CompletesAsyncOperation(asyncToken); } }
private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs diagnosticsUpdatedArgs) { var documentId = diagnosticsUpdatedArgs?.DocumentId; if (documentId == null) { return; } if (_diagnosticsUpdatedNotifiers.TryGetValue(documentId, out var notifier)) { if (diagnosticsUpdatedArgs.Kind == DiagnosticsUpdatedKind.DiagnosticsCreated) { var remove = diagnosticsUpdatedArgs.Diagnostics.RemoveAll(d => DisabledDiagnostics.Contains(d.Id)); if (remove.Length != diagnosticsUpdatedArgs.Diagnostics.Length) { diagnosticsUpdatedArgs = diagnosticsUpdatedArgs.WithDiagnostics(remove); } } notifier(diagnosticsUpdatedArgs); } }
private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) { if (_workspace != e.Workspace) { return; } if (e.Diagnostics.Length == 0) { OnDataRemoved(e); return; } var count = e.Diagnostics.Where(ShouldInclude).Count(); if (count <= 0) { OnDataRemoved(e); return; } OnDataAddedOrChanged(e); }
void UpdateInitialDiagnostics() { if (!AnalysisOptions.EnableFancyFeatures) { return; } var doc = DocumentContext.ParsedDocument; if (doc == null || DocumentContext.IsAdHocProject) { return; } var ad = new AnalysisDocument(Editor, DocumentContext); Task.Run(() => { var ws = DocumentContext.RoslynWorkspace; var project = DocumentContext.AnalysisDocument.Project.Id; var document = DocumentContext.AnalysisDocument.Id; // Force an initial diagnostic update from the engine. foreach (var updateArgs in diagService.GetDiagnosticsUpdatedEventArgs(ws, project, document, src.Token)) { var diagnostics = AdjustInitialDiagnostics(DocumentContext.AnalysisDocument.Project.Solution, updateArgs, src.Token); if (diagnostics.Length == 0) { continue; } var e = DiagnosticsUpdatedArgs.DiagnosticsCreated( updateArgs.Id, updateArgs.Workspace, DocumentContext.AnalysisDocument.Project.Solution, updateArgs.ProjectId, updateArgs.DocumentId, diagnostics); OnDiagnosticsUpdated(this, e); } }); }
private void GetInitialDiagnosticsInBackground( Document document, CancellationToken cancellationToken) { this.AssertIsBackground(); cancellationToken.ThrowIfCancellationRequested(); if (document != null) { var project = document.Project; var workspace = project.Solution.Workspace; foreach (var updateArgs in _owner._diagnosticService.GetDiagnosticsUpdatedEventArgs(workspace, project.Id, document.Id, cancellationToken)) { var diagnostics = AdjustInitialDiagnostics(project.Solution, updateArgs, cancellationToken); if (diagnostics.Length == 0) { continue; } OnDiagnosticsUpdatedOnBackground( DiagnosticsUpdatedArgs.DiagnosticsCreated( updateArgs.Id, updateArgs.Workspace, project.Solution, updateArgs.ProjectId, updateArgs.DocumentId, diagnostics)); } } }
public void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { _diagnostics = args.GetPushDiagnostics(_globalOptions, InternalDiagnosticsOptions.NormalDiagnosticMode); DiagnosticsUpdated?.Invoke(this, args); }
internal static async Task <IList <ITagSpan <TTag> > > GetErrorsFromUpdateSource(TestWorkspace workspace, DiagnosticsUpdatedArgs updateArgs) { var globalOptions = workspace.GetService <IGlobalOptionService>(); var source = new TestDiagnosticUpdateSource(globalOptions); using var wrapper = new DiagnosticTaggerWrapper <TProvider, TTag>(workspace, updateSource: source); var tagger = wrapper.TaggerProvider.CreateTagger <TTag>(workspace.Documents.First().GetTextBuffer()); using var disposable = (IDisposable)tagger; source.RaiseDiagnosticsUpdated(updateArgs); await wrapper.WaitForTags(); var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToImmutableArray(); return(spans); }
private void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { this.DiagnosticsUpdated?.Invoke(this, args); }
public void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { this.diagnostics = args.Diagnostics; DiagnosticsUpdated?.Invoke(this, args); }
private void DiagnosticService_DiagnosticsUpdated(object?_, DiagnosticsUpdatedArgs e) => DiagnosticService_DiagnosticsUpdated(e.Solution, e.DocumentId);
private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId currentDocumentId, int solutionVersion, DiagnosticsUpdatedArgs args = null) { // Explicitly hold onto the _subjectBuffer field in a local and use this local in this function to avoid crashes // if this field happens to be cleared by Dispose() below. This is required since this code path involves code // that can run on background thread. var buffer = _subjectBuffer; if (buffer == null) { return; } var workspace = buffer.GetWorkspace(); // workspace is not ready, nothing to do. if (workspace == null || workspace != currentWorkspace) { return; } if (currentDocumentId != workspace.GetDocumentIdInCurrentContext(buffer.AsTextContainer()) || solutionVersion == Volatile.Read(ref _lastSolutionVersionReported)) { return; } // make sure we only raise event once for same solution version. // light bulb controller will call us back to find out new information var changed = this.SuggestedActionsChanged; if (changed != null) { changed(this, EventArgs.Empty); } Volatile.Write(ref _lastSolutionVersionReported, solutionVersion); }
private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) { OnDataAddedOrChanged(this, _buildErrorSource.GetBuildErrors().Length); }
/// <summary> /// Called from the roslyn host when diagnostics was updated. /// </summary> /// <param name="a">a.</param> public void EhDiagnosticsUpdated(DiagnosticsUpdatedArgs a) { DiagnosticsUpdated?.Invoke(a); }
/// <summary> /// We do all mutation work on the UI thread. That ensures that all mutation /// is processed serially *and* it means we can safely examine things like /// subject buffers and open documents without any threat of race conditions. /// Note that we do not do any expensive work here. We just store (or remove) /// the data we were given in appropriate buckets. /// /// For example, we create a TaggerProvider per unique DiagnosticUpdatedArgs.Id /// we get. So if we see a new id we simply create a tagger for it and pass it /// these args to store. Otherwise we pass these args to the existing tagger. /// /// Similarly, clearing out data is just a matter of us clearing our reference /// to the data. /// </summary> private void OnDiagnosticsUpdatedOnForeground(DiagnosticsUpdatedArgs e) { this.AssertIsForeground(); if (_disposed) { return; } // Do some quick checks to avoid doing any further work for diagnostics we don't // care about. var ourDocument = _subjectBuffer.AsTextContainer().GetOpenDocumentInCurrentContext(); var ourDocumentId = ourDocument?.Id; if (ourDocumentId != _currentDocumentId) { // Our buffer has started tracking some other document entirely. // We have to clear out all of the diagnostics we have currently stored. RemoveAllCachedDiagnostics(); } _currentDocumentId = ourDocumentId; // Now see if the document we're tracking corresponds to the diagnostics // we're hearing about. If not, just ignore them. if (ourDocument == null || ourDocument.Project.Solution.Workspace != e.Workspace || ourDocument.Id != e.DocumentId) { return; } // We're hearing about diagnostics for our document. We may be hearing // about new diagnostics coming, or existing diagnostics being cleared // out. // First see if this is a document/project removal. If so, clear out any state we // have associated with any analyzers we have for that document/project. ProcessRemovedDiagnostics(e); // Make sure we can find an editor snapshot for these errors. Otherwise we won't // be able to make ITagSpans for them. If we can't, just bail out. This happens // when the solution crawler is very far behind. However, it will have a more // up to date document within it that it will eventually process. Until then // we just keep around the stale tags we have. // // Note: if the Solution or Document is null here, then that means the document // was removed. In that case, we do want to proceed so that we'll produce 0 // tags and we'll update the editor appropriately. SourceText sourceText = null; ITextSnapshot editorSnapshot = null; if (e.Solution != null) { var diagnosticDocument = e.Solution.GetDocument(e.DocumentId); if (diagnosticDocument != null) { if (!diagnosticDocument.TryGetText(out sourceText)) { return; } editorSnapshot = sourceText.FindCorrespondingEditorTextSnapshot(); if (editorSnapshot == null) { return; } // Make sure the editor we've got associated with these diagnostics is the // same one we're a tagger for. It is possible for us to hear about diagnostics // for the *same* Document that are not from the *same* buffer. For example, // say we have the following chain of events: // // Document is opened. // Diagnostics start analyzing. // Document is closed. // Document is opened. // Diagnostics finish and report for document. // // We'll hear about diagnostics for the original Document/Buffer that was // opened. But we'll be trying to apply them to this current Document/Buffer. // That won't work since these will be different buffers (and thus, we won't // be able to map the diagnostic spans appropriately). // // Note: returning here is safe. Because the file is closed/opened, The // Diagnostics Service will reanalyze it. It will then report the new results // which we will hear about and use. if (editorSnapshot.TextBuffer != _subjectBuffer) { return; } } } OnDiagnosticsUpdatedOnForeground(e, sourceText, editorSnapshot); }
private void OnDiagnosticsUpdatedOnBackground(DiagnosticsUpdatedArgs e) { this.AssertIsBackground(); RegisterNotification(() => OnDiagnosticsUpdatedOnForeground(e)); }
public void RaiseUpdateEvent(DiagnosticsUpdatedArgs args) { DiagnosticsUpdated?.Invoke(this, args); }
private void RaiseDiagnosticsCreated(object id, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray <DiagnosticData> items) { DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsCreated( CreateArgumentKey(id), _workspace, solution, projectId, documentId, items)); }
private void RaiseDiagnosticsRemoved(object id, Solution solution, ProjectId projectId, DocumentId documentId) { DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsRemoved( CreateArgumentKey(id), _workspace, solution, projectId, documentId)); }
private DiagnosticsUpdatedArgs MakeCreatedArgs( DebuggingSession session, object errorId, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray <DiagnosticData> items) { return(DiagnosticsUpdatedArgs.DiagnosticsCreated( CreateId(session, errorId), workspace, solution, projectId, documentId, items)); }
public void RaiseDiagnosticsUpdatedEvent(DiagnosticsUpdatedArgs args) => DiagnosticsUpdated?.Invoke(this, args);
private DiagnosticsUpdatedArgs MakeRemovedArgs( DebuggingSession session, object errorId, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId) { return(DiagnosticsUpdatedArgs.DiagnosticsRemoved( CreateId(session, errorId), workspace, solution, projectId, documentId)); }
private void Editor_ProcessDiagnostics(object sender, DiagnosticsUpdatedArgs e) { CodeEditor.ProcessDiagnostics(e); }
internal static async Task <IList <ITagSpan <IErrorTag> > > GetErrorsFromUpdateSource(TestWorkspace workspace, TestHostDocument document, DiagnosticsUpdatedArgs updateArgs) { var source = new TestDiagnosticUpdateSource(); using (var wrapper = new DiagnosticTaggerWrapper(workspace, source)) { var tagger = wrapper.TaggerProvider.CreateTagger <IErrorTag>(workspace.Documents.First().GetTextBuffer()); using (var disposable = tagger as IDisposable) { source.RaiseDiagnosticsUpdated(updateArgs); await wrapper.WaitForTags(); var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToImmutableArray(); return(spans); } } }