Ejemplo n.º 1
0
        private static void ExecuteAnalyzers(
            PreviewWorkspace previewWorkspace,
            ImmutableArray <DiagnosticAnalyzer> analyzers
            )
        {
            var analyzerOptions = new AnalyzerOptions(
                additionalFiles: ImmutableArray <AdditionalText> .Empty
                );
            var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(
                analyzerOptions,
                previewWorkspace.CurrentSolution
                );
            var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions(
                workspaceAnalyzerOptions,
                onAnalyzerException: null,
                concurrentAnalysis: false,
                logAnalyzerExecutionTime: false
                );
            var project     = previewWorkspace.CurrentSolution.Projects.Single();
            var compilation = project.GetRequiredCompilationAsync(CancellationToken.None).Result;
            var compilationWithAnalyzers = new CompilationWithAnalyzers(
                compilation,
                analyzers,
                compilationWithAnalyzersOptions
                );
            var result =
                compilationWithAnalyzers.GetAnalysisResultAsync(CancellationToken.None).Result;

            Assert.Equal(1, result.CompilationDiagnostics.Count);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Returns a list of all analysis results inside the specific project. This is an asynchronous operation.
        /// </summary>
        /// <param name="analyzers">The list of analyzers that should be used</param>
        /// <param name="project">The project that should be analyzed
        /// <see langword="false"/> to use the behavior configured for the specified <paramref name="project"/>.</param>
        /// <param name="cancellationToken">The cancellation token that the task will observe.</param>
        /// <returns>A list of analysis results inside the project</returns>
        private static async Task <AnalysisResult> GetProjectAnalysisResultAsync(
            ImmutableArray <DiagnosticAnalyzer> analyzers,
            Project project,
            Options analyzerOptionsInternal,
            CancellationToken cancellationToken)
        {
            WriteLine($"Running analyzers for {project.Name}", ConsoleColor.Gray);
            if (analyzerOptionsInternal.RunConcurrent)
            {
                await Task.Yield();
            }

            try
            {
                Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var newCompilation = compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(compilation.SyntaxTrees);

                var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution);
                CompilationWithAnalyzers compilationWithAnalyzers = newCompilation.WithAnalyzers(analyzers, new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, null, analyzerOptionsInternal.RunConcurrent, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: analyzerOptionsInternal.ReportSuppressedDiagnostics));
                var analystResult = await compilationWithAnalyzers.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false);

                return(analystResult);
            }
            catch (Exception e)
            {
                WriteLine($"Failed to analyze {project.Name} with {e.ToString()}", ConsoleColor.Red);
                return(null);
            }
        }
