Exemplo n.º 1
0
        protected static void AnalyzeDocumentCore(IDiagnosticAnalyzer analyzer, Document document, Action <Diagnostic> addDiagnostic, TextSpan?span = null, bool continueOnError = false)
        {
            TextSpan spanToTest    = span.HasValue ? span.Value : document.GetSyntaxRootAsync().Result.FullSpan;
            var      semanticModel = document.GetSemanticModelAsync().Result;

            AnalyzerDriver.RunAnalyzers(semanticModel, spanToTest, ImmutableArray.Create(analyzer), addDiagnostic, continueOnError: continueOnError);
        }
Exemplo n.º 2
0
        private static TCompilation GetCompilationWithAnalyzerDiagnostics <TCompilation>(
            this TCompilation c,
            DiagnosticAnalyzer[] analyzers,
            AnalyzerOptions options,
            Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
            bool reportSuppressedDiagnostics,
            bool includeCompilerDiagnostics,
            out ImmutableArray <Diagnostic> diagnostics)
            where TCompilation : Compilation
        {
            var analyzersArray = analyzers.ToImmutableArray();

            if (reportSuppressedDiagnostics != c.Options.ReportSuppressedDiagnostics)
            {
                c = (TCompilation)c.WithOptions(c.Options.WithReportSuppressedDiagnostics(reportSuppressedDiagnostics));
            }

            var analyzerManager = new AnalyzerManager(analyzersArray);
            var driver          = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, analyzerManager, onAnalyzerException, null, false, out var newCompilation, CancellationToken.None);

            var compilerDiagnostics = newCompilation.GetDiagnostics();
            var analyzerDiagnostics = driver.GetDiagnosticsAsync(newCompilation).Result;
            var allDiagnostics      = includeCompilerDiagnostics ?
                                      compilerDiagnostics.AddRange(analyzerDiagnostics) :
                                      analyzerDiagnostics;

            diagnostics = driver.ApplyProgrammaticSuppressions(allDiagnostics, newCompilation);

            if (!reportSuppressedDiagnostics)
            {
                Assert.True(diagnostics.All(d => !d.IsSuppressed));
            }

            return((TCompilation)newCompilation); // note this is a new compilation
        }
Exemplo n.º 3
0
        private void GenerateSimulatedCompilationSourceEvents(
            SyntaxTree tree,
            Compilation compilation,
            Func <SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel,
            AnalyzerDriver driver,
            CancellationToken cancellationToken)
        {
            using (_gate.DisposableWait(cancellationToken))
            {
                if (_treesWithGeneratedSourceEvents.Contains(tree))
                {
                    return;
                }
            }

            var globalNs          = compilation.Assembly.GlobalNamespace;
            var symbols           = GetDeclaredSymbolsInTree(tree, compilation, getCachedSemanticModel, cancellationToken);
            var compilationEvents = CreateCompilationEventsForTree(symbols.Concat(globalNs), tree, compilation);

            using (_gate.DisposableWait(cancellationToken))
            {
                if (_treesWithGeneratedSourceEvents.Contains(tree))
                {
                    return;
                }

                OnCompilationEventsGenerated_NoLock(compilationEvents, tree, driver, cancellationToken);

                var added = _treesWithGeneratedSourceEvents.Add(tree);
                Debug.Assert(added);
            }
        }
Exemplo n.º 4
0
        void TestDisabledDiagnostics()
        {
            var disabledDiagDescriptor = new DiagnosticDescriptor("XX001", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Warning, isEnabledByDefault: false);
            var enabledDiagDescriptor  = new DiagnosticDescriptor("XX002", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true);

            var disabledDiag = CodeAnalysis.Diagnostic.Create(disabledDiagDescriptor, Location.None);
            var enabledDiag  = CodeAnalysis.Diagnostic.Create(enabledDiagDescriptor, Location.None);

            var diags = new[] { disabledDiag, enabledDiag };

            // Verify that only the enabled diag shows up after filtering.
            var options        = TestOptions.Dll;
            var comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            var effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();

            Assert.Equal(1, effectiveDiags.Length);
            Assert.Contains(enabledDiag, effectiveDiags);

            // If the disabled diag was enabled through options, then it should show up.
            var specificDiagOptions = new Dictionary <string, ReportDiagnostic>();

            specificDiagOptions.Add(disabledDiagDescriptor.Id, ReportDiagnostic.Warn);
            specificDiagOptions.Add(enabledDiagDescriptor.Id, ReportDiagnostic.Suppress);

            options        = TestOptions.Dll.WithSpecificDiagnosticOptions(specificDiagOptions);
            comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();
            Assert.Equal(1, effectiveDiags.Length);
            Assert.Contains(disabledDiag, effectiveDiags);
        }
Exemplo n.º 5
0
        static void FieldNameAnalyzerTest()
        {
            //
            // Construct a syntax tree and a compilation.
            //

            var tree = CSharpSyntaxTree.ParseText(@"
class Person
{
    private int _age;
}");

            var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location);

            var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

            var comp = CSharpCompilation.Create("Demo")
                       .AddSyntaxTrees(tree)
                       .AddReferences(mscorlib)
                       .WithOptions(options);


            //
            // Get diagnostics.
            //

            var diags = AnalyzerDriver.GetDiagnostics(comp, new[] { new FieldNameAnalyzer() }, null, CancellationToken.None);

            foreach (var diag in diags)
            {
                Console.WriteLine(diag);
            }
        }
Exemplo n.º 6
0
        private static TCompilation GetCompilationWithAnalyzerDiagnostics <TCompilation>(
            this TCompilation c,
            DiagnosticAnalyzer[] analyzers,
            AnalyzerOptions options,
            Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
            bool logAnalyzerExceptionAsDiagnostics,
            bool reportSuppressedDiagnostics,
            bool includeCompilerDiagnostics,
            out ImmutableArray <Diagnostic> diagnostics)
            where TCompilation : Compilation
        {
            var analyzersArray = analyzers.ToImmutableArray();

            var exceptionDiagnostics = new ConcurrentSet <Diagnostic>();

            if (onAnalyzerException == null)
            {
                if (logAnalyzerExceptionAsDiagnostics)
                {
                    onAnalyzerException = (ex, analyzer, diagnostic) =>
                    {
                        exceptionDiagnostics.Add(diagnostic);
                    };
                }
                else
                {
                    // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
                    onAnalyzerException = FailFastOnAnalyzerException;
                }
            }

            if (reportSuppressedDiagnostics != c.Options.ReportSuppressedDiagnostics)
            {
                c = (TCompilation)c.WithOptions(c.Options.WithReportSuppressedDiagnostics(reportSuppressedDiagnostics));
            }

            var analyzerManager = new AnalyzerManager(analyzersArray);
            var driver          = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, analyzerManager, onAnalyzerException, null, false, out var newCompilation, CancellationToken.None);

            var compilerDiagnostics = newCompilation.GetDiagnostics();
            var analyzerDiagnostics = driver.GetDiagnosticsAsync(newCompilation).Result;
            var allDiagnostics      = includeCompilerDiagnostics ?
                                      compilerDiagnostics.AddRange(analyzerDiagnostics) :
                                      analyzerDiagnostics;

            diagnostics = driver.ApplyProgrammaticSuppressions(allDiagnostics, newCompilation).AddRange(exceptionDiagnostics);

            if (!reportSuppressedDiagnostics)
            {
                Assert.True(diagnostics.All(d => !d.IsSuppressed));
            }

            return((TCompilation)newCompilation); // note this is a new compilation
        }
