/// <summary> /// Return all diagnostics that belong to given project for the given StateSets (analyzers) either from cache or by calculating them /// </summary> public async Task<ProjectAnalysisData> GetProjectAnalysisDataAsync( CompilationWithAnalyzers analyzerDriverOpt, Project project, IEnumerable<StateSet> stateSets, CancellationToken cancellationToken) { try { // PERF: we need to flip this to false when we do actual diffing. var avoidLoadingData = true; var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); var existingData = await ProjectAnalysisData.CreateAsync(project, stateSets, avoidLoadingData, cancellationToken).ConfigureAwait(false); if (existingData.Version == version) { return existingData; } // perf optimization. check whether we want to analyze this project or not. if (!await FullAnalysisEnabledAsync(project, cancellationToken).ConfigureAwait(false)) { return new ProjectAnalysisData(project.Id, version, existingData.Result, ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult>.Empty); } var result = await ComputeDiagnosticsAsync(analyzerDriverOpt, project, stateSets, cancellationToken).ConfigureAwait(false); return new ProjectAnalysisData(project.Id, version, existingData.Result, result); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) either from cache or by calculating them /// </summary> public async Task<DocumentAnalysisData> GetDocumentAnalysisDataAsync( CompilationWithAnalyzers analyzerDriverOpt, Document document, StateSet stateSet, AnalysisKind kind, CancellationToken cancellationToken) { try { var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false); var state = stateSet.GetActiveFileState(document.Id); var existingData = state.GetAnalysisData(kind); if (existingData.Version == version) { return existingData; } // perf optimization. check whether analyzer is suppressed and avoid getting diagnostics if suppressed. // REVIEW: IsAnalyzerSuppressed call seems can be quite expensive in certain condition. is there any other way to do this? if (_owner.Owner.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project)) { return new DocumentAnalysisData(version, existingData.Items, ImmutableArray<DiagnosticData>.Empty); } var nullFilterSpan = (TextSpan?)null; var diagnostics = await ComputeDiagnosticsAsync(analyzerDriverOpt, document, stateSet.Analyzer, kind, nullFilterSpan, cancellationToken).ConfigureAwait(false); // we only care about local diagnostics return new DocumentAnalysisData(version, existingData.Items, diagnostics.ToImmutableArrayOrEmpty()); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public DiagnosticAnalyzerDriver( Document document, TextSpan? span, SyntaxNode root, DiagnosticIncrementalAnalyzer owner, bool concurrentAnalysis, bool reportSuppressedDiagnostics, CompilationWithAnalyzers cachedCompilationWithAnalyzersOpt, CancellationToken cancellationToken) : this(document.Project, owner, concurrentAnalysis, reportSuppressedDiagnostics, cachedCompilationWithAnalyzersOpt, cancellationToken) { _document = document; _span = span; _root = root; }
public DiagnosticAnalyzerDriver( Project project, DiagnosticIncrementalAnalyzer owner, bool concurrentAnalysis, bool reportSuppressedDiagnostics, CompilationWithAnalyzers cachedCompilationWithAnalyzersOpt, CancellationToken cancellationToken) { _project = project; _owner = owner; _concurrentAnalysis = concurrentAnalysis; _reportSuppressedDiagnostics = reportSuppressedDiagnostics; _cancellationToken = cancellationToken; _lazyCompilationWithAnalyzers = cachedCompilationWithAnalyzersOpt; }
public DiagnosticAnalyzerDriver( Project project, DiagnosticIncrementalAnalyzer owner, CancellationToken cancellationToken) { _project = project; _owner = owner; _cancellationToken = cancellationToken; _analysisOptions = new CompilationWithAnalyzersOptions( new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution.Workspace), owner.GetOnAnalyzerException(project.Id), concurrentAnalysis: false, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: true); _lazyCompilationWithAnalyzers = null; }
public async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { if (analyzerDriver.Analyzers.Length == 0) { // quick bail out return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty); } var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); // PERF: Run all analyzers at once using the new GetAnalysisResultAsync API. var analysisResult = await analyzerDriver.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false); // get compiler result builder map var builderMap = analysisResult.ToResultBuilderMap(project, version, analyzerDriver.Compilation, analyzerDriver.Analyzers, cancellationToken); return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo); }
private void AssertAnalyzers(CompilationWithAnalyzers analyzerDriver, IEnumerable<StateSet> stateSets) { if (analyzerDriver == null) { // this can happen if project doesn't support compilation or no stateSets are given. return; } // make sure analyzers are same. Contract.ThrowIfFalse(analyzerDriver.Analyzers.SetEquals(stateSets.Select(s => s.Analyzer).Where(a => !a.IsWorkspaceDiagnosticAnalyzer()))); }
private async Task UpdateAnalyzerTelemetryDataAsync(DiagnosticAnalyzer analyzer, CompilationWithAnalyzers compilationWithAnalyzers) { try { var analyzerTelemetryInfo = await compilationWithAnalyzers.GetAnalyzerTelemetryInfoAsync(analyzer, _cancellationToken).ConfigureAwait(false); DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerTelemetryInfo, _project, _owner.DiagnosticLogAggregator); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Return all diagnostics that belong to given project for the given StateSets (analyzers) by calculating them /// </summary> public async Task<ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult>> ComputeDiagnosticsAsync( CompilationWithAnalyzers analyzerDriverOpt, Project project, IEnumerable<StateSet> stateSets, CancellationToken cancellationToken) { var result = ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult>.Empty; // analyzerDriver can be null if given project doesn't support compilation. if (analyzerDriverOpt != null) { // calculate regular diagnostic analyzers diagnostics result = await analyzerDriverOpt.AnalyzeAsync(project, cancellationToken).ConfigureAwait(false); // record telemetry data await UpdateAnalyzerTelemetryDataAsync(analyzerDriverOpt, project, cancellationToken).ConfigureAwait(false); } // check whether there is IDE specific project diagnostic analyzer return await MergeProjectDiagnosticAnalyzerDiagnosticsAsync(project, stateSets, analyzerDriverOpt?.Compilation, result, cancellationToken).ConfigureAwait(false); }
// Old code, until we get EditorFeatures into composition so we can switch code fix service. public static async Task <IEnumerable <Result> > Check(AnalysisDocument analysisDocument, CancellationToken cancellationToken) { var input = analysisDocument.DocumentContext; if (!AnalysisOptions.EnableFancyFeatures || input.Project == null || !input.IsCompileableInProject || input.AnalysisDocument == null) { return(Enumerable.Empty <Result> ()); } if (SkipContext(input)) { return(Enumerable.Empty <Result> ()); } try { var model = await analysisDocument.DocumentContext.AnalysisDocument.GetSemanticModelAsync(cancellationToken); if (model == null) { return(Enumerable.Empty <Result> ()); } var compilation = model.Compilation; var language = CodeRefactoringService.MimeTypeToLanguage(analysisDocument.Editor.MimeType); await GetDescriptorTable(analysisDocument, cancellationToken); if (providers.Count == 0 || cancellationToken.IsCancellationRequested) { return(Enumerable.Empty <Result> ()); } #if DEBUG Debug.Listeners.Add(consoleTraceListener); #endif CompilationWithAnalyzers compilationWithAnalyzer; var analyzers = ImmutableArray <DiagnosticAnalyzer> .Empty.AddRange(providers); var diagnosticList = new List <Diagnostic> (); try { var sol = analysisDocument.DocumentContext.AnalysisDocument.Project.Solution; var options = new CompilationWithAnalyzersOptions( new WorkspaceAnalyzerOptions( new AnalyzerOptions(ImmutableArray <AdditionalText> .Empty), sol.Options, sol), delegate(Exception exception, DiagnosticAnalyzer analyzer, Diagnostic diag) { LoggingService.LogError("Exception in diagnostic analyzer " + diag.Id + ":" + diag.GetMessage(), exception); }, false, false ); compilationWithAnalyzer = compilation.WithAnalyzers(analyzers, options); if (input.ParsedDocument == null || cancellationToken.IsCancellationRequested) { return(Enumerable.Empty <Result> ()); } diagnosticList.AddRange(await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync(model, null, cancellationToken).ConfigureAwait(false)); diagnosticList.AddRange(await compilationWithAnalyzer.GetAnalyzerSyntaxDiagnosticsAsync(model.SyntaxTree, cancellationToken).ConfigureAwait(false)); } catch (OperationCanceledException) { } catch (AggregateException ae) { ae.Flatten().Handle(ix => ix is OperationCanceledException); } catch (Exception ex) { LoggingService.LogError("Error creating analyzer compilation", ex); return(Enumerable.Empty <Result> ()); } finally { #if DEBUG Debug.Listeners.Remove(consoleTraceListener); #endif CompilationWithAnalyzers.ClearAnalyzerState(analyzers); } return(diagnosticList .Where(d => !d.Id.StartsWith("CS", StringComparison.Ordinal)) .Where(d => !diagnosticTable.TryGetValue(d.Id, out var desc) || desc.GetIsEnabled(d.Descriptor)) .Select(diagnostic => { var res = new DiagnosticResult(diagnostic); // var line = analysisDocument.Editor.GetLineByOffset (res.Region.Start); // Console.WriteLine (diagnostic.Id + "/" + res.Region +"/" + analysisDocument.Editor.GetTextAt (line)); return res; })); } catch (OperationCanceledException) { return(Enumerable.Empty <Result> ()); } catch (AggregateException ae) { ae.Flatten().Handle(ix => ix is OperationCanceledException); return(Enumerable.Empty <Result> ()); } catch (Exception e) { LoggingService.LogError("Error while running diagnostics.", e); return(Enumerable.Empty <Result> ()); } }
public async Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { var service = project.Solution.Workspace.Services.GetService <IRemoteHostClientService>(); if (service == null) { // host doesn't support RemoteHostService such as under unit test return(await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false)); } var remoteHostClient = await service.GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); if (remoteHostClient == null) { // remote host is not running. this can happen if remote host is disabled. return(await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false)); } var outOfProcResult = await AnalyzeOutOfProcAsync(remoteHostClient, analyzerDriver, project, cancellationToken).ConfigureAwait(false); // make sure things are not cancelled cancellationToken.ThrowIfCancellationRequested(); return(DiagnosticAnalysisResultMap.Create(outOfProcResult.AnalysisResult, outOfProcResult.TelemetryInfo)); }
/// <summary> /// Given a set of compiler or <see cref="IDiagnosticAnalyzer"/> generated <paramref name="diagnostics"/>, returns the effective diagnostics after applying the below filters: /// 1) <see cref="CompilationOptions.SpecificDiagnosticOptions"/> specified for the given <paramref name="compilation"/>. /// 2) <see cref="CompilationOptions.GeneralDiagnosticOption"/> specified for the given <paramref name="compilation"/>. /// 3) Diagnostic suppression through applied <see cref="System.Diagnostics.CodeAnalysis.SuppressMessageAttribute"/>. /// 4) Pragma directives for the given <paramref name="compilation"/>. /// </summary> public static IEnumerable <Diagnostic> GetEffectiveDiagnostics(this Compilation compilation, IEnumerable <Diagnostic> diagnostics) { return(CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilation)); }
public CompilationWithAnalyzersCacheEntry(CompilationWithAnalyzers compilationWithAnalyzers, BidirectionalMap <string, DiagnosticAnalyzer> analyzerToIdMap) { CompilationWithAnalyzers = compilationWithAnalyzers; AnalyzerToIdMap = analyzerToIdMap; }
private async Task <IEnumerable <Diagnostic> > ComputeProjectDiagnosticAnalyzerDiagnosticsAsync( Project project, ProjectDiagnosticAnalyzer analyzer, Compilation compilationOpt, CancellationToken cancellationToken) { using (var pooledObject = SharedPools.Default <List <Diagnostic> >().GetPooledObject()) { var diagnostics = pooledObject.Object; cancellationToken.ThrowIfCancellationRequested(); try { await analyzer.AnalyzeProjectAsync(project, diagnostics.Add, cancellationToken).ConfigureAwait(false); // REVIEW: V1 doesn't convert diagnostics to effective diagnostics. not sure why. return(compilationOpt == null?diagnostics.ToImmutableArrayOrEmpty() : CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt)); } catch (Exception e) when(!IsCanceled(e, cancellationToken)) { OnAnalyzerException(analyzer, project.Id, compilationOpt, e); return(ImmutableArray <Diagnostic> .Empty); } } }
public async Task AnalyzeAsync( SemanticModel semanticModel, TextSpan?span, CompilationWithAnalyzers compilationWithAnalyzers, Func <DiagnosticAnalyzer, ImmutableArray <DiagnosticDescriptor> > getSupportedDiagnostics, Func <DiagnosticAnalyzer, bool> getIsCompilationEndAnalyzer, Action <Diagnostic> reportDiagnostic, CancellationToken cancellationToken) { // We need compilation with suppressed diagnostics for this feature. if (!compilationWithAnalyzers.Compilation.Options.ReportSuppressedDiagnostics) { return; } var tree = semanticModel.SyntaxTree; // Bail out if analyzer is suppressed on this file or project. // NOTE: Normally, we would not require this check in the analyzer as the analyzer driver has this optimization. // However, this is a special analyzer that is directly invoked by the analysis host (IDE), so we do this check here. if (compilationWithAnalyzers.Compilation.Options.SyntaxTreeOptionsProvider != null && compilationWithAnalyzers.Compilation.Options.SyntaxTreeOptionsProvider.TryGetDiagnosticValue(tree, IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId, cancellationToken, out var severity) || compilationWithAnalyzers.Compilation.Options.SpecificDiagnosticOptions.TryGetValue(IDEDiagnosticIds.RemoveUnnecessarySuppressionDiagnosticId, out severity)) { if (severity == ReportDiagnostic.Suppress) { return; } } // Bail out if analyzer has been turned off through options. var option = compilationWithAnalyzers.AnalysisOptions.Options?.GetOption( CodeStyleOptions2.RemoveUnnecessarySuppressionExclusions, tree, cancellationToken).Trim(); var(userIdExclusions, userCategoryExclusions, analyzerDisabled) = ParseUserExclusions(option); if (analyzerDisabled) { return; } // Bail out for generated code. if (tree.IsGeneratedCode(compilationWithAnalyzers.AnalysisOptions.Options, SyntaxFacts, cancellationToken)) { return; } var root = tree.GetRoot(cancellationToken); // Bail out if tree has syntax errors. if (root.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) { return; } // Process pragma directives and inline SuppressMessageAttributes in the tree. // The core algorithm is as follows: // 1. Iterate through all the active pragmas and local SuppressMessageAttributes in the source file and // identify the pragmas and local SuppressMessageAttributes // with diagnostics IDs for which we support unnecesary suppression analysis. // 2. Build the following data structures during this loop: // a. A map from diagnostic ID to list of pragmas for the ID. This map tracks supported diagnostic IDs for this tree's pragmas. // b. A array of tuples of candidate pragmas sorted by span, along with associated IDs and enable/disable flag. // This sorted array allows mapping an unnecessary pragma to the corresponding toggling pragma pair for removal. // c. A map from pragmas to a boolean indicating if the pragma was used or not. // d. A map from diagnostic ID to list of SuppressMessageAttribute nodes for the ID. // This map tracks supported diagnostic IDs for this tree's SuppressMessageAttribute nodes. // e. A map from SuppressMessageAttribute nodes to a boolean indicating if the attribute was used or not. // f. A set of supported compiler diagnostic IDs that are used in pragmas or SuppressMessageAttributes in this file. // 3. Map the set of candidate diagnostic IDs to the analyzers that can report diagnostics with these IDs. // 4. Execute these analyzers to compute the diagnostics reported by these analyzers in this file. // 5. Iterate through the suppressed diagnostics from this list and do the following: // a. If the diagnostic was suppressed with a prama, mark the closest preceeeding disable pragma // which suppresses this ID as used/necessary. Also mark the matching restore pragma as used. // b. Otherwise, if the diagnostic was suppressed with SuppressMessageAttribute, mark the attribute as used. // 6. Finally, report a diagostic all the pragmas and SuppressMessageAttributes which have not been marked as used. using var _1 = PooledDictionary <string, List <(SyntaxTrivia pragma, bool isDisable)> > .GetInstance(out var idToPragmasMap); using var _2 = ArrayBuilder <(SyntaxTrivia pragma, ImmutableArray <string> ids, bool isDisable)> .GetInstance(out var sortedPragmasWithIds); using var _3 = PooledDictionary <SyntaxTrivia, bool> .GetInstance(out var pragmasToIsUsedMap); using var _4 = PooledHashSet <string> .GetInstance(out var compilerDiagnosticIds); var hasPragmaInAnalysisSpan = ProcessPragmaDirectives(root, span, idToPragmasMap, pragmasToIsUsedMap, sortedPragmasWithIds, compilerDiagnosticIds, userIdExclusions); cancellationToken.ThrowIfCancellationRequested(); using var _5 = PooledDictionary <string, List <SyntaxNode> > .GetInstance(out var idToSuppressMessageAttributesMap); using var _6 = PooledDictionary <SyntaxNode, bool> .GetInstance(out var suppressMessageAttributesToIsUsedMap); var hasAttributeInAnalysisSpan = await ProcessSuppressMessageAttributesAsync(root, semanticModel, span, idToSuppressMessageAttributesMap, suppressMessageAttributesToIsUsedMap, userIdExclusions, userCategoryExclusions, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Bail out if we have no pragma directives or SuppressMessageAttributes to analyze. if (!hasPragmaInAnalysisSpan && !hasAttributeInAnalysisSpan) { return; } using var _8 = PooledHashSet <string> .GetInstance(out var idsToAnalyzeBuilder); idsToAnalyzeBuilder.AddAll(idToPragmasMap.Keys); idsToAnalyzeBuilder.AddAll(idToSuppressMessageAttributesMap.Keys); var idsToAnalyze = idsToAnalyzeBuilder.ToImmutableHashSet(); // Compute all the reported compiler and analyzer diagnostics for diagnostic IDs corresponding to pragmas in the tree. var(diagnostics, unhandledIds) = await GetReportedDiagnosticsForIdsAsync( idsToAnalyze, root, semanticModel, compilationWithAnalyzers, getSupportedDiagnostics, getIsCompilationEndAnalyzer, compilerDiagnosticIds, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Iterate through reported diagnostics which are suppressed in source through pragmas and mark the corresponding pragmas as used. await ProcessReportedDiagnosticsAsync(diagnostics, tree, compilationWithAnalyzers, idToPragmasMap, pragmasToIsUsedMap, idToSuppressMessageAttributesMap, suppressMessageAttributesToIsUsedMap, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Remove entries for unhandled diagnostic ids. foreach (var id in unhandledIds) { if (idToPragmasMap.TryGetValue(id, out var pragmas)) { foreach (var(pragma, _) in pragmas) { pragmasToIsUsedMap.Remove(pragma); } } if (idToSuppressMessageAttributesMap.TryGetValue(id, out var attributeNodes)) { foreach (var attributeNode in attributeNodes) { suppressMessageAttributesToIsUsedMap.Remove(attributeNode); } idToSuppressMessageAttributesMap.Remove(id); } } // Finally, report the unnecessary suppressions. var effectiveSeverity = severity.ToDiagnosticSeverity() ?? s_removeUnnecessarySuppressionDescriptor.DefaultSeverity; ReportUnnecessarySuppressions(pragmasToIsUsedMap, sortedPragmasWithIds, suppressMessageAttributesToIsUsedMap, reportDiagnostic, effectiveSeverity, compilationWithAnalyzers.Compilation); }
public async Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, bool forcedAnalysis, CancellationToken cancellationToken) { var workspace = project.Solution.Workspace; if (!workspace.Options.GetOption(RemoteFeatureOptions.DiagnosticsEnabled)) { // diagnostic service running on remote host is disabled. just run things in in proc return(await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false)); } var service = project.Solution.Workspace.Services.GetService <IRemoteHostClientService>(); if (service == null) { // host doesn't support RemoteHostService such as under unit test return(await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false)); } var remoteHostClient = await service.TryGetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); if (remoteHostClient == null) { // remote host is not running. this can happen if remote host is disabled. return(await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false)); } // due to OpenFileOnly analyzer, we need to run inproc as well for such analyzers var inProcResultTask = AnalyzeInProcAsync(CreateAnalyzerDriver(analyzerDriver, a => a.IsOpenFileOnly(project.Solution.Workspace)), project, cancellationToken); var outOfProcResultTask = AnalyzeOutOfProcAsync(remoteHostClient, analyzerDriver, project, forcedAnalysis, cancellationToken); // run them concurrently in vs and remote host await Task.WhenAll(inProcResultTask, outOfProcResultTask).ConfigureAwait(false); // make sure things are not cancelled cancellationToken.ThrowIfCancellationRequested(); // merge 2 results return(DiagnosticAnalysisResultMap.Create( inProcResultTask.Result.AnalysisResult.AddRange(outOfProcResultTask.Result.AnalysisResult), inProcResultTask.Result.TelemetryInfo.AddRange(outOfProcResultTask.Result.TelemetryInfo))); }
private Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeInProcAsync( CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { return(AnalyzeInProcAsync(analyzerDriver, project, client: null, cancellationToken)); }
public static async Task <ImmutableArray <Diagnostic> > GetAllDiagnosticsAsync(Compilation compilation, CompilationWithAnalyzers compilationWithAnalyzers, ImmutableArray <DiagnosticAnalyzer> analyzers, IEnumerable <Document> documents, bool includeCompilerDiagnostics, CancellationToken cancellationToken) { if (GetAnalyzerSyntaxDiagnosticsAsync == null || GetAnalyzerSemanticDiagnosticsAsync == null) { // In everything except Roslyn 1.1, we use GetAllDiagnosticsAsync and return the result. var allDiagnostics = await compilationWithAnalyzers.GetAllDiagnosticsAsync().ConfigureAwait(false); return(allDiagnostics); } compilationWithAnalyzers.Compilation.GetDeclarationDiagnostics(cancellationToken); // Note that the following loop to obtain syntax and semantic diagnostics for each document cannot operate // on parallel due to our use of a single CompilationWithAnalyzers instance. var diagnostics = ImmutableArray.CreateBuilder <Diagnostic>(); foreach (var document in documents) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var syntaxDiagnostics = await GetAnalyzerSyntaxDiagnosticsAsync(compilationWithAnalyzers, syntaxTree, cancellationToken).ConfigureAwait(false); diagnostics.AddRange(syntaxDiagnostics); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var semanticDiagnostics = await GetAnalyzerSemanticDiagnosticsAsync(compilationWithAnalyzers, semanticModel, default(TextSpan?), cancellationToken).ConfigureAwait(false); diagnostics.AddRange(semanticDiagnostics); } foreach (var analyzer in analyzers) { diagnostics.AddRange(await GetAnalyzerCompilationDiagnosticsAsync(compilationWithAnalyzers, ImmutableArray.Create(analyzer), cancellationToken).ConfigureAwait(false)); } if (includeCompilerDiagnostics) { // This is the special handling for cases where code fixes operate on warnings produced by the C# // compiler, as opposed to being created by specific analyzers. var compilerDiagnostics = compilation.GetDiagnostics(cancellationToken); diagnostics.AddRange(compilerDiagnostics); } return(diagnostics.ToImmutable()); }
public async Task <bool> RunAsync() { try { // this parameter was introduced in rc3, all call to it seem to be using RuntimeEnvironment.GetRuntimeDirectory() // https://github.com/dotnet/roslyn/blob/0382e3e3fc543fc483090bff3ab1eaae39dfb4d9/src/Compilers/CSharp/csc/Program.cs#L18 var sdkDirectory = RuntimeEnvironment.GetRuntimeDirectory(); CscArgs = CSharpCommandLineParser.Default.Parse(_precompilationCommandLineArgs.Arguments, _precompilationCommandLineArgs.BaseDirectory, sdkDirectory); Diagnostics = new List <Diagnostic>(CscArgs.Errors); // load those before anything else hooks into our AssemlbyResolve... var compilationModules = LoadModules().ToList(); if (Diagnostics.Any()) { return(false); } Encoding = CscArgs.Encoding ?? new UTF8Encoding(false); // utf8 without bom var pdbPath = CscArgs.PdbPath; var outputPath = Path.Combine(CscArgs.OutputDirectory, CscArgs.OutputFileName); if (!CscArgs.EmitPdb) { pdbPath = null; } else if (string.IsNullOrWhiteSpace(pdbPath)) { pdbPath = Path.ChangeExtension(outputPath, ".pdb"); } using (var workspace = CreateWokspace()) using (var analysisCts = new CancellationTokenSource()) using (var peStream = new MemoryStream()) using (var pdbStream = !string.IsNullOrWhiteSpace(pdbPath) ? new MemoryStream() : null) using (var xmlDocumentationStream = !string.IsNullOrWhiteSpace(CscArgs.DocumentationPath) ? new MemoryStream() : null) { EmitResult emitResult = null; var project = CreateProject(workspace); CSharpCompilation compilation = null; CompilationWithAnalyzers compilationWithAnalyzers = null; try { compilation = await project.GetCompilationAsync() as CSharpCompilation; } catch (Exception ex) { Console.WriteLine("error: failed to create compilation: " + ex.Message); return(false); } var context = new CompileContext(compilationModules); context.Before(new BeforeCompileContext { Arguments = CscArgs, Compilation = compilation.AddSyntaxTrees(GeneratedSyntaxTrees()), Diagnostics = Diagnostics, }); CscArgs = context.BeforeCompileContext.Arguments; compilation = context.BeforeCompileContext.Compilation; var analyzers = project.AnalyzerReferences.SelectMany(x => x.GetAnalyzers(project.Language)).ToImmutableArray(); if (!analyzers.IsEmpty) { compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, analysisCts.Token); compilation = compilationWithAnalyzers.Compilation as CSharpCompilation; } var analysisTask = compilationWithAnalyzers?.GetAnalysisResultAsync(analysisCts.Token); using (var win32Resources = CreateWin32Resource(compilation)) { // https://github.com/dotnet/roslyn/blob/41950e21da3ac2c307fb46c2ca8c8509b5059909/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L437 emitResult = compilation.Emit( peStream: peStream, pdbStream: pdbStream, xmlDocumentationStream: xmlDocumentationStream, win32Resources: win32Resources, manifestResources: CscArgs.ManifestResources, options: CscArgs.EmitOptions, sourceLinkStream: TryOpenFile(CscArgs.SourceLink, out var sourceLinkStream) ? sourceLinkStream : null, embeddedTexts: CscArgs.EmbeddedFiles.AsEnumerable() .Select(x => TryOpenFile(x.Path, out var embeddedText) ? EmbeddedText.FromStream(x.Path, embeddedText) : null) .Where(x => x != null), debugEntryPoint: null); } analysisCts.Cancel(); Diagnostics.AddRange(emitResult.Diagnostics); try { var analysisResult = analysisTask == null ? null : await analysisTask; if (analysisResult != null) { Diagnostics.AddRange(analysisResult.GetAllDiagnostics()); foreach (var info in analysisResult.AnalyzerTelemetryInfo) { Console.WriteLine($"hidden: {info.Key} {info.Value.ExecutionTime.TotalMilliseconds:#}ms"); } } } catch (OperationCanceledException) { Console.WriteLine("warning: analysis canceled"); } catch (Exception ex) { Console.WriteLine("error: analysis failed: " + ex.Message); return(false); } if (!emitResult.Success || HasErrors) { return(false); } context.After(new AfterCompileContext { Arguments = CscArgs, AssemblyStream = peStream, Compilation = compilation, Diagnostics = Diagnostics, SymbolStream = pdbStream, XmlDocStream = xmlDocumentationStream, }); if (!HasErrors) { // do not create the output files if emit fails // if the output files are there, msbuild incremental build thinks the previous build succeeded await Task.WhenAll( DumpToFileAsync(outputPath, peStream), DumpToFileAsync(pdbPath, pdbStream), DumpToFileAsync(CscArgs.DocumentationPath, xmlDocumentationStream)); return(true); } return(false); } } catch (Exception ex) { Console.WriteLine(string.Join("\n", ex.ToString().Split('\n').Select((x, i) => x + $"ERROR: {i:D4} {x}"))); return(false); } finally { Diagnostics.ForEach(x => Console.WriteLine(x.ToString())); // strings only, since the Console.Out textwriter is another app domain... } }
private async Task <ProjectAnalysisResult> AnalyzeProjectCoreAsync(Project project, ImmutableArray <DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken = default) { LogHelpers.WriteUsedAnalyzers(analyzers, null, Options, ConsoleColor.DarkGray, Verbosity.Diagnostic); cancellationToken.ThrowIfCancellationRequested(); Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); ImmutableArray <Diagnostic> compilerDiagnostics = (Options.IgnoreCompilerDiagnostics) ? ImmutableArray <Diagnostic> .Empty : compilation.GetDiagnostics(cancellationToken); compilerDiagnostics = FilterDiagnostics(compilerDiagnostics, cancellationToken).ToImmutableArray(); ImmutableArray <Diagnostic> diagnostics = ImmutableArray <Diagnostic> .Empty; ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> telemetry = ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> .Empty; if (analyzers.Any()) { var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions( options: default(AnalyzerOptions), onAnalyzerException: default(Action <Exception, DiagnosticAnalyzer, Diagnostic>), concurrentAnalysis: Options.ConcurrentAnalysis, logAnalyzerExecutionTime: Options.LogAnalyzerExecutionTime, reportSuppressedDiagnostics: Options.ReportSuppressedDiagnostics); var compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, compilationWithAnalyzersOptions); if (Options.LogAnalyzerExecutionTime) { AnalysisResult analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false); diagnostics = analysisResult.GetAllDiagnostics(); telemetry = analysisResult.AnalyzerTelemetryInfo; } else { diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); } } string projectDirectoryPath = Path.GetDirectoryName(project.FilePath); LogHelpers.WriteDiagnostics(FilterDiagnostics(diagnostics.Where(f => f.IsAnalyzerExceptionDiagnostic()), cancellationToken).ToImmutableArray(), baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Detailed); #if DEBUG if (ConsoleOut.Verbosity >= Verbosity.Detailed && diagnostics.Any(f => f.IsAnalyzerExceptionDiagnostic())) { Console.Write("Stop (Y/N)? "); if (char.ToUpperInvariant((char)Console.Read()) == 'Y') { throw new OperationCanceledException(); } } #endif diagnostics = FilterDiagnostics(diagnostics.Where(f => !f.IsAnalyzerExceptionDiagnostic()), cancellationToken).ToImmutableArray(); LogHelpers.WriteDiagnostics(compilerDiagnostics, baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Normal); LogHelpers.WriteDiagnostics(diagnostics, baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Normal); return(new ProjectAnalysisResult(project.Id, analyzers, compilerDiagnostics, diagnostics, telemetry)); }
private async Task UpdateAnalyzerTelemetryDataAsync(DiagnosticAnalyzer analyzer, CompilationWithAnalyzers compilationWithAnalyzers) { try { var actionCounts = await compilationWithAnalyzers.GetAnalyzerActionCountsAsync(analyzer, _cancellationToken).ConfigureAwait(false); DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, actionCounts, _project, _owner.DiagnosticLogAggregator); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public void Dispose() { CompilationWithAnalyzers.ClearAnalyzerState(_workspaceAnalyzers); }
public async Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeAsync(CompilationWithAnalyzers compilation, Project project, bool forcedAnalysis, CancellationToken cancellationToken) { Contract.ThrowIfFalse(compilation.Analyzers.Length != 0); var workspace = project.Solution.Workspace; var service = workspace.Services.GetService <IRemoteHostClientService>(); if (service == null) { // host doesn't support RemoteHostService such as under unit test return(await AnalyzeInProcAsync(compilation, project, client : null, cancellationToken).ConfigureAwait(false)); } var remoteHostClient = await service.TryGetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); if (remoteHostClient == null) { // remote host is not running. this can happen if remote host is disabled. return(await AnalyzeInProcAsync(compilation, project, client : null, cancellationToken).ConfigureAwait(false)); } // out of proc analysis will use 2 source of analyzers. one is AnalyzerReference from project (nuget). and the other is host analyzers (vsix) // that are not part of roslyn solution. these host analyzers must be sync to OOP before hand by the Host. return(await AnalyzeOutOfProcAsync(remoteHostClient, compilation, project, forcedAnalysis, cancellationToken).ConfigureAwait(false)); }
public async Task<bool> RunAsync(CancellationToken cancellationToken = default(CancellationToken)) { try { // this parameter was introduced in rc3, all call to it seem to be using RuntimeEnvironment.GetRuntimeDirectory() // https://github.com/dotnet/roslyn/blob/0382e3e3fc543fc483090bff3ab1eaae39dfb4d9/src/Compilers/CSharp/csc/Program.cs#L18 var sdkDirectory = RuntimeEnvironment.GetRuntimeDirectory(); CscArgs = CSharpCommandLineParser.Default.Parse(_precompilationCommandLineArgs.Arguments, _precompilationCommandLineArgs.BaseDirectory, sdkDirectory); Diagnostics = new List<Diagnostic>(CscArgs.Errors); // load those before anything else hooks into our AssemlbyResolve... var compilationModules = LoadModules().ToList(); if (Diagnostics.Any()) { return false; } Encoding = CscArgs.Encoding ?? new UTF8Encoding(false); // utf8 without bom var outputPath = Path.Combine(CscArgs.OutputDirectory, CscArgs.OutputFileName); var pdbPath = CscArgs.PdbPath ?? Path.ChangeExtension(outputPath, ".pdb"); using (var workspace = CreateWokspace()) using (var peStream = new MemoryStream()) using (var pdbStream = CscArgs.EmitPdb && CscArgs.EmitOptions.DebugInformationFormat != DebugInformationFormat.Embedded ? new MemoryStream() : null) using (var xmlDocumentationStream = !string.IsNullOrWhiteSpace(CscArgs.DocumentationPath) ? new MemoryStream() : null) using (var razorParser = CreateRazorParser(workspace, cancellationToken)) { EmitResult emitResult = null; var project = CreateProject(workspace, razorParser); CSharpCompilation compilation = null; CompilationWithAnalyzers compilationWithAnalyzers = null; try { compilation = await project.GetCompilationAsync(cancellationToken) as CSharpCompilation; await razorParser.Complete(); } catch (Exception ex) { Diagnostics.Add(Diagnostic.Create(FailedToCreateCompilation, Location.None, ex)); return false; } var analyzers = project.AnalyzerReferences.SelectMany(x => x.GetAnalyzers(project.Language)).ToImmutableArray(); if (!analyzers.IsEmpty) { compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, cancellationToken); compilation = compilationWithAnalyzers.Compilation as CSharpCompilation; } var context = new CompileContext(compilationModules); context.Before(new BeforeCompileContext { Arguments = CscArgs, Compilation = compilation.AddSyntaxTrees(GeneratedSyntaxTrees()), Diagnostics = Diagnostics, }); CscArgs = context.BeforeCompileContext.Arguments; compilation = context.BeforeCompileContext.Compilation; var analysisTask = compilationWithAnalyzers?.GetAnalysisResultAsync(cancellationToken); using (var win32Resources = CreateWin32Resource(compilation)) { // PathMapping is also required here, to actually get the symbols to line up: // https://github.com/dotnet/roslyn/blob/9d081e899b35294b8f1793d31abe5e2c43698844/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L616 // PathUtilities.NormalizePathPrefix is internal, but callable via the SourceFileResolver, that we set in CreateProject var emitOptions = CscArgs.EmitOptions .WithPdbFilePath(compilation.Options.SourceReferenceResolver.NormalizePath(pdbPath, CscArgs.BaseDirectory)); // https://github.com/dotnet/roslyn/blob/41950e21da3ac2c307fb46c2ca8c8509b5059909/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L437 emitResult = compilation.Emit( peStream: peStream, pdbStream: pdbStream, xmlDocumentationStream: xmlDocumentationStream, win32Resources: win32Resources, manifestResources: CscArgs.ManifestResources, options: emitOptions, sourceLinkStream: TryOpenFile(CscArgs.SourceLink, out var sourceLinkStream) ? sourceLinkStream : null, embeddedTexts: CscArgs.EmbeddedFiles.AsEnumerable() .Select(x => TryOpenFile(x.Path, out var embeddedText) ? EmbeddedText.FromStream(x.Path, embeddedText) : null) .Where(x => x != null), debugEntryPoint: null, cancellationToken: cancellationToken); } Diagnostics.AddRange(emitResult.Diagnostics); try { var analysisResult = analysisTask == null ? null : await analysisTask; if (analysisResult != null) { Diagnostics.AddRange(analysisResult.GetAllDiagnostics()); foreach (var info in analysisResult.AnalyzerTelemetryInfo) { Console.WriteLine($"hidden: {info.Key} {info.Value.ExecutionTime.TotalMilliseconds:#}ms"); } } } catch (OperationCanceledException) { Console.WriteLine("warning: analysis canceled"); } catch (Exception ex) { Diagnostics.Add(Diagnostic.Create(AnalysisFailed, Location.None, ex)); return false; } if (!emitResult.Success || HasErrors) { return false; } context.After(new AfterCompileContext { Arguments = CscArgs, AssemblyStream = peStream, Compilation = compilation, Diagnostics = Diagnostics, SymbolStream = pdbStream, XmlDocStream = xmlDocumentationStream, }); if (!HasErrors) { // do not create the output files if emit fails // if the output files are there, msbuild incremental build thinks the previous build succeeded await Task.WhenAll( DumpToFileAsync(outputPath, peStream, cancellationToken), DumpToFileAsync(pdbPath, pdbStream, cancellationToken), DumpToFileAsync(CscArgs.DocumentationPath, xmlDocumentationStream, cancellationToken)); return true; } return false; } } catch (PrecompilationModuleException pmex) { Diagnostics.Add(Diagnostic.Create(PrecompilationModuleFailed, Location.None, pmex.Message, pmex.InnerException)); return false; } catch (Exception ex) { Diagnostics.Add(Diagnostic.Create(UnhandledException, Location.None, ex)); return false; } finally { // strings only, since the Console.Out textwriter is another app domain... // https://stackoverflow.com/questions/2459994/is-there-a-way-to-print-a-new-line-when-using-message for (var i = 0; i < Diagnostics.Count; i++) { var d = Diagnostics[i]; if (!d.IsSuppressed && d.Severity != DiagnosticSeverity.Hidden) { Console.WriteLine(d.ToString().Replace("\r", "").Replace("\n", "\\n")); } } } }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// <paramref name="continueOnError"/> says whether the caller would like the exception thrown by the analyzers to be handled or not. If true - Handles ; False - Not handled. /// </summary> public static bool IsDiagnosticAnalyzerSuppressed(this DiagnosticAnalyzer analyzer, CompilationOptions options) { return(CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(analyzer, options)); }
public DiagnosticAnalyzerDriver( Project project, DiagnosticIncrementalAnalyzer owner, IEnumerable<DiagnosticAnalyzer> analyzers, bool concurrentAnalysis, bool reportSuppressedDiagnostics, CompilationWithAnalyzers cachedCompilationWithAnalyzersOpt, CancellationToken cancellationToken) { _project = project; _owner = owner; _analyzers = analyzers; _concurrentAnalysis = concurrentAnalysis; _reportSuppressedDiagnostics = reportSuppressedDiagnostics; _cancellationToken = cancellationToken; _lazyCompilationWithAnalyzers = cachedCompilationWithAnalyzersOpt; #if DEBUG // this is a bit wierd, but if both analyzers and compilationWithAnalyzers are given, // make sure both are same. if (_lazyCompilationWithAnalyzers != null) { Contract.ThrowIfFalse(_lazyCompilationWithAnalyzers.Analyzers.SetEquals(_analyzers)); } #endif }
/// <summary> /// Return all diagnostics that belong to given project for the given StateSets (analyzers) by calculating them /// </summary> public async Task<ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult>> ComputeDiagnosticsAsync( CompilationWithAnalyzers analyzerDriverOpt, Project project, IEnumerable<StateSet> stateSets, CancellationToken cancellationToken) { try { var result = ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult>.Empty; // analyzerDriver can be null if given project doesn't support compilation. if (analyzerDriverOpt != null) { // calculate regular diagnostic analyzers diagnostics var compilerResult = await analyzerDriverOpt.AnalyzeAsync(project, cancellationToken).ConfigureAwait(false); result = compilerResult.AnalysisResult; // record telemetry data UpdateAnalyzerTelemetryData(compilerResult, project, cancellationToken); } // check whether there is IDE specific project diagnostic analyzer return await MergeProjectDiagnosticAnalyzerDiagnosticsAsync(project, stateSets, analyzerDriverOpt?.Compilation, result, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private bool TryReduceAnalyzersToRun( CompilationWithAnalyzers analyzerDriverOpt, VersionStamp version, ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult> existing, out ImmutableArray<DiagnosticAnalyzer> analyzers) { analyzers = default(ImmutableArray<DiagnosticAnalyzer>); // we don't have analyzer driver, nothing to reduce. if (analyzerDriverOpt == null) { return false; } var existingAnalyzers = analyzerDriverOpt.Analyzers; var builder = ImmutableArray.CreateBuilder<DiagnosticAnalyzer>(); foreach (var analyzer in existingAnalyzers) { AnalysisResult analysisResult; if (existing.TryGetValue(analyzer, out analysisResult) && analysisResult.Version == version) { // we already have up to date result. continue; } // analyzer that is out of date. builder.Add(analyzer); } // if this condition is true, it shouldn't be called. Contract.ThrowIfTrue(builder.Count == 0); // all of analyzers are out of date. if (builder.Count == existingAnalyzers.Length) { return false; } analyzers = builder.ToImmutable(); return true; }
public static async Task <IEnumerable <Result> > Check(AnalysisDocument analysisDocument, CancellationToken cancellationToken) { var input = analysisDocument.DocumentContext; if (!AnalysisOptions.EnableFancyFeatures || input.Project == null || !input.IsCompileableInProject || input.AnalysisDocument == null) { return(Enumerable.Empty <Result> ()); } try { var model = input.ParsedDocument.GetAst <SemanticModel> (); if (model == null) { return(Enumerable.Empty <Result> ()); } var compilation = model.Compilation; var language = CodeRefactoringService.MimeTypeToLanguage(analysisDocument.Editor.MimeType); var providers = new List <DiagnosticAnalyzer> (); var alreadyAdded = new HashSet <Type>(); if (diagnostics == null) { diagnostics = await CodeRefactoringService.GetCodeDiagnosticsAsync(analysisDocument.DocumentContext, language, cancellationToken); } foreach (var diagnostic in diagnostics) { if (alreadyAdded.Contains(diagnostic.DiagnosticAnalyzerType)) { continue; } alreadyAdded.Add(diagnostic.DiagnosticAnalyzerType); var provider = diagnostic.GetProvider(); if (provider == null) { continue; } providers.Add(provider); } if (providers.Count == 0 || cancellationToken.IsCancellationRequested) { return(Enumerable.Empty <Result> ()); } #if DEBUG Debug.Listeners.Add(consoleTraceListener); #endif CompilationWithAnalyzers compilationWithAnalyzer; var analyzers = System.Collections.Immutable.ImmutableArray <DiagnosticAnalyzer> .Empty.AddRange(providers); var diagnosticList = new List <Diagnostic> (); try { compilationWithAnalyzer = compilation.WithAnalyzers(analyzers, null, cancellationToken); if (input.ParsedDocument == null || cancellationToken.IsCancellationRequested) { return(Enumerable.Empty <Result> ()); } diagnosticList.AddRange(await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync(model, null, cancellationToken).ConfigureAwait(false)); diagnosticList.AddRange(await compilationWithAnalyzer.GetAnalyzerSyntaxDiagnosticsAsync(model.SyntaxTree, cancellationToken).ConfigureAwait(false)); } catch (Exception) { return(Enumerable.Empty <Result> ()); } finally { #if DEBUG Debug.Listeners.Remove(consoleTraceListener); #endif CompilationWithAnalyzers.ClearAnalyzerState(analyzers); } return(diagnosticList .Where(d => !d.Id.StartsWith("CS", StringComparison.Ordinal)) .Select(diagnostic => { var res = new DiagnosticResult(diagnostic); // var line = analysisDocument.Editor.GetLineByOffset (res.Region.Start); // Console.WriteLine (diagnostic.Id + "/" + res.Region +"/" + analysisDocument.Editor.GetTextAt (line)); return res; })); } catch (OperationCanceledException) { return(Enumerable.Empty <Result> ()); } catch (AggregateException ae) { ae.Flatten().Handle(ix => ix is OperationCanceledException); return(Enumerable.Empty <Result> ()); } catch (Exception e) { LoggingService.LogError("Error while running diagnostics.", e); return(Enumerable.Empty <Result> ()); } }
private async Task UpdateAnalyzerTelemetryDataAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { foreach (var analyzer in analyzerDriver.Analyzers) { await UpdateAnalyzerTelemetryDataAsync(analyzerDriver, analyzer, project, cancellationToken).ConfigureAwait(false); } }
/// <summary> /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) by calculating them /// </summary> public async Task<IEnumerable<DiagnosticData>> ComputeDiagnosticsAsync( CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan? spanOpt, CancellationToken cancellationToken) { var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer; if (documentAnalyzer != null) { var diagnostics = await ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(document, documentAnalyzer, kind, analyzerDriverOpt?.Compilation, cancellationToken).ConfigureAwait(false); return ConvertToLocalDiagnostics(document, diagnostics); } var documentDiagnostics = await ComputeDiagnosticAnalyzerDiagnosticsAsync(analyzerDriverOpt, document, analyzer, kind, spanOpt, cancellationToken).ConfigureAwait(false); return ConvertToLocalDiagnostics(document, documentDiagnostics); }
internal AfterCompilationWithAnalyzersEventArgs(DiagnosticAnalyzer analyzer , CompilationWithAnalyzers compilationWithAnalyzers) { Analyzer = analyzer; CompilationWithAnalyzers = compilationWithAnalyzers; }
private async Task<ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult>> ComputeDiagnosticsAsync( CompilationWithAnalyzers analyzerDriverOpt, Project project, IEnumerable<StateSet> stateSets, ImmutableDictionary<DiagnosticAnalyzer, AnalysisResult> existing, CancellationToken cancellationToken) { try { // PERF: check whether we can reduce number of analyzers we need to run. // this can happen since caller could have created the driver with different set of analyzers that are different // than what we used to create the cache. var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); ImmutableArray<DiagnosticAnalyzer> analyzersToRun; if (TryReduceAnalyzersToRun(analyzerDriverOpt, version, existing, out analyzersToRun)) { // it looks like we can reduce the set. create new CompilationWithAnalyzer. var analyzerDriverWithReducedSet = await _owner._compilationManager.CreateAnalyzerDriverAsync( project, analyzersToRun, analyzerDriverOpt.AnalysisOptions.ReportSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); var result = await ComputeDiagnosticsAsync(analyzerDriverWithReducedSet, project, stateSets, cancellationToken).ConfigureAwait(false); return MergeExistingDiagnostics(version, existing, result); } // we couldn't reduce the set. return await ComputeDiagnosticsAsync(analyzerDriverOpt, project, stateSets, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync( CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { // quick bail out if (analyzerDriver.Analyzers.Length == 0) { return DiagnosticAnalysisResultMap.Create( ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty); } var executor = project.Solution.Workspace.Services.GetService<ICodeAnalysisDiagnosticAnalyzerExecutor>(); return await executor.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false); }
private async Task<IEnumerable<Diagnostic>> ComputeDiagnosticAnalyzerDiagnosticsAsync( CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan? spanOpt, CancellationToken cancellationToken) { // quick optimization to reduce allocations. if (analyzerDriverOpt == null || !_owner.SupportAnalysisKind(analyzer, document.Project.Language, kind)) { return ImmutableArray<Diagnostic>.Empty; } // REVIEW: more unnecessary allocations just to get diagnostics per analyzer var oneAnalyzers = ImmutableArray.Create(analyzer); switch (kind) { case AnalysisKind.Syntax: var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var diagnostics = await analyzerDriverOpt.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false); Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count()); return diagnostics.ToImmutableArrayOrEmpty(); case AnalysisKind.Semantic: var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); diagnostics = await analyzerDriverOpt.GetAnalyzerSemanticDiagnosticsAsync(model, spanOpt, oneAnalyzers, cancellationToken).ConfigureAwait(false); Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count()); return diagnostics.ToImmutableArrayOrEmpty(); default: return Contract.FailWithReturn<ImmutableArray<Diagnostic>>("shouldn't reach here"); } }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// <paramref name="continueOnError"/> says whether the caller would like the exception thrown by the analyzers to be handled or not. If true - Handles ; False - Not handled. /// </summary> public static bool IsDiagnosticAnalyzerSuppressed(this DiagnosticAnalyzer analyzer, CompilationOptions options) { return(CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(analyzer, options, (exception, throwingAnalyzer) => true)); }
public DiagnosticAnalyzerDriver( Project project, DiagnosticIncrementalAnalyzer owner, IEnumerable<DiagnosticAnalyzer> analyzers, bool concurrentAnalysis, bool reportSuppressedDiagnostics, CompilationWithAnalyzers cachedCompilationWithAnalyzersOpt, CancellationToken cancellationToken) { _project = project; _owner = owner; _analyzers = analyzers; _concurrentAnalysis = concurrentAnalysis; _reportSuppressedDiagnostics = reportSuppressedDiagnostics; _cancellationToken = cancellationToken; _lazyCompilationWithAnalyzers = cachedCompilationWithAnalyzersOpt; #if DEBUG // this is a bit wierd, but if both analyzers and compilationWithAnalyzers are given, // make sure both are same. // We also need to handle the fact that compilationWithAnalyzers is created with all non-supprssed analyzers. if (_lazyCompilationWithAnalyzers != null) { var filteredAnalyzers = _analyzers .Where(a => !CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(a, _lazyCompilationWithAnalyzers.Compilation.Options, _lazyCompilationWithAnalyzers.AnalysisOptions.OnAnalyzerException)) .Distinct(); Contract.ThrowIfFalse(_lazyCompilationWithAnalyzers.Analyzers.SetEquals(filteredAnalyzers)); } #endif }
public static async Task <ImmutableArray <Diagnostic> > GetAllDiagnosticsAsync(Compilation compilation, CompilationWithAnalyzers compilationWithAnalyzers, ImmutableArray <DiagnosticAnalyzer> analyzers, IEnumerable <Document> documents, bool includeCompilerDiagnostics, CancellationToken cancellationToken) { return(await compilationWithAnalyzers.GetAllDiagnosticsAsync().ConfigureAwait(false)); }
private async Task UpdateAnalyzerTelemetryDataAsync(DiagnosticAnalyzer analyzer, CompilationWithAnalyzers compilationWithAnalyzers) { var actionCounts = await compilationWithAnalyzers.GetAnalyzerActionCountsAsync(analyzer, _cancellationToken).ConfigureAwait(false); DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, actionCounts, _project, _owner.DiagnosticLogAggregator); }
public static async Task <ImmutableDictionary <DiagnosticAnalyzer, AnalysisResult> > AnalyzeAsync(this CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); // PERF: Run all analyzers at once using the new GetAnalysisResultAsync API. var analysisResult = await analyzerDriver.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false); var analyzers = analyzerDriver.Analyzers; var compilation = analyzerDriver.Compilation; var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalysisResult>(); foreach (var analyzer in analyzers) { var result = new Builder(project, version); foreach (var tree in compilation.SyntaxTrees) { ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > syntaxDiagnosticsByAnalyzer; ImmutableArray <Diagnostic> syntaxDiagnostics; if (analysisResult.SyntaxDiagnostics.TryGetValue(tree, out syntaxDiagnosticsByAnalyzer) && syntaxDiagnosticsByAnalyzer.TryGetValue(analyzer, out syntaxDiagnostics)) { Contract.Requires(syntaxDiagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(syntaxDiagnostics, analyzerDriver.Compilation).Count()); result.AddSyntaxDiagnostics(tree, syntaxDiagnostics); } ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > semanticDiagnosticsByAnalyzer; ImmutableArray <Diagnostic> semanticDiagnostics; if (analysisResult.SemanticDiagnostics.TryGetValue(tree, out semanticDiagnosticsByAnalyzer) && semanticDiagnosticsByAnalyzer.TryGetValue(analyzer, out semanticDiagnostics)) { Contract.Requires(semanticDiagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(semanticDiagnostics, analyzerDriver.Compilation).Count()); result.AddSemanticDiagnostics(tree, semanticDiagnostics); } } ImmutableArray <Diagnostic> compilationDiagnostics; if (analysisResult.CompilationDiagnostics.TryGetValue(analyzer, out compilationDiagnostics)) { Contract.Requires(compilationDiagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(compilationDiagnostics, analyzerDriver.Compilation).Count()); result.AddCompilationDiagnostics(compilationDiagnostics); } builder.Add(analyzer, result.ToResult()); } return(builder.ToImmutable()); }