Ejemplo n.º 3
0
        public static async Task <ImmutableDictionary <DiagnosticAnalyzer, AnalysisResult> > AnalyzeAsync(this CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
        {
            var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

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

            var analyzers   = analyzerDriver.Analyzers;
            var compilation = analyzerDriver.Compilation;

            var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalysisResult>();

            foreach (var analyzer in analyzers)
            {
                var result = new Builder(project, version);

                foreach (var tree in compilation.SyntaxTrees)
                {
                    ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > syntaxDiagnosticsByAnalyzer;
                    ImmutableArray <Diagnostic> syntaxDiagnostics;
                    if (analysisResult.SyntaxDiagnostics.TryGetValue(tree, out syntaxDiagnosticsByAnalyzer) &&
                        syntaxDiagnosticsByAnalyzer.TryGetValue(analyzer, out syntaxDiagnostics))
                    {
                        Contract.Requires(syntaxDiagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(syntaxDiagnostics, analyzerDriver.Compilation).Count());
                        result.AddSyntaxDiagnostics(tree, syntaxDiagnostics);
                    }

                    ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > semanticDiagnosticsByAnalyzer;
                    ImmutableArray <Diagnostic> semanticDiagnostics;
                    if (analysisResult.SemanticDiagnostics.TryGetValue(tree, out semanticDiagnosticsByAnalyzer) &&
                        semanticDiagnosticsByAnalyzer.TryGetValue(analyzer, out semanticDiagnostics))
                    {
                        Contract.Requires(semanticDiagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(semanticDiagnostics, analyzerDriver.Compilation).Count());
                        result.AddSemanticDiagnostics(tree, semanticDiagnostics);
                    }
                }

                ImmutableArray <Diagnostic> compilationDiagnostics;
                if (analysisResult.CompilationDiagnostics.TryGetValue(analyzer, out compilationDiagnostics))
                {
                    Contract.Requires(compilationDiagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(compilationDiagnostics, analyzerDriver.Compilation).Count());
                    result.AddCompilationDiagnostics(compilationDiagnostics);
                }

                builder.Add(analyzer, result.ToResult());
            }

            return(builder.ToImmutable());
        }
Ejemplo n.º 4
0
        public void GetAnalyzerTelemetry()
        {
            var compilation             = CSharpCompilation.Create("c", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
            DiagnosticAnalyzer analyzer = new AnalyzerWithDisabledRules();
            var analyzers         = ImmutableArray.Create(analyzer);
            var analyzerOptions   = new AnalyzerOptions(ImmutableArray <AdditionalText> .Empty);
            var compWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, analyzerOptions, CancellationToken.None);

            var analysisResult = compWithAnalyzers.GetAnalysisResultAsync(CancellationToken.None).Result;

            Assert.Empty(analysisResult.CompilationDiagnostics);

            // Even though the analyzer registers a symbol action, it should never be invoked because all of its rules are disabled.
            var analyzerTelemetry = compWithAnalyzers.GetAnalyzerTelemetryInfoAsync(analyzer, CancellationToken.None).Result;

            Assert.Equal(0, analyzerTelemetry.SymbolActionsCount);
        }
        public async Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
        {
            if (analyzerDriver.Analyzers.Length == 0)
            {
                // quick bail out
                return(DiagnosticAnalysisResultMap.Create(ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> .Empty, ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> .Empty));
            }

            var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

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

            // get compiler result builder map
            var builderMap = analysisResult.ToResultBuilderMap(project, version, analyzerDriver.Compilation, analyzerDriver.Analyzers, cancellationToken);

            return(DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo));
        }
            public async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
            {
                if (analyzerDriver.Analyzers.Length == 0)
                {
                    // quick bail out
                    return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty);
                }

                var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

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

                // get compiler result builder map
                var builderMap = analysisResult.ToResultBuilderMap(project, version, analyzerDriver.Compilation, analyzerDriver.Analyzers, cancellationToken);

                return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo);
            }
        public async Task CA2247_DiagnosticsProduced()
        {
            var analysisResult = await CompilationWithAnalyzers.GetAnalysisResultAsync(CancellationToken.None);

            var diagnostics = analysisResult.GetAllDiagnostics(analysisResult.Analyzers.First());

            if (analysisResult.Analyzers.Length != 1)
            {
                throw new InvalidOperationException($"Expected a single analyzer but found '{analysisResult.Analyzers.Length}'");
            }

            if (analysisResult.CompilationDiagnostics.Count != 0)
            {
                throw new InvalidOperationException($"Expected no compilation diagnostics but found '{analysisResult.CompilationDiagnostics.Count}'");
            }

            if (diagnostics.Length != 3 * Constants.Number_Of_Code_Files)
            {
                throw new InvalidOperationException($"Expected '{3 * Constants.Number_Of_Code_Files:N0}' analyzer diagnostics but found '{diagnostics.Length}'");
            }
        }
        public async Task CA2247_Baseline()
        {
            var analysisResult = await BaselineCompilationWithAnalyzers.GetAnalysisResultAsync(CancellationToken.None);

            var diagnostics = analysisResult.GetAllDiagnostics(analysisResult.Analyzers.First());

            if (analysisResult.Analyzers.Length != 1)
            {
                throw new InvalidOperationException($"Expected a single analyzer but found '{analysisResult.Analyzers.Length}'");
            }

            if (analysisResult.CompilationDiagnostics.Count != 0)
            {
                throw new InvalidOperationException($"Expected no compilation diagnostics but found '{analysisResult.CompilationDiagnostics.Count}'");
            }

            if (diagnostics.Length != 0)
            {
                throw new InvalidOperationException($"Expected no analyzer diagnostics but found '{diagnostics.Length}'");
            }
        }