Exemplo n.º 7
0
        public IEnumerable <Diagnostic> GetDiagnostics(SyntaxTree syntaxTree)
        {
            var cancellationToken = new CancellationTokenSource().Token;

            Compilation compilation = CSharpCompilation.Create(null, ImmutableArray.Create(syntaxTree));

            var driver = AnalyzerDriver.Create(compilation, DiagnosticAnalyzers, null, out compilation, cancellationToken);

            compilation.GetDiagnostics(cancellationToken);
            return(driver.GetDiagnosticsAsync().Result);
        }
Exemplo n.º 8
0
        void TestGetEffectiveDiagnosticsGlobal()
        {
            var noneDiagDesciptor    = new DiagnosticDescriptor("XX0001", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Hidden, isEnabledByDefault: true);
            var infoDiagDesciptor    = new DiagnosticDescriptor("XX0002", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Info, isEnabledByDefault: true);
            var warningDiagDesciptor = new DiagnosticDescriptor("XX0003", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true);
            var errorDiagDesciptor   = new DiagnosticDescriptor("XX0004", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Error, isEnabledByDefault: true);

            var noneDiag    = Microsoft.CodeAnalysis.Diagnostic.Create(noneDiagDesciptor, Location.None);
            var infoDiag    = Microsoft.CodeAnalysis.Diagnostic.Create(infoDiagDesciptor, Location.None);
            var warningDiag = Microsoft.CodeAnalysis.Diagnostic.Create(warningDiagDesciptor, Location.None);
            var errorDiag   = Microsoft.CodeAnalysis.Diagnostic.Create(errorDiagDesciptor, Location.None);

            var diags = new [] { noneDiag, infoDiag, warningDiag, errorDiag };

            var options        = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Default);
            var comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            var effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();

            Assert.Equal(4, effectiveDiags.Length);

            options        = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Error);
            comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();
            Assert.Equal(4, effectiveDiags.Length);
            Assert.Equal(1, effectiveDiags.Count(d => d.IsWarningAsError));

            options        = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Warn);
            comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();
            Assert.Equal(4, effectiveDiags.Length);
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error));
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Warning));

            options        = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Info);
            comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();
            Assert.Equal(4, effectiveDiags.Length);
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error));
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Info));

            options        = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Hidden);
            comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();
            Assert.Equal(4, effectiveDiags.Length);
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error));
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Hidden));

            options        = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Suppress);
            comp           = CreateCompilationWithMscorlib45("", compOptions: options);
            effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray();
            Assert.Equal(2, effectiveDiags.Length);
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error));
            Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Hidden));
        }
Exemplo n.º 9
0
        public IEnumerable <Diagnostic> GetDiagnostics(SyntaxTree syntaxTree)
        {
            var cancellationToken = new CancellationTokenSource().Token;
            // FIXME Cannot dispose() because of violation of invariant in
            // http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/DiagnosticAnalyzer/AsyncQueue.cs,187
            var driver = new AnalyzerDriver <SyntaxKind>(DiagnosticAnalyzers, n => n.CSharpKind(), null, cancellationToken, null);

            Compilation compilation = CSharpCompilation.Create(null, ImmutableArray.Create(syntaxTree));

            compilation = compilation.WithEventQueue(driver.CompilationEventQueue);
            compilation.GetDiagnostics(cancellationToken);

            return(driver.GetDiagnosticsAsync().Result);
        }
Exemplo n.º 10
0
        private async Task EnsureAnalyzerActionCountsInitializedAsync(AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            if (_lazyAnalyzerActionCountsMap == null)
            {
                var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalyzerActionCounts>();
                foreach (var(analyzer, _) in _analyzerStateMap)
                {
                    var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, _compilationOptions, cancellationToken).ConfigureAwait(false);

                    builder.Add(analyzer, actionCounts);
                }

                Interlocked.CompareExchange(ref _lazyAnalyzerActionCountsMap, builder.ToImmutable(), null);
            }
        }
Exemplo n.º 11
0
        static void ConfigureAwaitAnalyzerTest()
        {
            //
            // Construct a syntax tree and a compilation.
            //

            var tree = CSharpSyntaxTree.ParseText(@"
using System.Threading.Tasks;

class Foo
{
    async Task Bar(Task t)
    {
        await t;
    }

    async Task<int> Baz(Task<int> t)
    {
        return await t;
    }

    async Task Qux(Task t)
    {
        await t.ConfigureAwait(false);
    }
}");

            var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location);

            var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

            var comp = CSharpCompilation.Create("Demo")
                       .AddSyntaxTrees(tree)
                       .AddReferences(mscorlib)
                       .WithOptions(options);


            //
            // Get diagnostics.
            //

            var diags = AnalyzerDriver.GetDiagnostics(comp, new[] { new ConfigureAwaitAnalyzer() }, null, CancellationToken.None);

            foreach (var diag in diags)
            {
                Console.WriteLine(diag);
            }
        }
        protected static async Task <IReadOnlyCollection <Diagnostic> > GetDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document document)
        {
            var compilation = await document.Project.GetCompilationAsync();

            var tree = await document.GetSyntaxTreeAsync();

            var driver = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, CancellationToken.None);

            compilation.GetDiagnostics();
            var diagnostics = (await driver.GetDiagnosticsAsync())
                              .Where(d => d.Location == Location.None || d.Location.IsInMetadata || d.Location.SourceTree == tree)
                              .OrderBy(d => d.Location.SourceSpan.Start)
                              .ToList();

            return(new ReadOnlyCollection <Diagnostic>(diagnostics));
        }
