/// <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())));
            }
Esempio n. 8
0
 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);
            }
Esempio n. 10
0
        // 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));
            }
Esempio n. 12
0
 /// <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));
 }
Esempio n. 13
0
 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);
                    }
                }
            }
Esempio n. 15
0
        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);
        }
Esempio n. 16
0
            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)));
            }
Esempio n. 17
0
 private Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeInProcAsync(
     CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
 {
     return(AnalyzeInProcAsync(analyzerDriver, project, client: null, cancellationToken));
 }
Esempio n. 18
0
        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...
            }
        }
Esempio n. 20
0
        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"));
                    }
                }
            }
        }
Esempio n. 25
0
 /// <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));
 }
Esempio n. 26
0
        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
        }
Esempio n. 27
0
            /// <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;
                }
            }
Esempio n. 28
0
            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;
            }
Esempio n. 29
0
        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);
     }
 }
Esempio n. 31
0
            /// <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);
            }
Esempio n. 32
0
 internal AfterCompilationWithAnalyzersEventArgs(DiagnosticAnalyzer analyzer
                                                 , CompilationWithAnalyzers compilationWithAnalyzers)
 {
     Analyzer = analyzer;
     CompilationWithAnalyzers = compilationWithAnalyzers;
 }
Esempio n. 33
0
            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);
            }
Esempio n. 35
0
            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");
                }
            }
Esempio n. 36
0
 /// <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));
 }
Esempio n. 37
0
        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
        }
Esempio n. 38
0
 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());
        }