internal static async Task<ImmutableArray<Diagnostic>> GetDiagnostics (Project project, List<DiagnosticAnalyzer> providers, CancellationToken token)
		{
			var analyzers = ImmutableArray<DiagnosticAnalyzer>.Empty.AddRange (providers);
			try {
				var compilation = await project.GetCompilationAsync (token).ConfigureAwait (false);
				CompilationWithAnalyzers compilationWithAnalyzer;
				var options = new CompilationWithAnalyzersOptions (
					null,
					delegate (Exception exception, DiagnosticAnalyzer analyzer, Diagnostic diag) {
						LoggingService.LogError ("Exception in diagnostic analyzer " + diag.Id + ":" + diag.GetMessage (), exception);
					},
					true,
					false
				);

				compilationWithAnalyzer = compilation.WithAnalyzers (analyzers, options);
				if (token.IsCancellationRequested)
					return ImmutableArray<Diagnostic>.Empty;

				return await compilationWithAnalyzer.GetAnalyzerDiagnosticsAsync ().ConfigureAwait (false);
			} catch (Exception) {
				return ImmutableArray<Diagnostic>.Empty;
			} finally {
				CompilationWithAnalyzers.ClearAnalyzerState (analyzers);
			}
		}
Exemplo n.º 2
0
 /// <summary>
 /// Returns a new compilation with attached diagnostic analyzers.
 /// </summary>
 /// <param name="compilation">Compilation to which analyzers are to be added.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="analysisOptions">Options to configure analyzer execution within <see cref="CompilationWithAnalyzers"/>.</param>
 public static CompilationWithAnalyzers WithAnalyzers(
     this Compilation compilation,
     ImmutableArray <DiagnosticAnalyzer> analyzers,
     CompilationWithAnalyzersOptions analysisOptions
     )
 {
     return(new CompilationWithAnalyzers(compilation, analyzers, analysisOptions));
 }
Exemplo n.º 3
0
        public async Task<DiagnosticAnalysisResultMap<string, DiagnosticAnalysisResultBuilder>> GetDiagnosticsAsync(
            IEnumerable<AnalyzerReference> hostAnalyzers,
            IEnumerable<string> analyzerIds,
            bool reportSuppressedDiagnostics,
            bool logAnalyzerExecutionTime,
            CancellationToken cancellationToken)
        {
            var analyzerMap = CreateAnalyzerMap(hostAnalyzers, _project);
            var analyzers = GetAnalyzers(analyzerMap, analyzerIds);

            if (analyzers.Length == 0)
            {
                return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<string, DiagnosticAnalysisResultBuilder>.Empty, ImmutableDictionary<string, AnalyzerTelemetryInfo>.Empty);
            }

            var compilation = await _project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            // TODO: can we support analyzerExceptionFilter in remote host? 
            //       right now, host doesn't support watson, we might try to use new NonFatal watson API?
            var analyzerOptions = new CompilationWithAnalyzersOptions(
                    options: _project.AnalyzerOptions,
                    onAnalyzerException: OnAnalyzerException,
                    analyzerExceptionFilter: null,
                    concurrentAnalysis: true,
                    logAnalyzerExecutionTime: logAnalyzerExecutionTime,
                    reportSuppressedDiagnostics: reportSuppressedDiagnostics);

            var analyzerDriver = compilation.WithAnalyzers(analyzers, analyzerOptions);

            // PERF: Run all analyzers at once using the new GetAnalysisResultAsync API.
            var analysisResult = await analyzerDriver.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false);

            // REVIEW: the design of current analyzer engine is that, information/states in CompilationWithAnalyzer (more specifically AnalyzerManager singleton)
            //         will live forever until analyzer references (analyzers), which is given to CompilationWithAnalyzer, go away.
            //         that is not suitable for OOP since OOP will create new workspace
            //         for each analysis but share all resources including analyzer references.
            //         until, we address this issue, OOP will clear state every time analysis is done.
            //
            //         * NOTE * this only works for now since we don't run analysis on multiple threads.
            //
            //         best way to fix this is doing this - https://github.com/dotnet/roslyn/issues/2830
            //         host should control lifetime of all information related to analyzer reference explicitly
            CompilationWithAnalyzers.ClearAnalyzerState(analyzers);

            var builderMap = analysisResult.ToResultBuilderMap(_project, VersionStamp.Default, compilation, analysisResult.Analyzers, cancellationToken);

            return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => GetAnalyzerId(analyzerMap, kv.Key), kv => kv.Value),
                                                      analysisResult.AnalyzerTelemetryInfo.ToImmutableDictionary(kv => GetAnalyzerId(analyzerMap, kv.Key), kv => kv.Value),
                                                      _exceptions.ToImmutableDictionary(kv => GetAnalyzerId(analyzerMap, kv.Key), kv => kv.Value.ToImmutableArray()));
        }