Exemplo n.º 13
0
        internal void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver, Compilation compilation, Func <DiagnosticAnalyzer, AnalyzerActionCounts> getAnalyzerActionCounts, bool fullAnalysisResultForAnalyzersInScope)
        {
            Debug.Assert(!fullAnalysisResultForAnalyzersInScope || analysisScope.FilterTreeOpt == null, "Full analysis result cannot come from partial (tree) analysis.");

            foreach (var analyzer in analysisScope.Analyzers)
            {
                // Dequeue reported analyzer diagnostics from the driver and store them in our maps.
                var syntaxDiagnostics      = driver.DequeueLocalDiagnostics(analyzer, syntax: true, compilation: compilation);
                var semanticDiagnostics    = driver.DequeueLocalDiagnostics(analyzer, syntax: false, compilation: compilation);
                var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer, compilation);

                lock (_gate)
                {
                    if (_completedAnalyzers.Contains(analyzer))
                    {
                        // Already stored full analysis result for this analyzer.
                        continue;
                    }

                    if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0 || fullAnalysisResultForAnalyzersInScope)
                    {
                        UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSyntaxDiagnosticsOpt);
                        UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSemanticDiagnosticsOpt);
                        UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics, fullAnalysisResultForAnalyzersInScope);
                    }

                    if (_analyzerExecutionTimeOpt != null)
                    {
                        var timeSpan = driver.ResetAnalyzerExecutionTime(analyzer);
                        _analyzerExecutionTimeOpt[analyzer] = fullAnalysisResultForAnalyzersInScope ?
                                                              timeSpan :
                                                              _analyzerExecutionTimeOpt[analyzer] + timeSpan;
                    }

                    if (!_analyzerActionCounts.ContainsKey(analyzer))
                    {
                        _analyzerActionCounts.Add(analyzer, getAnalyzerActionCounts(analyzer));
                    }

                    if (fullAnalysisResultForAnalyzersInScope)
                    {
                        _completedAnalyzers.Add(analyzer);
                    }
                }
            }
        }
Exemplo n.º 14
0
        /// <summary>
        /// Given an analyzer and a collection of documents to apply it to, run the analyzer and gather an array of
        /// diagnostics found. The returned diagnostics are then ordered by location in the source documents.
        /// </summary>
        /// <param name="analyzer">The analyzer to run on the documents.</param>
        /// <param name="documents">The <see cref="Document"/>s that the analyzer will be run on.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param>
        /// <returns>A collection of <see cref="Diagnostic"/>s that surfaced in the source code, sorted by
        /// <see cref="Diagnostic.Location"/>.</returns>
        protected static async Task <ImmutableArray <Diagnostic> > GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document[] documents, CancellationToken cancellationToken)
        {
            var projects = new HashSet <Project>();

            foreach (var document in documents)
            {
                projects.Add(document.Project);
            }

            var diagnostics = ImmutableArray.CreateBuilder <Diagnostic>();

            foreach (var project in projects)
            {
                var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var driver    = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, cancellationToken);
                var discarded = compilation.GetDiagnostics(cancellationToken);
                var diags     = await driver.GetDiagnosticsAsync().ConfigureAwait(false);

                foreach (var diag in diags)
                {
                    if (diag.Location == Location.None || diag.Location.IsInMetadata)
                    {
                        diagnostics.Add(diag);
                    }
                    else
                    {
                        for (int i = 0; i < documents.Length; i++)
                        {
                            var document = documents[i];
                            var tree     = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                            if (tree == diag.Location.SourceTree)
                            {
                                diagnostics.Add(diag);
                            }
                        }
                    }
                }
            }

            var results = SortDiagnostics(diagnostics);

            return(results.ToImmutableArray());
        }
        /// <summary>
        /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it.
        /// The returned diagnostics are then ordered by location in the source document.
        /// </summary>
        /// <param name="analyzer">The analyzer to run on the documents</param>
        /// <param name="documents">The Documents that the analyzer will be run on</param>
        /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param>
        /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns>
        protected async static Task <Diagnostic[]> GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document[] documents)
        {
            var projects = new HashSet <Project>();

            foreach (var document in documents)
            {
                projects.Add(document.Project);
            }

            var diagnostics = new List <Diagnostic>();

            foreach (var project in projects)
            {
                var compilation = await project.GetCompilationAsync();

                var driver    = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, CancellationToken.None);
                var discarded = compilation.GetDiagnostics();
                var diags     = await driver.GetDiagnosticsAsync();

                foreach (var diag in diags)
                {
                    if (diag.Location == Location.None || diag.Location.IsInMetadata)
                    {
                        diagnostics.Add(diag);
                    }
                    else
                    {
                        foreach (var document in documents)
                        {
                            var tree = await document.GetSyntaxTreeAsync();

                            if (tree == diag.Location.SourceTree)
                            {
                                diagnostics.Add(diag);
                            }
                        }
                    }
                }
            }

            var results = SortDiagnostics(diagnostics);

            diagnostics.Clear();
            return(results);
        }
Exemplo n.º 16
0
        private static TCompilation GetAnalyzerDiagnostics <TCompilation>(
            this TCompilation c,
            DiagnosticAnalyzer[] analyzers,
            AnalyzerOptions options,
            Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
            out ImmutableArray <Diagnostic> diagnostics)
            where TCompilation : Compilation
        {
            // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
            continueOnAnalyzerException = continueOnAnalyzerException ?? DonotCatchAnalyzerExceptions;

            Compilation newCompilation;
            var         driver    = AnalyzerDriver.Create(c, analyzers.ToImmutableArray(), options, out newCompilation, continueOnAnalyzerException, CancellationToken.None);
            var         discarded = newCompilation.GetDiagnostics();

            diagnostics = driver.GetDiagnosticsAsync().Result;
            return((TCompilation)newCompilation); // note this is a new compilation
        }
Exemplo n.º 17
0
        /// <summary>
        /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it.
        /// The returned diagnostics are then ordered by location in the source document.
        /// </summary>
        /// <param name="analyzer">The analyzer to run on the documents</param>
        /// <param name="documents">The Documents that the analyzer will be run on</param>
        /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param>
        /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns>
        protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(IDiagnosticAnalyzer analyzer, Document[] documents)
        {
            var projects = new HashSet <Project>();

            foreach (var document in documents)
            {
                projects.Add(document.Project);
            }

            var diagnostics = new List <Diagnostic>();

            foreach (var project in projects)
            {
                var compilation = project.GetCompilationAsync().Result;
                var driver      = new AnalyzerDriver <SyntaxKind>((new[] { analyzer }).ToImmutableArray(), n => n.CSharpKind(), null, CancellationToken.None);
                compilation = compilation.WithEventQueue(driver.CompilationEventQueue);
                var discarded = compilation.GetDiagnostics();
                var diags     = driver.GetDiagnosticsAsync().Result;
                foreach (var diag in diags)
                {
                    if (diag.Location == Location.None || diag.Location.IsInMetadata)
                    {
                        diagnostics.Add(diag);
                    }
                    else
                    {
                        for (int i = 0; i < documents.Length; i++)
                        {
                            var document = documents[i];
                            var tree     = document.GetSyntaxTreeAsync().Result;
                            if (tree == diag.Location.SourceTree)
                            {
                                diagnostics.Add(diag);
                            }
                        }
                    }
                }
            }

            var results = SortDiagnostics(diagnostics);

            diagnostics.Clear();
            return(results);
        }
