private void RaiseDocumentDiagnosticsIfNeeded( Document document, StateSet stateSet, AnalysisKind kind, AnalysisResult oldResult, AnalysisResult newResult, Action <DiagnosticsUpdatedArgs> raiseEvents) { var oldItems = GetResult(oldResult, kind, document.Id); var newItems = GetResult(newResult, kind, document.Id); RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, oldItems, newItems, raiseEvents); }
private ImmutableArray <DiagnosticData> GetDiagnostics(AnalysisResult result) { // PERF: don't allocation anything if not needed if (result.IsAggregatedForm || result.IsEmpty) { return(ImmutableArray <DiagnosticData> .Empty); } return(result.SyntaxLocals.Values.SelectMany(v => v).Concat( result.SemanticLocals.Values.SelectMany(v => v)).Concat( result.NonLocals.Values.SelectMany(v => v)).Concat( result.Others).ToImmutableArray()); }
public async Task MergeAsync(ActiveFileState state, Document document) { Contract.ThrowIfFalse(state.DocumentId == document.Id); // merge active file state to project state var lastResult = _lastResult; var syntax = state.GetAnalysisData(AnalysisKind.Syntax); var semantic = state.GetAnalysisData(AnalysisKind.Semantic); var project = document.Project; var fullAnalysis = ServiceFeatureOnOffOptions.IsClosedFileDiagnosticsEnabled(project.Solution.Workspace, project.Language); // keep from build flag if full analysis is off var fromBuild = fullAnalysis ? false : lastResult.FromBuild; // if it is allowed to keep project state, check versions and if they are same, bail out // if full solution analysis is off or we are asked to reset document state, we always merge. if (fullAnalysis && syntax.Version != VersionStamp.Default && syntax.Version == semantic.Version && syntax.Version == lastResult.Version) { // all data is in sync already. return; } // we have mixed versions or full analysis is off, set it to default so that it can be re-calculated next time so data can be in sync. var version = VersionStamp.Default; // serialization can't be cancelled. var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version); // save active file diagnostics back to project state await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, syntax.Items).ConfigureAwait(false); await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, semantic.Items).ConfigureAwait(false); // save last aggregated form of analysis result _lastResult = new AnalysisResult(_lastResult.ProjectId, version, _lastResult.DocumentIdsOrEmpty.Add(state.DocumentId), isEmpty: false, fromBuild: fromBuild); }
private static ImmutableArray <DiagnosticData> GetResult(AnalysisResult result, AnalysisKind kind, DocumentId id) { if (result.IsEmpty || !result.DocumentIds.Contains(id) || result.IsAggregatedForm) { return(ImmutableArray <DiagnosticData> .Empty); } switch (kind) { case AnalysisKind.Syntax: return(result.GetResultOrEmpty(result.SyntaxLocals, id)); case AnalysisKind.Semantic: return(result.GetResultOrEmpty(result.SemanticLocals, id)); case AnalysisKind.NonLocal: return(result.GetResultOrEmpty(result.NonLocals, id)); default: return(Contract.FailWithReturn <ImmutableArray <DiagnosticData> >("shouldn't reach here")); } }
public async Task SaveAsync(Project project, AnalysisResult result) { Contract.ThrowIfTrue(result.IsAggregatedForm); RemoveInMemoryCache(_lastResult); // save last aggregated form of analysis result _lastResult = result.ToAggregatedForm(); // serialization can't be cancelled. var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, result.Version); foreach (var documentId in result.DocumentIds) { var document = project.GetDocument(documentId); Contract.ThrowIfNull(document); await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, GetResult(result, AnalysisKind.Syntax, document.Id)).ConfigureAwait(false); await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, GetResult(result, AnalysisKind.Semantic, document.Id)).ConfigureAwait(false); await SerializeAsync(serializer, document, document.Id, _owner.NonLocalStateName, GetResult(result, AnalysisKind.NonLocal, document.Id)).ConfigureAwait(false); } await SerializeAsync(serializer, project, result.ProjectId, _owner.NonLocalStateName, result.Others).ConfigureAwait(false); }
private void RaiseProjectDiagnosticsCreated(Project project, StateSet stateSet, AnalysisResult oldAnalysisResult, AnalysisResult newAnalysisResult, Action <DiagnosticsUpdatedArgs> raiseEvents) { foreach (var documentId in newAnalysisResult.DocumentIds) { var document = project.GetDocument(documentId); Contract.ThrowIfNull(document); RaiseDocumentDiagnosticsIfNeeded(document, stateSet, AnalysisKind.NonLocal, oldAnalysisResult, newAnalysisResult, raiseEvents); // we don't raise events for active file. it will be taken cared by active file analysis if (stateSet.IsActiveFile(documentId)) { continue; } RaiseDocumentDiagnosticsIfNeeded(document, stateSet, AnalysisKind.Syntax, oldAnalysisResult, newAnalysisResult, raiseEvents); RaiseDocumentDiagnosticsIfNeeded(document, stateSet, AnalysisKind.Semantic, oldAnalysisResult, newAnalysisResult, raiseEvents); } RaiseDiagnosticsCreated(project, stateSet, newAnalysisResult.Others, raiseEvents); }
private async Task FireAndForgetReportAnalyzerPerformanceAsync(Project project, RemoteHostClient?client, AnalysisResult analysisResult, CancellationToken cancellationToken) { if (client == null) { return; } try { _ = await client.TryRunRemoteAsync( WellKnownServiceHubServices.CodeAnalysisService, nameof(IRemoteDiagnosticAnalyzerService.ReportAnalyzerPerformance), solution : null, new object[] { analysisResult.AnalyzerTelemetryInfo.ToAnalyzerPerformanceInfo(_analyzerInfoCache), // +1 for project itself project.DocumentIds.Count + 1 }, callbackTarget : null, cancellationToken).ConfigureAwait(false); } catch (Exception ex) when(FatalError.ReportWithoutCrashUnlessCanceled(ex)) { // ignore all, this is fire and forget method } }
private void RaiseProjectDiagnosticsCreated(Project project, StateSet stateSet, AnalysisResult oldAnalysisResult, AnalysisResult newAnalysisResult, Action <DiagnosticsUpdatedArgs> raiseEvents) { foreach (var documentId in newAnalysisResult.DocumentIds) { var document = project.GetDocument(documentId); if (document == null) { // it can happen with build synchronization since, in build case, // we don't have actual snapshot (we have no idea what sources out of proc build has picked up) // so we might be out of sync. // example of such cases will be changing anything about solution while building is going on. // it can be user explict actions such as unloading project, deleting a file, but also it can be // something project system or roslyn workspace does such as populating workspace right after // solution is loaded. continue; } RaiseDocumentDiagnosticsIfNeeded(document, stateSet, AnalysisKind.NonLocal, oldAnalysisResult, newAnalysisResult, raiseEvents); // we don't raise events for active file. it will be taken cared by active file analysis if (stateSet.IsActiveFile(documentId)) { continue; } RaiseDocumentDiagnosticsIfNeeded(document, stateSet, AnalysisKind.Syntax, oldAnalysisResult, newAnalysisResult, raiseEvents); RaiseDocumentDiagnosticsIfNeeded(document, stateSet, AnalysisKind.Semantic, oldAnalysisResult, newAnalysisResult, raiseEvents); } RaiseDiagnosticsCreated(project, stateSet, newAnalysisResult.Others, raiseEvents); }
private bool IsEmpty(AnalysisResult result, DocumentId documentId) { return(!result.DocumentIdsOrEmpty.Contains(documentId)); }
public ProjectState(StateSet owner, ProjectId projectId) { _owner = owner; _lastResult = new AnalysisResult(projectId, VersionStamp.Default, documentIds: null, isEmpty: true); }
public void ResetVersion() { // reset version of cached data so that we can recalculate new data (ex, OnDocumentReset) _lastResult = new AnalysisResult(_lastResult.ProjectId, VersionStamp.Default, _lastResult.DocumentIds, _lastResult.IsEmpty, _lastResult.FromBuild); }