Exemplo n.º 4
0
        private CompilationWithAnalyzers(Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions, CancellationToken cancellationToken)
        {
            VerifyArguments(compilation, analyzers, analysisOptions);

            _compilation       = compilation.WithEventQueue(new AsyncQueue <CompilationEvent>());
            _analyzers         = analyzers;
            _analysisOptions   = analysisOptions;
            _cancellationToken = cancellationToken;

            _analysisState  = new AnalysisState(analyzers);
            _analysisResult = new AnalysisResult(analysisOptions.LogAnalyzerExecutionTime, analyzers);
            _driverPool     = new ObjectPool <AnalyzerDriver>(() => compilation.AnalyzerForLanguage(analyzers, AnalyzerManager.Instance));
            _executingConcurrentTreeTasksOpt             = analysisOptions.ConcurrentAnalysis ? new Dictionary <SyntaxTree, Tuple <Task, CancellationTokenSource> >() : null;
            _concurrentTreeTaskTokensOpt                 = analysisOptions.ConcurrentAnalysis ? new Dictionary <Task, int>() : null;
            _executingCompilationOrNonConcurrentTreeTask = null;
        }
Exemplo n.º 5
0
        // internal for testing purposes
        internal static AnalyzerDriver CreateAndAttachToCompilation(
            Compilation compilation,
            ImmutableArray<DiagnosticAnalyzer> analyzers,
            AnalyzerOptions options,
            AnalyzerManager analyzerManager,
            Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
            bool reportAnalyzer,
            out Compilation newCompilation,
            CancellationToken cancellationToken)
        {
            AnalyzerDriver analyzerDriver = compilation.AnalyzerForLanguage(analyzers, analyzerManager);
            newCompilation = compilation.WithEventQueue(new AsyncQueue<CompilationEvent>());

            var categorizeDiagnostics = false;
            var analysisOptions = new CompilationWithAnalyzersOptions(options, onAnalyzerException, concurrentAnalysis: true, logAnalyzerExecutionTime: reportAnalyzer);
            analyzerDriver.Initialize(newCompilation, analysisOptions, categorizeDiagnostics, cancellationToken);

            var analysisScope = new AnalysisScope(newCompilation, analyzers, concurrentAnalysis: newCompilation.Options.ConcurrentBuild, categorizeDiagnostics: categorizeDiagnostics);
            analyzerDriver.AttachQueueAndStartProcessingEvents(newCompilation.EventQueue, analysisScope, cancellationToken: cancellationToken);
            return analyzerDriver;
        }