Exemplo n.º 18
0
        void TestDisabledAnalyzers()
        {
            var fullyDisabledAnalyzer     = new FullyDisabledAnalyzer();
            var partiallyDisabledAnalyzer = new PartiallyDisabledAnalyzer();

            var options = TestOptions.Dll;

            Assert.True(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(fullyDisabledAnalyzer, options));
            Assert.False(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(partiallyDisabledAnalyzer, options));

            var specificDiagOptions = new Dictionary <string, ReportDiagnostic>();

            specificDiagOptions.Add(FullyDisabledAnalyzer.desc1.Id, ReportDiagnostic.Warn);
            specificDiagOptions.Add(PartiallyDisabledAnalyzer.desc2.Id, ReportDiagnostic.Suppress);

            options = TestOptions.Dll.WithSpecificDiagnosticOptions(specificDiagOptions);
            Assert.False(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(fullyDisabledAnalyzer, options));
            Assert.True(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(partiallyDisabledAnalyzer, options));
        }
Exemplo n.º 19
0
        private static TCompilation GetAnalyzerDiagnostics <TCompilation>(
            this TCompilation c,
            DiagnosticAnalyzer[] analyzers,
            AnalyzerOptions options,
            Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
            bool logAnalyzerExceptionAsDiagnostics,
            bool reportDiagnosticsWithSourceSuppressions,
            out ImmutableArray <Diagnostic> diagnostics)
            where TCompilation : Compilation
        {
            var analyzersArray = analyzers.ToImmutableArray();

            var exceptionDiagnostics = new ConcurrentSet <Diagnostic>();

            if (onAnalyzerException == null)
            {
                if (logAnalyzerExceptionAsDiagnostics)
                {
                    onAnalyzerException = (ex, analyzer, diagnostic) =>
                    {
                        exceptionDiagnostics.Add(diagnostic);
                    };
                }
                else
                {
                    // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
                    onAnalyzerException = FailFastOnAnalyzerException;
                }
            }

            Compilation newCompilation;
            var         driver    = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, AnalyzerManager.Instance, onAnalyzerException, false, reportDiagnosticsWithSourceSuppressions, out newCompilation, CancellationToken.None);
            var         discarded = newCompilation.GetDiagnostics();

            diagnostics = driver.GetDiagnosticsAsync(newCompilation).Result.AddRange(exceptionDiagnostics);

            if (!reportDiagnosticsWithSourceSuppressions)
            {
                Assert.True(diagnostics.All(d => !d.IsSuppressed));
            }

            return((TCompilation)newCompilation); // note this is a new compilation
        }
        /// <summary>
        /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it.
        /// The returned diagnostics are then ordered by location in the source document.
        /// </summary>
        /// <param name="analyzer">The analyzer to run on the documents</param>
        /// <param name="documents">The Documents that the analyzer will be run on</param>
        /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param>
        /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns>
        protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents)
        {
            var projects = new HashSet <Project>();

            foreach (var document in documents)
            {
                projects.Add(document.Project);
            }

            var diagnostics = new List <Diagnostic>();

            foreach (var project in projects)
            {
                var compilation = project.GetCompilationAsync().Result;
                var diags       = AnalyzerDriver.GetAnalyzerDiagnosticsAsync(compilation, ImmutableArray.Create(analyzer)).Result;
                foreach (var diag in diags)
                {
                    if (diag.Location == Location.None || diag.Location.IsInMetadata)
                    {
                        diagnostics.Add(diag);
                    }
                    else
                    {
                        for (int i = 0; i < documents.Length; i++)
                        {
                            var document = documents[i];
                            var tree     = document.GetSyntaxTreeAsync().Result;
                            if (tree == diag.Location.SourceTree)
                            {
                                diagnostics.Add(diag);
                            }
                        }
                    }
                }
            }

            var results = SortDiagnostics(diagnostics);

            diagnostics.Clear();
            return(results);
        }
Exemplo n.º 21
0
        public static ImmutableArray <Diagnostic> GetAnalyzerDiagnostics <TCompilation>(
            this TCompilation c,
            DiagnosticAnalyzer[] analyzers,
            TestValidationMode validationMode,
            AnalyzerOptions options = null,
            Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null,
            bool logAnalyzerExceptionAsDiagnostics = true)
            where TCompilation : Compilation
        {
            ImmutableArray <DiagnosticAnalyzer> analyzersArray = analyzers.ToImmutableArray();

            var exceptionDiagnostics = new ConcurrentSet <Diagnostic>();

            if (onAnalyzerException == null)
            {
                if (logAnalyzerExceptionAsDiagnostics)
                {
                    onAnalyzerException = (ex, analyzer, diagnostic) =>
                    {
                        exceptionDiagnostics.Add(diagnostic);
                    };
                }
                else
                {
                    // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
                    onAnalyzerException = FailFastOnAnalyzerException;
                }
            }

            Compilation    newCompilation;
            AnalyzerDriver driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, AnalyzerManager.Instance, onAnalyzerException, null, false, out newCompilation, CancellationToken.None);

            ImmutableArray <Diagnostic> diagnostics = newCompilation.GetDiagnostics();

            if (validationMode != TestValidationMode.AllowCompileErrors)
            {
                ValidateNoCompileErrors(diagnostics);
            }

            return(driver.GetDiagnosticsAsync(newCompilation).Result.AddRange(exceptionDiagnostics));
        }
Exemplo n.º 22
0
        private static TCompilation GetAnalyzerDiagnostics <TCompilation, TLanguageKindEnum>(
            this TCompilation c,
            Func <SyntaxNode, TLanguageKindEnum> getKind,
            DiagnosticAnalyzer[] analyzers,
            AnalyzerOptions options,
            Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
            out ImmutableArray <Diagnostic> diagnostics)
            where TCompilation : Compilation
            where TLanguageKindEnum : struct
        {
            // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
            continueOnAnalyzerException = continueOnAnalyzerException ?? DonotCatchAnalyzerExceptions;

            var driver = new AnalyzerDriver <TLanguageKindEnum>(analyzers.ToImmutableArray(), getKind, options, CancellationToken.None, continueOnAnalyzerException);

            c = (TCompilation)c.WithEventQueue(driver.CompilationEventQueue);
            var discarded = c.GetDiagnostics();

            diagnostics = driver.GetDiagnosticsAsync().Result;
            return(c); // note this is a new compilation
        }
Exemplo n.º 23
0
        public void Verify()
        {
            Assert.AreEqual(descriptors.Count, locations.Count, "Source code specifies {0} locations; {1} diagnostics provided", locations.Count, descriptors.Count);
            var project = CreateProject();

            var compilation = project.GetCompilationAsync().Result;
            var driver      = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, CancellationToken.None);
            // TODO: Work out why this is needed.
            var discarded = compilation.GetDiagnostics();
            var diags     = driver.GetDiagnosticsAsync().Result;
            // TODO: Work out what the code in DiagnosticVerifier was doing here... it seems unnecessarily complicated.

            // TODO: Handle diagnostics with no location?
            var actual = diags
                         .Select(SimplifiedDiagnostic.FromDiagnostic)
                         .OrderBy(sd => sd.Location)
                         .ToList();
            var expected = descriptors.Zip(locations, (d, l) => d.WithLocation(l)).ToList();

            CollectionAssert.AreEqual(expected, actual);
        }