Ejemplo n.º 9
0
            private async Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeInProcAsync(
                CompilationWithAnalyzers compilation, Project project, RemoteHostClient?client, CancellationToken cancellationToken)
            {
                Debug.Assert(compilation.Analyzers.Length != 0);

                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

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

                // if remote host is there, report performance data
                var asyncToken = _asyncOperationListener.BeginAsyncOperation(nameof(AnalyzeInProcAsync));
                var _          = FireAndForgetReportAnalyzerPerformanceAsync(project, client, analysisResult, cancellationToken).CompletesAsyncOperation(asyncToken);

                // get compiler result builder map
                var builderMap = analysisResult.ToResultBuilderMap(project, version, compilation.Compilation, compilation.Analyzers, cancellationToken);

                return(DiagnosticAnalysisResultMap.Create(
                           builderMap.ToImmutableDictionary(kv => kv.Key, kv => DiagnosticAnalysisResult.CreateFromBuilder(kv.Value)),
                           analysisResult.AnalyzerTelemetryInfo));
            }
Ejemplo n.º 10
0
        private async Task <DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> > AnalyzeAsync(
            CompilationWithAnalyzers compilationWithAnalyzers,
            BidirectionalMap <string, DiagnosticAnalyzer> analyzerToIdMap,
            ImmutableArray <DiagnosticAnalyzer> analyzers,
            SkippedHostAnalyzersInfo skippedAnalyzersInfo,
            bool reportSuppressedDiagnostics,
            bool logPerformanceInfo,
            bool getTelemetryInfo,
            CancellationToken cancellationToken)
        {
            var documentAnalysisScope = _document != null
                ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind !.Value)
                : null;

            var(analysisResult, additionalPragmaSuppressionDiagnostics) = await compilationWithAnalyzers.GetAnalysisResultAsync(
                documentAnalysisScope, _project, _analyzerInfoCache, cancellationToken).ConfigureAwait(false);

            // Record performance if tracker is available
            if (logPerformanceInfo && _performanceTracker != null)
            {
                // +1 to include project itself
                var unitCount = documentAnalysisScope != null ? 1 : _project.DocumentIds.Count + 1;
                _performanceTracker.AddSnapshot(analysisResult.AnalyzerTelemetryInfo.ToAnalyzerPerformanceInfo(_analyzerInfoCache), unitCount);
            }

            var builderMap = await analysisResult.ToResultBuilderMapAsync(
                additionalPragmaSuppressionDiagnostics, documentAnalysisScope,
                _project, VersionStamp.Default, compilationWithAnalyzers.Compilation,
                analyzers, skippedAnalyzersInfo, reportSuppressedDiagnostics, cancellationToken).ConfigureAwait(false);

            var result    = builderMap.ToImmutableDictionary(kv => GetAnalyzerId(analyzerToIdMap, kv.Key), kv => kv.Value);
            var telemetry = getTelemetryInfo
                ? GetTelemetryInfo(analysisResult, analyzers, analyzerToIdMap)
                : ImmutableDictionary <string, AnalyzerTelemetryInfo> .Empty;

            return(DiagnosticAnalysisResultMap.Create(result, telemetry));
            private async Task <DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> > AnalyzeInProcAsync(
                CompilationWithAnalyzers analyzerDriver, Project project, RemoteHostClient client, CancellationToken cancellationToken)
            {
                if (analyzerDriver == null ||
                    analyzerDriver.Analyzers.Length == 0)
                {
                    // quick bail out
                    return(DiagnosticAnalysisResultMap.Create(ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> .Empty, ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> .Empty));
                }

                var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

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

                // if remote host is there, report performance data
                var asyncToken = _owner?.Listener.BeginAsyncOperation(nameof(AnalyzeInProcAsync));
                var _          = FireAndForgetReportAnalyzerPerformanceAsync(project, client, analysisResult, cancellationToken).CompletesAsyncOperation(asyncToken);

                // get compiler result builder map
                var builderMap = analysisResult.ToResultBuilderMap(project, version, analyzerDriver.Compilation, analyzerDriver.Analyzers, cancellationToken);

                return(DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => DiagnosticAnalysisResult.CreateFromBuilder(kv.Value)), analysisResult.AnalyzerTelemetryInfo));
            }