Exemplo n.º 6
0
        internal void Initialize(
           Compilation compilation,
           CompilationWithAnalyzersOptions analysisOptions,
           bool categorizeDiagnostics,
           CancellationToken cancellationToken)
        {
            Debug.Assert(_initializeTask == null);

            var diagnosticQueue = DiagnosticQueue.Create(categorizeDiagnostics);
            var addDiagnostic = GetDiagnosticSinkWithSuppression(diagnosticQueue.Enqueue, compilation);
            var addLocalDiagnosticOpt = categorizeDiagnostics ? GetDiagnosticSinkWithSuppression(diagnosticQueue.EnqueueLocal, compilation) : null;
            var addNonLocalDiagnosticOpt = categorizeDiagnostics ? GetDiagnosticSinkWithSuppression(diagnosticQueue.EnqueueNonLocal, compilation) : null;

            Action<Exception, DiagnosticAnalyzer, Diagnostic> newOnAnalyzerException;
            if (analysisOptions.OnAnalyzerException != null)
            {
                // Wrap onAnalyzerException to pass in filtered diagnostic.
                var comp = compilation;
                newOnAnalyzerException = (ex, analyzer, diagnostic) =>
                    analysisOptions.OnAnalyzerException(ex, analyzer, GetFilteredDiagnostic(diagnostic, comp));
            }
            else
            {
                // Add exception diagnostic to regular diagnostic bag.
                newOnAnalyzerException = (ex, analyzer, diagnostic) => addDiagnostic(diagnostic);
            }

            // Assume all analyzers are non-thread safe.
            var singleThreadedAnalyzerToGateMap = ImmutableDictionary.CreateRange(analyzers.Select(a => KeyValuePair.Create(a, new object())));

            if (analysisOptions.LogAnalyzerExecutionTime)
            {
                // If we are reporting detailed analyzer performance numbers, then do a dummy invocation of Compilation.GetTypeByMetadataName API upfront.
                // This API seems to cause a severe hit for the first analyzer invoking it and hence introduces lot of noise in the computed analyzer execution times.
                var unused = compilation.GetTypeByMetadataName("System.Object");
            }

            Func<DiagnosticAnalyzer, object> getAnalyzerGate = analyzer => singleThreadedAnalyzerToGateMap[analyzer];
            var analyzerExecutor = AnalyzerExecutor.Create(compilation, analysisOptions.AnalyzerOptions ?? AnalyzerOptions.Empty, addDiagnostic, newOnAnalyzerException, IsCompilerAnalyzer,
                analyzerManager, getAnalyzerGate, analysisOptions.LogAnalyzerExecutionTime, addLocalDiagnosticOpt, addNonLocalDiagnosticOpt, cancellationToken);

            Initialize(analyzerExecutor, diagnosticQueue, cancellationToken);
        }
Exemplo n.º 7
0
        private static void VerifyArguments(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions)
        {
            if (compilation == null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }

            if (analysisOptions == null)
            {
                throw new ArgumentNullException(nameof(analysisOptions));
            }

            VerifyAnalyzersArgumentForStaticApis(analyzers);
        }
Exemplo n.º 8
0
        private CompilationWithAnalyzers(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions, CancellationToken cancellationToken)
        {
            VerifyArguments(compilation, analyzers, analysisOptions);

            _compilation = compilation.WithEventQueue(new AsyncQueue<CompilationEvent>());
            _analyzers = analyzers;
            _analysisOptions = analysisOptions;
            _cancellationToken = cancellationToken;

            _analysisState = new AnalysisState(analyzers);
            _analysisResult = new AnalysisResult(analysisOptions.LogAnalyzerExecutionTime, analyzers);
            _driverPool = new ObjectPool<AnalyzerDriver>(() => compilation.AnalyzerForLanguage(analyzers, AnalyzerManager.Instance));
            _executingConcurrentTreeTasksOpt = analysisOptions.ConcurrentAnalysis ? new Dictionary<SyntaxTree, Tuple<Task, CancellationTokenSource>>() : null;
            _concurrentTreeTaskTokensOpt = analysisOptions.ConcurrentAnalysis ? new Dictionary<Task, int>() : null;
            _executingCompilationOrNonConcurrentTreeTask = null;
        }
Exemplo n.º 9
0
 /// <summary>
 /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
 /// </summary>
 /// <param name="compilation">The original compilation.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="analysisOptions">Options to configure analyzer execution.</param>
 public CompilationWithAnalyzers(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions)
     : this(compilation, analyzers, analysisOptions, cancellationToken: CancellationToken.None)
 {
 }
Exemplo n.º 10
0
 /// <summary>
 /// Returns a new compilation with attached diagnostic analyzers.
 /// </summary>
 /// <param name="compilation">Compilation to which analyzers are to be added.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="analysisOptions">Options to configure analyzer execution within <see cref="CompilationWithAnalyzers"/>.</param>
 public static CompilationWithAnalyzers WithAnalyzers(this Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions)
 {
     return new CompilationWithAnalyzers(compilation, analyzers, analysisOptions);
 }
Exemplo n.º 11
0
        private static void VerifyArguments(Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions)
        {
            if (compilation == null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }

            if (analysisOptions == null)
            {
                throw new ArgumentNullException(nameof(analysisOptions));
            }

            VerifyAnalyzersArgumentForStaticApis(analyzers);
        }