Exemplo n.º 24
0
        public async Task GenerateSimulatedCompilationEventsAsync(
            AnalysisScope analysisScope,
            Compilation compilation,
            Func <SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel,
            AnalyzerDriver driver,
            CancellationToken cancellationToken)
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

            // Compilation started event.
            GenerateSimulatedCompilationNonSourceEvent(compilation, driver, started: true, cancellationToken: cancellationToken);

            // Symbol declared and compilation unit completed events.
            foreach (var tree in analysisScope.SyntaxTrees)
            {
                GenerateSimulatedCompilationSourceEvents(tree, compilation, getCachedSemanticModel, driver, cancellationToken);
            }

            // Compilation ended event.
            if (analysisScope.FilterTreeOpt == null)
            {
                GenerateSimulatedCompilationNonSourceEvent(compilation, driver, started: false, cancellationToken: cancellationToken);
            }
        }
Exemplo n.º 25
0
        private static void ReportAnalyzerExecutionTime(TextWriter consoleOutput, AnalyzerDriver analyzerDriver, CultureInfo culture, bool isConcurrentBuild)
        {
            Debug.Assert(analyzerDriver.AnalyzerExecutionTimes != null);
            if (analyzerDriver.AnalyzerExecutionTimes.IsEmpty)
            {
                return;
            }

            var totalAnalyzerExecutionTime         = analyzerDriver.AnalyzerExecutionTimes.Sum(kvp => kvp.Value.TotalSeconds);
            Func <double, string> getFormattedTime = d => d.ToString("##0.000", culture);

            consoleOutput.WriteLine();
            consoleOutput.WriteLine(string.Format(CodeAnalysisResources.AnalyzerTotalExecutionTime, getFormattedTime(totalAnalyzerExecutionTime)));

            if (isConcurrentBuild)
            {
                consoleOutput.WriteLine(CodeAnalysisResources.MultithreadedAnalyzerExecutionNote);
            }

            var analyzersByAssembly = analyzerDriver.AnalyzerExecutionTimes
                                      .GroupBy(kvp => kvp.Key.GetType().GetTypeInfo().Assembly)
                                      .OrderByDescending(kvp => kvp.Sum(entry => entry.Value.Ticks));

            consoleOutput.WriteLine();

            getFormattedTime = d => d < 0.001 ?
                               string.Format(culture, "{0,8:<0.000}", 0.001) :
                               string.Format(culture, "{0,8:##0.000}", d);
            Func <int, string>    getFormattedPercentage   = i => string.Format("{0,5}", i < 1 ? "<1" : i.ToString());
            Func <string, string> getFormattedAnalyzerName = s => "   " + s;

            // Table header
            var analyzerTimeColumn       = string.Format("{0,8}", CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader);
            var analyzerPercentageColumn = string.Format("{0,5}", "%");
            var analyzerNameColumn       = getFormattedAnalyzerName(CodeAnalysisResources.AnalyzerNameColumnHeader);

            consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn);

            // Table rows grouped by assembly.
            foreach (var analyzerGroup in analyzersByAssembly)
            {
                var executionTime = analyzerGroup.Sum(kvp => kvp.Value.TotalSeconds);
                var percentage    = (int)(executionTime * 100 / totalAnalyzerExecutionTime);

                analyzerTimeColumn       = getFormattedTime(executionTime);
                analyzerPercentageColumn = getFormattedPercentage(percentage);
                analyzerNameColumn       = getFormattedAnalyzerName(analyzerGroup.Key.FullName);

                consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn);

                // Rows for each diagnostic analyzer in the assembly.
                foreach (var kvp in analyzerGroup.OrderByDescending(kvp => kvp.Value))
                {
                    executionTime = kvp.Value.TotalSeconds;
                    percentage    = (int)(executionTime * 100 / totalAnalyzerExecutionTime);

                    analyzerTimeColumn       = getFormattedTime(executionTime);
                    analyzerPercentageColumn = getFormattedPercentage(percentage);
                    analyzerNameColumn       = getFormattedAnalyzerName("   " + kvp.Key.ToString());

                    consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn);
                }

                consoleOutput.WriteLine();
            }
        }
