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); }
/// <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); } }
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()); }
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}'"); } }
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)); }
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)); }
/// <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; } }
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)); }
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")); } } } }
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... } }