Ejemplo n.º 12
0
        /// <summary>
        /// Returns a list of all analysis results inside the specific project. This is an asynchronous operation.
        /// </summary>
        /// <param name="analyzers">The list of analyzers that should be used</param>
        /// <param name="project">The project that should be analyzed
        /// <see langword="false"/> to use the behavior configured for the specified <paramref name="project"/>.</param>
        /// <param name="cancellationToken">The cancellation token that the task will observe.</param>
        /// <returns>A list of analysis results inside the project</returns>
        private static async Task<AnalysisResult> GetProjectAnalysisResultAsync(
            ImmutableArray<DiagnosticAnalyzer> analyzers,
            Project project,
            Options analyzerOptionsInternal,
            CancellationToken cancellationToken)
        {
            WriteLine($"Running analyzers for {project.Name}", ConsoleColor.Gray);
            if (analyzerOptionsInternal.RunConcurrent)
            {
                await Task.Yield();
            }

            // update the project compilation options
            var modifiedSpecificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions
                .Add("AD0001", ReportDiagnostic.Error)
                .Add("AD0002", ReportDiagnostic.Error);
            // Report exceptions during the analysis process as errors
            var modifiedCompilationOptions = project.CompilationOptions.WithSpecificDiagnosticOptions(modifiedSpecificDiagnosticOptions);
            var processedProject = project.WithCompilationOptions(modifiedCompilationOptions);

            try
            {
                Compilation compilation = await processedProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
                var newCompilation = compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(compilation.SyntaxTrees);

                var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution.Options, project.Solution);
                CompilationWithAnalyzers compilationWithAnalyzers = newCompilation.WithAnalyzers(analyzers, new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, null, analyzerOptionsInternal.RunConcurrent, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: analyzerOptionsInternal.ReportSuppressedDiagnostics));
                var analystResult = await compilationWithAnalyzers.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false);
                return analystResult;
            }
            catch (Exception e)
            {
                WriteLine($"Failed to analyze {project.Name} with {e.ToString()}", ConsoleColor.Red);
                return null;
            }
        }
Ejemplo n.º 13
0
        private async Task <ProjectAnalysisResult> AnalyzeProjectCoreAsync(Project project, ImmutableArray <DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken = default)
        {
            LogHelpers.WriteUsedAnalyzers(analyzers, null, Options, ConsoleColors.DarkGray, Verbosity.Diagnostic);

            cancellationToken.ThrowIfCancellationRequested();

            Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            ImmutableArray <Diagnostic> compilerDiagnostics = (Options.IgnoreCompilerDiagnostics)
                ? ImmutableArray <Diagnostic> .Empty
                : compilation.GetDiagnostics(cancellationToken);

            compilerDiagnostics = FilterDiagnostics(compilerDiagnostics, project, cancellationToken).ToImmutableArray();

            ImmutableArray <Diagnostic> diagnostics = ImmutableArray <Diagnostic> .Empty;

            ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> telemetry = ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> .Empty;

            if (analyzers.Any())
            {
                var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions(
                    options: project.AnalyzerOptions,
                    onAnalyzerException: default(Action <Exception, DiagnosticAnalyzer, Diagnostic>),
                    concurrentAnalysis: Options.ConcurrentAnalysis,
                    logAnalyzerExecutionTime: Options.LogAnalyzerExecutionTime,
                    reportSuppressedDiagnostics: Options.ReportSuppressedDiagnostics);

                var compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, compilationWithAnalyzersOptions);

                if (Options.LogAnalyzerExecutionTime)
                {
                    AnalysisResult analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false);

                    diagnostics = analysisResult.GetAllDiagnostics();
                    telemetry   = analysisResult.AnalyzerTelemetryInfo;
                }
                else
                {
                    diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false);
                }
            }

            string projectDirectoryPath = Path.GetDirectoryName(project.FilePath);

            LogHelpers.WriteDiagnostics(FilterDiagnostics(diagnostics.Where(f => f.IsAnalyzerExceptionDiagnostic()), project, cancellationToken).ToImmutableArray(), baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: "  ", verbosity: Verbosity.Detailed);