Exemplo n.º 26
0
        private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken)
        {
            Debug.Assert(!Arguments.IsScriptRunner);

            cancellationToken.ThrowIfCancellationRequested();

            if (Arguments.DisplayLogo)
            {
                PrintLogo(consoleOutput);
            }

            if (Arguments.DisplayHelp)
            {
                PrintHelp(consoleOutput);
                return(Succeeded);
            }

            if (ReportErrors(Arguments.Errors, consoleOutput, errorLogger))
            {
                return(Failed);
            }

            var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null;

            Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger, errorLogger);

            if (compilation == null)
            {
                return(Failed);
            }

            var diagnostics = new List <DiagnosticInfo>();
            ImmutableArray <DiagnosticAnalyzer> analyzers;
            ImmutableArray <SourceGenerator>    sourceGenerators;

            ResolveAnalyzersAndGeneratorsFromArguments(diagnostics, MessageProvider, out analyzers, out sourceGenerators);
            var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger);

            if (ReportErrors(diagnostics, consoleOutput, errorLogger))
            {
                return(Failed);
            }

            bool reportAnalyzer = false;
            CancellationTokenSource analyzerCts     = null;
            AnalyzerManager         analyzerManager = null;
            AnalyzerDriver          analyzerDriver  = null;

            try
            {
                // Print the diagnostics produced during the parsing stage and exit if there were any errors.
                if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                if (!sourceGenerators.IsEmpty)
                {
                    var trees = compilation.GenerateSource(sourceGenerators, this.Arguments.OutputDirectory, writeToDisk: true, cancellationToken: cancellationToken);
                    if (!trees.IsEmpty)
                    {
                        compilation = compilation.AddSyntaxTrees(trees);
                        if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger))
                        {
                            return(Failed);
                        }
                    }
                }

                ConcurrentSet <Diagnostic> analyzerExceptionDiagnostics = null;

                if (!analyzers.IsEmpty)
                {
                    analyzerCts     = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                    analyzerManager = new AnalyzerManager();
                    analyzerExceptionDiagnostics = new ConcurrentSet <Diagnostic>();
                    Action <Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic);
                    var analyzerOptions = new AnalyzerOptions(ImmutableArray <AdditionalText> .CastUp(additionalTextFiles));

                    analyzerDriver = AnalyzerDriver.CreateAndAttachToCompilation(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token);
                    reportAnalyzer = Arguments.ReportAnalyzer && !analyzers.IsEmpty;
                }

                if (ReportErrors(compilation.GetDeclarationDiagnostics(), consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                string outputName       = GetOutputFileName(compilation, cancellationToken);
                var    finalPeFilePath  = Path.Combine(Arguments.OutputDirectory, outputName);
                var    finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb");
                var    finalXmlFilePath = Arguments.DocumentationPath;

                var diagnosticBag = DiagnosticBag.GetInstance();

                try
                {
                    // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit.
                    var emitOptions = Arguments.EmitOptions.
                                      WithOutputNameOverride(outputName).
                                      WithPdbFilePath(finalPdbFilePath);

                    // The PDB path is emitted in it's entirety into the PE.  This makes it impossible to have deterministic
                    // builds that occur in different source directories.  To enable this we shave all path information from
                    // the PDB when specified by the user.
                    //
                    // This is a temporary work around to allow us to make progress with determinism.  The following issue
                    // tracks getting an official solution here.
                    //
                    // https://github.com/dotnet/roslyn/issues/9813
                    if (Arguments.ParseOptions.Features.ContainsKey("pdb-path-determinism") && !string.IsNullOrEmpty(emitOptions.PdbFilePath))
                    {
                        emitOptions = emitOptions.WithPdbFilePath(Path.GetFileName(emitOptions.PdbFilePath));
                    }

                    var moduleBeingBuilt = compilation.CheckOptionsAndCreateModuleBuilder(
                        diagnosticBag,
                        Arguments.ManifestResources,
                        emitOptions,
                        debugEntryPoint: null,
                        testData: null,
                        cancellationToken: cancellationToken);

                    if (moduleBeingBuilt != null)
                    {
                        bool success;

                        try
                        {
                            success = compilation.CompileMethods(
                                moduleBeingBuilt,
                                Arguments.EmitPdb,
                                diagnosticBag,
                                filterOpt: null,
                                cancellationToken: cancellationToken);

                            if (success)
                            {
                                // NOTE: as native compiler does, we generate the documentation file
                                // NOTE: 'in place', replacing the contents of the file if it exists
                                Stream xmlStreamOpt = null;

                                if (finalXmlFilePath != null)
                                {
                                    xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, PortableShim.FileMode.OpenOrCreate, PortableShim.FileAccess.Write, PortableShim.FileShare.ReadWriteBitwiseOrDelete);
                                    if (xmlStreamOpt == null)
                                    {
                                        return(Failed);
                                    }

                                    xmlStreamOpt.SetLength(0);
                                }

                                using (xmlStreamOpt)
                                {
                                    IEnumerable <DiagnosticInfo> errors;
                                    using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors))
                                    {
                                        if (ReportErrors(errors, consoleOutput, errorLogger))
                                        {
                                            return(Failed);
                                        }

                                        success = compilation.GenerateResourcesAndDocumentationComments(
                                            moduleBeingBuilt,
                                            xmlStreamOpt,
                                            win32ResourceStreamOpt,
                                            diagnosticBag,
                                            cancellationToken);
                                    }

                                    // only report unused usings if we have success.
                                    if (success)
                                    {
                                        compilation.ReportUnusedImports(null, diagnosticBag, cancellationToken);
                                    }
                                }
                            }

                            compilation.CompleteTrees(null);

                            if (analyzerDriver != null)
                            {
                                // GetDiagnosticsAsync is called after ReportUnusedImports
                                // since that method calls EventQueue.TryComplete. Without
                                // TryComplete, we may miss diagnostics.
                                var hostDiagnostics = analyzerDriver.GetDiagnosticsAsync(compilation).Result;
                                diagnosticBag.AddRange(hostDiagnostics);
                                if (hostDiagnostics.Any(IsReportedError))
                                {
                                    success = false;
                                }
                            }
                        }
                        finally
                        {
                            moduleBeingBuilt.CompilationFinished();
                        }

                        if (success)
                        {
                            using (var peStreamProvider = new CompilerEmitStreamProvider(this, finalPeFilePath))
                                using (var pdbStreamProviderOpt = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null)
                                {
                                    success = compilation.SerializeToPeStream(
                                        moduleBeingBuilt,
                                        peStreamProvider,
                                        pdbStreamProviderOpt,
                                        testSymWriterFactory: null,
                                        diagnostics: diagnosticBag,
                                        metadataOnly: emitOptions.EmitMetadataOnly,
                                        cancellationToken: cancellationToken);

                                    if (success && touchedFilesLogger != null)
                                    {
                                        if (pdbStreamProviderOpt != null)
                                        {
                                            touchedFilesLogger.AddWritten(finalPdbFilePath);
                                        }
                                        touchedFilesLogger.AddWritten(finalPeFilePath);
                                    }
                                }
                        }
                    }

                    var compileAndEmitDiagnostics = diagnosticBag.ToReadOnly();
                    GenerateSqmData(Arguments.CompilationOptions, compileAndEmitDiagnostics);

                    if (ReportErrors(compileAndEmitDiagnostics, consoleOutput, errorLogger))
                    {
                        return(Failed);
                    }
                }
                finally
                {
                    diagnosticBag.Free();
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (analyzerExceptionDiagnostics != null && ReportErrors(analyzerExceptionDiagnostics, consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                bool errorsReadingAdditionalFiles = false;
                foreach (var additionalFile in additionalTextFiles)
                {
                    if (ReportErrors(additionalFile.Diagnostics, consoleOutput, errorLogger))
                    {
                        errorsReadingAdditionalFiles = true;
                    }
                }

                if (errorsReadingAdditionalFiles)
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (Arguments.TouchedFilesPath != null)
                {
                    Debug.Assert(touchedFilesLogger != null);

                    if (finalXmlFilePath != null)
                    {
                        touchedFilesLogger.AddWritten(finalXmlFilePath);
                    }

                    var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate);
                    if (readStream == null)
                    {
                        return(Failed);
                    }

                    using (var writer = new StreamWriter(readStream))
                    {
                        touchedFilesLogger.WriteReadPaths(writer);
                    }

                    var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate);
                    if (writtenStream == null)
                    {
                        return(Failed);
                    }

                    using (var writer = new StreamWriter(writtenStream))
                    {
                        touchedFilesLogger.WriteWrittenPaths(writer);
                    }
                }
            }
            finally
            {
                // At this point analyzers are already complete in which case this is a no-op.  Or they are
                // still running because the compilation failed before all of the compilation events were
                // raised.  In the latter case the driver, and all its associated state, will be waiting around
                // for events that are never coming.  Cancel now and let the clean up process begin.
                if (analyzerCts != null)
                {
                    analyzerCts.Cancel();

                    if (analyzerManager != null)
                    {
                        // Clear cached analyzer descriptors and unregister exception handlers hooked up to the LocalizableString fields of the associated descriptors.
                        analyzerManager.ClearAnalyzerState(analyzers);
                    }

                    if (reportAnalyzer)
                    {
                        ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild);
                    }
                }
            }

            return(Succeeded);
        }
