diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs index 03369e7b6013..4ddef8b5cc45 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs @@ -13,6 +13,8 @@ using Microsoft.CodeAnalysis.Text; using Semmle.Util; using Semmle.Util.Logging; +using Basic.CompilerLog; +using Basic.CompilerLog.Util; namespace Semmle.Extraction.CSharp { @@ -92,11 +94,56 @@ public static ILogger MakeLogger(Verbosity verbosity, bool includeConsole) /// Command line arguments as passed to csc.exe /// public static ExitCode Run(string[] args) + { + var options = Options.CreateWithEnvironment(args); + if (options.BinaryLogPath is string binlogPath) + { + using var fileStream = new FileStream(binlogPath, FileMode.Open, FileAccess.Read, FileShare.Read); + + // Filter out compiler calls that aren't interesting for examination + var predicate = bool (CompilerCall compilerCall) => + { + if (!compilerCall.IsCSharp) + { + return false; + } + + return compilerCall.Kind switch + { + CompilerCallKind.XamlPreCompile => false, + CompilerCallKind.Satellite => false, + CompilerCallKind.WpfTemporaryCompile => false, + _ => true + }; + }; + + var compilerCalls = BinaryLogUtil.ReadAllCompilerCalls(fileStream, predicate); + var exitCode = ExitCode.Ok; + foreach (var compilerCall in compilerCalls) + { + Console.WriteLine($"Processing {compilerCall.GetDiagnosticName()}"); + var compilerCallOptions = Options.CreateWithEnvironment([]); + compilerCallOptions.CompilerName = compilerCall.CompilerFilePath; + compilerCallOptions.CompilerArguments.AddRange(compilerCall.GetArguments()); + var ec = Run(compilerCallOptions); + if (ec != ExitCode.Ok) + { + exitCode = ec; + } + } + + return exitCode; + } + else + { + return Run(options); + } + } + + public static ExitCode Run(Options options) { var stopwatch = new Stopwatch(); stopwatch.Start(); - - var options = Options.CreateWithEnvironment(args); Entities.Compilation.Settings = (Directory.GetCurrentDirectory(), options.CompilerArguments.ToArray()); using var logger = MakeLogger(options.Verbosity, options.Console); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs index 4fafffe98333..2a15cf562a52 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Options.cs @@ -25,13 +25,15 @@ public sealed class Options : CommonOptions /// /// All other arguments passed to the compilation. /// - public IList CompilerArguments { get; } = new List(); + public List CompilerArguments { get; } = new List(); /// /// Holds if assembly information should be prefixed to TRAP labels. /// public bool AssemblySensitiveTrap { get; private set; } = false; + public string? BinaryLogPath { get; set; } + public static Options CreateWithEnvironment(string[] arguments) { var options = new Options(); @@ -65,6 +67,9 @@ public override bool HandleOption(string key, string value) case "load-sources-from-project": ProjectsToLoad.Add(value); return true; + case "binlog": + BinaryLogPath = value; + return true; default: return base.HandleOption(key, value); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj index 2a59f3716ceb..b4659168a599 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj @@ -19,5 +19,6 @@ +