Exemplo n.º 12
0
 /// <summary>
 /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
 /// </summary>
 /// <param name="compilation">The original compilation.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="analysisOptions">Options to configure analyzer execution.</param>
 public CompilationWithAnalyzers(Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions)
     : this(compilation, analyzers, analysisOptions, cancellationToken : CancellationToken.None)
 {
 }
		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 = await analysisDocument.DocumentContext.AnalysisDocument.GetSemanticModelAsync (cancellationToken);
				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);
				}
				var diagnosticTable = new Dictionary<string, CodeDiagnosticDescriptor> ();
				foreach (var diagnostic in diagnostics) {
					if (alreadyAdded.Contains (diagnostic.DiagnosticAnalyzerType))
						continue;
					if (!diagnostic.IsEnabled)
						continue;
					alreadyAdded.Add (diagnostic.DiagnosticAnalyzerType);
					var provider = diagnostic.GetProvider ();
					if (provider == null)
						continue;
					foreach (var diag in provider.SupportedDiagnostics)
						diagnosticTable [diag.Id] = diagnostic;
					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 {
					var options = new CompilationWithAnalyzersOptions (
						null, 
						delegate (Exception exception, DiagnosticAnalyzer analyzer, Diagnostic diag) {
							LoggingService.LogError ("Exception in diagnostic analyzer " + diag.Id + ":" + diag.GetMessage (), exception);
						},
						null, 
						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 (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))
					.Where (d => diagnosticTable[d.Id].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> ();
			}
		}
Exemplo n.º 14
0
        internal void Initialize(
           Compilation compilation,
           CompilationWithAnalyzersOptions analysisOptions,
           CompilationData compilationData,
           bool categorizeDiagnostics,
           CancellationToken cancellationToken)
        {
            Debug.Assert(_initializeTask == null);

            var diagnosticQueue = DiagnosticQueue.Create(categorizeDiagnostics);

            Action<Diagnostic> addNotCategorizedDiagnosticOpt = null;
            Action<Diagnostic, DiagnosticAnalyzer, bool> addCategorizedLocalDiagnosticOpt = null;
            Action<Diagnostic, DiagnosticAnalyzer> addCategorizedNonLocalDiagnosticOpt = null;
            if (categorizeDiagnostics)
            {
                addCategorizedLocalDiagnosticOpt = GetDiagnosticSink(diagnosticQueue.EnqueueLocal, compilation);
                addCategorizedNonLocalDiagnosticOpt = GetDiagnosticSink(diagnosticQueue.EnqueueNonLocal, compilation);
            }
            else
            {
                addNotCategorizedDiagnosticOpt = GetDiagnosticSink(diagnosticQueue.Enqueue, compilation);
            }

            // Wrap onAnalyzerException to pass in filtered diagnostic.
            Action<Exception, DiagnosticAnalyzer, Diagnostic> newOnAnalyzerException = (ex, analyzer, diagnostic) =>
            {
                var filteredDiagnostic = GetFilteredDiagnostic(diagnostic, compilation);
                if (filteredDiagnostic != null)
                {
                    if (analysisOptions.OnAnalyzerException != null)
                    {
                        analysisOptions.OnAnalyzerException(ex, analyzer, filteredDiagnostic);
                    }
                    else if (categorizeDiagnostics)
                    {
                        addCategorizedNonLocalDiagnosticOpt(filteredDiagnostic, analyzer);
                    }
                    else
                    {
                        addNotCategorizedDiagnosticOpt(filteredDiagnostic);
                    }
                }
            };

            if (analysisOptions.LogAnalyzerExecutionTime)
            {
                // If we are reporting detailed analyzer performance numbers, then do a dummy invocation of Compilation.GetTypeByMetadataName API upfront.
                // This API seems to cause a severe hit for the first analyzer invoking it and hence introduces lot of noise in the computed analyzer execution times.
                var unused = compilation.GetTypeByMetadataName("System.Object");
            }

            var analyzerExecutor = AnalyzerExecutor.Create(
                compilation, analysisOptions.Options ?? AnalyzerOptions.Empty, addNotCategorizedDiagnosticOpt, newOnAnalyzerException, analysisOptions.AnalyzerExceptionFilter,
                IsCompilerAnalyzer, analyzerManager, ShouldSkipAnalysisOnGeneratedCode, ShouldSuppressGeneratedCodeDiagnostic, GetAnalyzerGate,
                analysisOptions.LogAnalyzerExecutionTime, addCategorizedLocalDiagnosticOpt, addCategorizedNonLocalDiagnosticOpt, cancellationToken);

            Initialize(analyzerExecutor, diagnosticQueue, compilationData, cancellationToken);
        }