#if DEBUG
            if (ConsoleOut.Verbosity >= Verbosity.Detailed &&
                diagnostics.Any(f => f.IsAnalyzerExceptionDiagnostic()))
            {
                Console.Write("Stop (Y/N)? ");

                if (char.ToUpperInvariant((char)Console.Read()) == 'Y')
                {
                    throw new OperationCanceledException();
                }
            }
#endif
            diagnostics = FilterDiagnostics(diagnostics.Where(f => !f.IsAnalyzerExceptionDiagnostic()), project, cancellationToken).ToImmutableArray();

            LogHelpers.WriteDiagnostics(compilerDiagnostics, baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: "  ", verbosity: Verbosity.Normal);

            LogHelpers.WriteDiagnostics(diagnostics, baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: "  ", verbosity: Verbosity.Normal);

            return(ProjectAnalysisResult.Create(project, compilerDiagnostics, diagnostics, telemetry));
        }
Ejemplo n.º 14
0
        public async Task <bool> RunAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                // this parameter was introduced in rc3, all call to it seem to be using RuntimeEnvironment.GetRuntimeDirectory()
                // https://github.com/dotnet/roslyn/blob/0382e3e3fc543fc483090bff3ab1eaae39dfb4d9/src/Compilers/CSharp/csc/Program.cs#L18
                var sdkDirectory = RuntimeEnvironment.GetRuntimeDirectory();

                CscArgs     = CSharpCommandLineParser.Default.Parse(_precompilationCommandLineArgs.Arguments, _precompilationCommandLineArgs.BaseDirectory, sdkDirectory);
                Diagnostics = new List <Diagnostic>(CscArgs.Errors);

                // load those before anything else hooks into our AssemlbyResolve.
                var loader = new PrecompilationModuleLoader(PrecompilerSection.Current);
                loader.ModuleInitializationFailed += (module, ex) =>
                {
                    Diagnostics.Add(Diagnostic.Create(
                                        FailedToCreateModule,
                                        Location.Create(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, new TextSpan(), new LinePositionSpan()),
                                        module.Type,
                                        ex.Message));
                };
                var compilationModules = loader.LoadedModules;

                if (Diagnostics.Any())
                {
                    return(false);
                }
                Encoding = CscArgs.Encoding ?? new UTF8Encoding(false); // utf8 without bom

                var outputPath = Path.Combine(CscArgs.OutputDirectory, CscArgs.OutputFileName);
                var pdbPath    = CscArgs.PdbPath ?? Path.ChangeExtension(outputPath, ".pdb");

                using (var container = CreateCompositionHost())
                    using (var workspace = CreateWokspace(container))
                        using (var peStream = new MemoryStream())
                            using (var pdbStream = CscArgs.EmitPdb && CscArgs.EmitOptions.DebugInformationFormat != DebugInformationFormat.Embedded ? new MemoryStream() : null)
                                using (var xmlDocumentationStream = !string.IsNullOrWhiteSpace(CscArgs.DocumentationPath) ? new MemoryStream() : null)
                                {
                                    EmitResult emitResult = null;

                                    var documentExtenders = workspace.Services.FindLanguageServices <IDocumentExtender>(_ => true).ToList();
                                    var project           = CreateProject(workspace, documentExtenders);
                                    CSharpCompilation        compilation = null;
                                    CompilationWithAnalyzers compilationWithAnalyzers = null;
                                    try
                                    {
                                        Diagnostics.AddRange((await Task.WhenAll(documentExtenders.Select(x => x.Complete()))).SelectMany(x => x));
                                        compilation = await project.GetCompilationAsync(cancellationToken) as CSharpCompilation;
                                    }
                                    catch (Exception ex)
                                    {
                                        Diagnostics.Add(Diagnostic.Create(FailedToCreateCompilation, Location.None, ex));
                                        return(false);
                                    }

                                    var analyzers = project.AnalyzerReferences.SelectMany(x => x.GetAnalyzers(project.Language)).ToImmutableArray();
                                    if (!analyzers.IsEmpty)
                                    {
                                        compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, cancellationToken);
                                        compilation = compilationWithAnalyzers.Compilation as CSharpCompilation;
                                    }

                                    var context = new CompileContext(compilationModules);
                                    context.Before(new BeforeCompileContext
                                    {
                                        Arguments   = CscArgs,
                                        Compilation = compilation.AddSyntaxTrees(GeneratedSyntaxTrees()),
                                        Diagnostics = Diagnostics,
                                    });

                                    CscArgs     = context.BeforeCompileContext.Arguments;
                                    compilation = context.BeforeCompileContext.Compilation;

                                    var analysisTask = compilationWithAnalyzers?.GetAnalysisResultAsync(cancellationToken);

                                    using (var win32Resources = CreateWin32Resource(compilation))
                                    {
                                        // PathMapping is also required here, to actually get the symbols to line up:
                                        // https://github.com/dotnet/roslyn/blob/9d081e899b35294b8f1793d31abe5e2c43698844/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L616
                                        // PathUtilities.NormalizePathPrefix is internal, but callable via the SourceFileResolver, that we set in CreateProject
                                        var emitOptions = CscArgs.EmitOptions
                                                          .WithPdbFilePath(compilation.Options.SourceReferenceResolver.NormalizePath(pdbPath, CscArgs.BaseDirectory));

                                        // https://github.com/dotnet/roslyn/blob/41950e21da3ac2c307fb46c2ca8c8509b5059909/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L437
                                        emitResult = compilation.Emit(
                                            peStream: peStream,
                                            pdbStream: pdbStream,
                                            xmlDocumentationStream: xmlDocumentationStream,
                                            win32Resources: win32Resources,
                                            manifestResources: CscArgs.ManifestResources,
                                            options: emitOptions,
                                            sourceLinkStream: TryOpenFile(CscArgs.SourceLink, out var sourceLinkStream) ? sourceLinkStream : null,
                                            embeddedTexts: CscArgs.EmbeddedFiles.AsEnumerable()
                                            .Select(x => TryOpenFile(x.Path, out var embeddedText) ? EmbeddedText.FromStream(x.Path, embeddedText) : null)
                                            .Where(x => x != null),
                                            debugEntryPoint: null,
                                            cancellationToken: cancellationToken);
                                    }

                                    Diagnostics.AddRange(emitResult.Diagnostics);

                                    try
                                    {
                                        var analysisResult = analysisTask == null ? null : await analysisTask;
                                        if (analysisResult != null)
                                        {
                                            Diagnostics.AddRange(analysisResult.GetAllDiagnostics());

                                            foreach (var info in analysisResult.AnalyzerTelemetryInfo)
                                            {
                                                Console.WriteLine($"hidden: {info.Key} {info.Value.ExecutionTime.TotalMilliseconds:#}ms");
                                            }
                                        }
                                    }
                                    catch (OperationCanceledException)
                                    {
                                        Console.WriteLine("warning: analysis canceled");
                                    }
                                    catch (Exception ex)
                                    {
                                        Diagnostics.Add(Diagnostic.Create(AnalysisFailed, Location.None, ex));
                                        return(false);
                                    }

                                    if (!emitResult.Success || HasErrors)
                                    {
                                        return(false);
                                    }

                                    context.After(new AfterCompileContext
                                    {
                                        Arguments      = CscArgs,
                                        AssemblyStream = peStream,
                                        Compilation    = compilation,
                                        Diagnostics    = Diagnostics,
                                        SymbolStream   = pdbStream,
                                        XmlDocStream   = xmlDocumentationStream,
                                    });

                                    if (!HasErrors)
                                    {
                                        // do not create the output files if emit fails
                                        // if the output files are there, msbuild incremental build thinks the previous build succeeded
                                        await Task.WhenAll(
                                            DumpToFileAsync(outputPath, peStream, cancellationToken),
                                            DumpToFileAsync(pdbPath, pdbStream, cancellationToken),
                                            DumpToFileAsync(CscArgs.DocumentationPath, xmlDocumentationStream, cancellationToken));

                                        return(true);
                                    }

                                    return(false);
                                }
            }
            catch (PrecompilationModuleException pmex)
            {
                Diagnostics.Add(Diagnostic.Create(PrecompilationModuleFailed, Location.None, pmex.Message, pmex.InnerException));
                return(false);
            }
            catch (Exception ex)
            {
                Diagnostics.Add(Diagnostic.Create(UnhandledException, Location.None, ex));
                return(false);
            }
            finally
            {
                // strings only, since the Console.Out textwriter is another app domain...
                // https://stackoverflow.com/questions/2459994/is-there-a-way-to-print-a-new-line-when-using-message
                for (var i = 0; i < Diagnostics.Count; i++)
                {
                    var d = Diagnostics[i];
                    if (!d.IsSuppressed && d.Severity != DiagnosticSeverity.Hidden)
                    {
                        Console.WriteLine(d.ToString().Replace("\r", "").Replace("\n", "\\n"));
                    }
                }
            }
        }
