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 @@
+