Exemplo n.º 27
0
        private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken)
        {
            Debug.Assert(!Arguments.IsInteractive);

            cancellationToken.ThrowIfCancellationRequested();

            if (Arguments.DisplayLogo)
            {
                PrintLogo(consoleOutput);
            }

            if (Arguments.DisplayHelp)
            {
                PrintHelp(consoleOutput);
                return(Succeeded);
            }

            if (ReportErrors(Arguments.Errors, consoleOutput, errorLogger))
            {
                return(Failed);
            }

            var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null;

            Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger, errorLogger);

            if (compilation == null)
            {
                return(Failed);
            }

            var diagnostics         = new List <DiagnosticInfo>();
            var analyzers           = ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger);
            var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger);

            if (ReportErrors(diagnostics, consoleOutput, errorLogger))
            {
                return(Failed);
            }

            cancellationToken.ThrowIfCancellationRequested();

            CancellationTokenSource analyzerCts     = null;
            AnalyzerManager         analyzerManager = null;
            AnalyzerDriver          analyzerDriver  = null;

            try
            {
                Func <ImmutableArray <Diagnostic> > getAnalyzerDiagnostics       = null;
                ConcurrentSet <Diagnostic>          analyzerExceptionDiagnostics = null;
                if (!analyzers.IsDefaultOrEmpty)
                {
                    analyzerCts     = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                    analyzerManager = new AnalyzerManager();
                    analyzerExceptionDiagnostics = new ConcurrentSet <Diagnostic>();
                    Action <Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic);
                    var analyzerOptions = new AnalyzerOptions(ImmutableArray <AdditionalText> .CastUp(additionalTextFiles));
                    analyzerDriver         = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token);
                    getAnalyzerDiagnostics = () => analyzerDriver.GetDiagnosticsAsync().Result;
                }

                // Print the diagnostics produced during the parsing stage and exit if there were any errors.
                if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                if (ReportErrors(compilation.GetDeclarationDiagnostics(), consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                EmitResult emitResult;

                // NOTE: as native compiler does, we generate the documentation file
                // NOTE: 'in place', replacing the contents of the file if it exists

                string finalPeFilePath;
                string finalPdbFilePath;
                string finalXmlFilePath;

                Stream xmlStreamOpt = null;

                cancellationToken.ThrowIfCancellationRequested();

                finalXmlFilePath = Arguments.DocumentationPath;
                if (finalXmlFilePath != null)
                {
                    xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, PortableShim.FileMode.OpenOrCreate, PortableShim.FileAccess.Write, PortableShim.FileShare.ReadWriteBitwiseOrDelete);
                    if (xmlStreamOpt == null)
                    {
                        return(Failed);
                    }

                    xmlStreamOpt.SetLength(0);
                }

                cancellationToken.ThrowIfCancellationRequested();

                IEnumerable <DiagnosticInfo> errors;
                using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors))
                    using (xmlStreamOpt)
                    {
                        if (ReportErrors(errors, consoleOutput, errorLogger))
                        {
                            return(Failed);
                        }

                        cancellationToken.ThrowIfCancellationRequested();

                        string outputName = GetOutputFileName(compilation, cancellationToken);

                        finalPeFilePath  = Path.Combine(Arguments.OutputDirectory, outputName);
                        finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb");

                        // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit.
                        var emitOptions = Arguments.EmitOptions.
                                          WithOutputNameOverride(outputName).
                                          WithPdbFilePath(finalPdbFilePath);

                        using (var peStreamProvider = new CompilerEmitStreamProvider(this, finalPeFilePath))
                            using (var pdbStreamProviderOpt = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null)
                            {
                                emitResult = compilation.Emit(
                                    peStreamProvider,
                                    pdbStreamProviderOpt,
                                    (xmlStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(xmlStreamOpt) : null,
                                    (win32ResourceStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(win32ResourceStreamOpt) : null,
                                    Arguments.ManifestResources,
                                    emitOptions,
                                    getAnalyzerDiagnostics,
                                    cancellationToken);

                                if (emitResult.Success && touchedFilesLogger != null)
                                {
                                    if (pdbStreamProviderOpt != null)
                                    {
                                        touchedFilesLogger.AddWritten(finalPdbFilePath);
                                    }

                                    touchedFilesLogger.AddWritten(finalPeFilePath);
                                }
                            }
                    }

                GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics);

                if (ReportErrors(emitResult.Diagnostics, consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (analyzerExceptionDiagnostics != null && ReportErrors(analyzerExceptionDiagnostics, consoleOutput, errorLogger))
                {
                    return(Failed);
                }

                bool errorsReadingAdditionalFiles = false;
                foreach (var additionalFile in additionalTextFiles)
                {
                    if (ReportErrors(additionalFile.Diagnostics, consoleOutput, errorLogger))
                    {
                        errorsReadingAdditionalFiles = true;
                    }
                }

                if (errorsReadingAdditionalFiles)
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (Arguments.TouchedFilesPath != null)
                {
                    Debug.Assert(touchedFilesLogger != null);

                    if (finalXmlFilePath != null)
                    {
                        touchedFilesLogger.AddWritten(finalXmlFilePath);
                    }

                    var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate);
                    if (readStream == null)
                    {
                        return(Failed);
                    }

                    using (var writer = new StreamWriter(readStream))
                    {
                        touchedFilesLogger.WriteReadPaths(writer);
                    }

                    var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate);
                    if (writtenStream == null)
                    {
                        return(Failed);
                    }

                    using (var writer = new StreamWriter(writtenStream))
                    {
                        touchedFilesLogger.WriteWrittenPaths(writer);
                    }
                }
            }
            finally
            {
                // At this point analyzers are already complete in which case this is a no-op.  Or they are
                // still running because the compilation failed before all of the compilation events were
                // raised.  In the latter case the driver, and all its associated state, will be waiting around
                // for events that are never coming.  Cancel now and let the clean up process begin.
                if (analyzerCts != null)
                {
                    analyzerCts.Cancel();

                    if (analyzerManager != null)
                    {
                        // Clear cached analyzer descriptors and unregister exception handlers hooked up to the LocalizableString fields of the associated descriptors.
                        analyzerManager.ClearAnalyzerState(analyzers);
                    }

                    if (Arguments.ReportAnalyzer && analyzerDriver != null && compilation != null)
                    {
                        ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild);
                    }
                }
            }

            return(Succeeded);
        }