Ejemplo n.º 15
0
        public async Task <bool> RunAsync()
        {
            try
            {
                // this parameter was introduced in rc3, all call to it seem to be using RuntimeEnvironment.GetRuntimeDirectory()
                // https://github.com/dotnet/roslyn/blob/0382e3e3fc543fc483090bff3ab1eaae39dfb4d9/src/Compilers/CSharp/csc/Program.cs#L18
                var sdkDirectory = RuntimeEnvironment.GetRuntimeDirectory();

                CscArgs     = CSharpCommandLineParser.Default.Parse(_precompilationCommandLineArgs.Arguments, _precompilationCommandLineArgs.BaseDirectory, sdkDirectory);
                Diagnostics = new List <Diagnostic>(CscArgs.Errors);

                // load those before anything else hooks into our AssemlbyResolve...
                var compilationModules = LoadModules().ToList();

                if (Diagnostics.Any())
                {
                    return(false);
                }
                Encoding = CscArgs.Encoding ?? new UTF8Encoding(false); // utf8 without bom

                var pdbPath    = CscArgs.PdbPath;
                var outputPath = Path.Combine(CscArgs.OutputDirectory, CscArgs.OutputFileName);

                if (!CscArgs.EmitPdb)
                {
                    pdbPath = null;
                }
                else if (string.IsNullOrWhiteSpace(pdbPath))
                {
                    pdbPath = Path.ChangeExtension(outputPath, ".pdb");
                }

                using (var workspace = CreateWokspace())
                    using (var analysisCts = new CancellationTokenSource())
                        using (var peStream = new MemoryStream())
                            using (var pdbStream = !string.IsNullOrWhiteSpace(pdbPath) ? new MemoryStream() : null)
                                using (var xmlDocumentationStream = !string.IsNullOrWhiteSpace(CscArgs.DocumentationPath) ? new MemoryStream() : null)
                                {
                                    EmitResult               emitResult  = null;
                                    var                      project     = CreateProject(workspace);
                                    CSharpCompilation        compilation = null;
                                    CompilationWithAnalyzers compilationWithAnalyzers = null;
                                    try
                                    {
                                        compilation = await project.GetCompilationAsync() as CSharpCompilation;
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine("error: failed to create compilation: " + ex.Message);
                                        return(false);
                                    }

                                    var context = new CompileContext(compilationModules);
                                    context.Before(new BeforeCompileContext
                                    {
                                        Arguments   = CscArgs,
                                        Compilation = compilation.AddSyntaxTrees(GeneratedSyntaxTrees()),
                                        Diagnostics = Diagnostics,
                                    });

                                    CscArgs     = context.BeforeCompileContext.Arguments;
                                    compilation = context.BeforeCompileContext.Compilation;

                                    var analyzers = project.AnalyzerReferences.SelectMany(x => x.GetAnalyzers(project.Language)).ToImmutableArray();
                                    if (!analyzers.IsEmpty)
                                    {
                                        compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, analysisCts.Token);
                                        compilation = compilationWithAnalyzers.Compilation as CSharpCompilation;
                                    }
                                    var analysisTask = compilationWithAnalyzers?.GetAnalysisResultAsync(analysisCts.Token);

                                    using (var win32Resources = CreateWin32Resource(compilation))
                                    {
                                        // https://github.com/dotnet/roslyn/blob/41950e21da3ac2c307fb46c2ca8c8509b5059909/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L437
                                        emitResult = compilation.Emit(
                                            peStream: peStream,
                                            pdbStream: pdbStream,
                                            xmlDocumentationStream: xmlDocumentationStream,
                                            win32Resources: win32Resources,
                                            manifestResources: CscArgs.ManifestResources,
                                            options: CscArgs.EmitOptions,
                                            sourceLinkStream: TryOpenFile(CscArgs.SourceLink, out var sourceLinkStream) ? sourceLinkStream : null,
                                            embeddedTexts: CscArgs.EmbeddedFiles.AsEnumerable()
                                            .Select(x => TryOpenFile(x.Path, out var embeddedText) ? EmbeddedText.FromStream(x.Path, embeddedText) : null)
                                            .Where(x => x != null),
                                            debugEntryPoint: null);
                                    }

                                    Diagnostics.AddRange(emitResult.Diagnostics);

                                    try
                                    {
                                        var analysisResult = analysisTask == null ? null : await analysisTask;
                                        if (analysisResult != null)
                                        {
                                            Diagnostics.AddRange(analysisResult.GetAllDiagnostics());

                                            foreach (var info in analysisResult.AnalyzerTelemetryInfo)
                                            {
                                                Console.WriteLine($"hidden: {info.Key} {info.Value.ExecutionTime.TotalMilliseconds:#}ms");
                                            }
                                        }
                                    }
                                    catch (OperationCanceledException)
                                    {
                                        Console.WriteLine("warning: analysis canceled");
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine("error: analysis failed: " + ex.Message);
                                        return(false);
                                    }

                                    if (!emitResult.Success || HasErrors)
                                    {
                                        return(false);
                                    }

                                    context.After(new AfterCompileContext
                                    {
                                        Arguments      = CscArgs,
                                        AssemblyStream = peStream,
                                        Compilation    = compilation,
                                        Diagnostics    = Diagnostics,
                                        SymbolStream   = pdbStream,
                                        XmlDocStream   = xmlDocumentationStream,
                                    });

                                    if (!HasErrors)
                                    {
                                        // do not create the output files if emit fails
                                        // if the output files are there, msbuild incremental build thinks the previous build succeeded
                                        await Task.WhenAll(
                                            DumpToFileAsync(outputPath, peStream),
                                            DumpToFileAsync(pdbPath, pdbStream),
                                            DumpToFileAsync(CscArgs.DocumentationPath, xmlDocumentationStream));

                                        return(true);
                                    }

                                    return(false);
                                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Join("\n", ex.ToString().Split('\n').Select((x, i) => x + $"ERROR: {i:D4} {x}")));
                return(false);
            }
            finally
            {
                Diagnostics.ForEach(x => Console.WriteLine(x.ToString())); // strings only, since the Console.Out textwriter is another app domain...
            }
        }