Exemplo n.º 28
0
        /// <summary>
        /// csc.exe and vbc.exe entry point.
        /// </summary>
        public virtual int Run(TextWriter consoleOutput, CancellationToken cancellationToken)
        {
            Debug.Assert(!Arguments.IsInteractive);

            cancellationToken.ThrowIfCancellationRequested();

            if (Arguments.DisplayLogo)
            {
                PrintLogo(consoleOutput);
            }

            if (Arguments.DisplayHelp)
            {
                PrintHelp(consoleOutput);
                return(Succeeded);
            }

            if (PrintErrors(Arguments.Errors, consoleOutput))
            {
                return(Failed);
            }

            var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null;

            Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger);

            if (compilation == null)
            {
                return(Failed);
            }

            var diagnostics = new List <DiagnosticInfo>();
            var analyzers   = Arguments.ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger);

            if (PrintErrors(diagnostics, consoleOutput))
            {
                return(Failed);
            }

            cancellationToken.ThrowIfCancellationRequested();

            EmitResult emitResult;

            // EDMAURER: Don't yet know if there are method body errors. don't overwrite
            // any existing output files until the compilation is known to be successful.
            string tempExeFilename = null;
            string tempPdbFilename = null;

            // NOTE: as native compiler does, we generate the documentation file
            // NOTE: 'in place', replacing the contents of the file if it exists

            try
            {
                tempExeFilename = CreateTempFile(consoleOutput);

                // Can happen when temp directory is "full"
                if (tempExeFilename == null)
                {
                    return(Failed);
                }

                FileStream output = OpenFile(tempExeFilename, consoleOutput);
                if (output == null)
                {
                    return(Failed);
                }

                string finalOutputPath;
                string finalPdbFilePath;
                string finalXmlFilePath;

                using (output)
                {
                    FileStream pdb = null;
                    FileStream xml = null;

                    cancellationToken.ThrowIfCancellationRequested();

                    if (Arguments.CompilationOptions.DebugInformationKind != DebugInformationKind.None)
                    {
                        tempPdbFilename = CreateTempFile(consoleOutput);

                        if (tempPdbFilename == null)
                        {
                            return(Failed);
                        }

                        pdb = OpenFile(tempPdbFilename, consoleOutput);
                        if (pdb == null)
                        {
                            return(Failed);
                        }
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    finalXmlFilePath = Arguments.DocumentationPath;
                    if (finalXmlFilePath != null)
                    {
                        xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
                        if (xml == null)
                        {
                            return(Failed);
                        }
                        xml.SetLength(0);
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    IEnumerable <DiagnosticInfo> errors;
                    using (var win32Res = GetWin32Resources(Arguments, compilation, out errors))
                        using (pdb)
                            using (xml)
                            {
                                if (PrintErrors(errors, consoleOutput))
                                {
                                    return(Failed);
                                }

                                cancellationToken.ThrowIfCancellationRequested();

                                string outputName = GetOutputFileName(compilation, cancellationToken);

                                finalOutputPath  = Path.Combine(Arguments.OutputDirectory, outputName);
                                finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalOutputPath, ".pdb");

                                // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit.
                                emitResult = compilation.Emit(output, outputName, finalPdbFilePath, pdb, xml, cancellationToken, win32Res, Arguments.ManifestResources);
                            }
                }

                GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics);

                if (PrintErrors(emitResult.Diagnostics, consoleOutput))
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                var analyzerDiagnostics = AnalyzerDriver.GetDiagnostics(compilation, analyzers, default(CancellationToken));
                if (PrintErrors(analyzerDiagnostics, consoleOutput))
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (!TryDeleteFile(finalOutputPath, consoleOutput) || !TryMoveFile(tempExeFilename, finalOutputPath, consoleOutput))
                {
                    return(Failed);
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (tempPdbFilename != null)
                {
                    if (!TryDeleteFile(finalPdbFilePath, consoleOutput) || !TryMoveFile(tempPdbFilename, finalPdbFilePath, consoleOutput))
                    {
                        return(Failed);
                    }
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (Arguments.TouchedFilesPath != null)
                {
                    Debug.Assert(touchedFilesLogger != null);

                    touchedFilesLogger.AddWritten(tempExeFilename);
                    touchedFilesLogger.AddWritten(finalOutputPath);
                    if (tempPdbFilename != null)
                    {
                        touchedFilesLogger.AddWritten(tempPdbFilename);
                        touchedFilesLogger.AddWritten(finalPdbFilePath);
                    }
                    if (finalXmlFilePath != null)
                    {
                        touchedFilesLogger.AddWritten(finalXmlFilePath);
                    }


                    var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, FileMode.OpenOrCreate);
                    if (readStream == null)
                    {
                        return(Failed);
                    }

                    using (var writer = new StreamWriter(readStream))
                    {
                        touchedFilesLogger.WriteReadPaths(writer);
                    }

                    var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, FileMode.OpenOrCreate);
                    if (writtenStream == null)
                    {
                        return(Failed);
                    }

                    using (var writer = new StreamWriter(writtenStream))
                    {
                        touchedFilesLogger.WriteWrittenPaths(writer);
                    }
                }


                return(Succeeded);
            }
            finally
            {
                if (tempExeFilename != null)
                {
                    TryDeleteFile(tempExeFilename, consoleOutput: null);
                }

                if (tempPdbFilename != null)
                {
                    TryDeleteFile(tempPdbFilename, consoleOutput: null);
                }
            }
        }
Exemplo n.º 29
0
        static void SingleStatementBodyAnalyzerTest()
        {
            //
            // Construct a syntax tree and a compilation.
            //

            var tree = CSharpSyntaxTree.ParseText(@"
using System;

class Foo
{
    void If(int x)
    {
        if (x > 0)
            Console.WriteLine(x);
        else if (x == 0)
            Console.WriteLine(0);
        else if (x < 0)
            Console.WriteLine(-x);
    }

    void For()
    {
        for (int i = 0; i < 10; i++)
            Console.WriteLine(i);
    }

    void ForEach()
    {
        foreach (var x in new[] { 1, 2, 3 })
            Console.WriteLine(x);
    }

    void While()
    {
        while (true)
            Console.Write('.');
    }
}");

            var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location);

            var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

            var comp = CSharpCompilation.Create("Demo")
                       .AddSyntaxTrees(tree)
                       .AddReferences(mscorlib)
                       .WithOptions(options);


            //
            // Get diagnostics.
            //

            var diags = AnalyzerDriver.GetDiagnostics(comp, new[] { new SingleStatementBodyAnalyzer() }, null, CancellationToken.None);

            foreach (var diag in diags)
            {
                Console.WriteLine(diag);
            }
        }
Exemplo n.º 30
0
        public void AnalyzerDriverIsSafeAgainstAnalyzerExceptions()
        {
            var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode);

            ThrowingDiagnosticAnalyzer <SyntaxKind> .VerifyAnalyzerEngineIsSafeAgainstExceptions(analyzer =>
                                                                                                 AnalyzerDriver.GetDiagnostics(compilation, new[] { analyzer }, CancellationToken.None), typeof(AnalyzerDriver).Name);
        }