private static ExitCode AnalyseTracing( TracingAnalyser analyser, CSharpCommandLineArguments compilerArguments, Options options, CanonicalPathCache canonicalPathCache, Stopwatch stopwatch) { return(Analyse(stopwatch, analyser, options, references => ResolveReferences(compilerArguments, analyser, canonicalPathCache, references), (analyser, syntaxTrees) => { return ReadSyntaxTrees( compilerArguments.SourceFiles.Select(src => canonicalPathCache.GetCanonicalPath(src.Path)), analyser, compilerArguments.ParseOptions, compilerArguments.Encoding, syntaxTrees); }, (syntaxTrees, references) => { // csc.exe (CSharpCompiler.cs) also provides CompilationOptions // .WithMetadataReferenceResolver(), // .WithXmlReferenceResolver() and // .WithSourceReferenceResolver(). // These would be needed if we hadn't explicitly provided the source/references // already. return CSharpCompilation.Create( compilerArguments.CompilationName, syntaxTrees, references, compilerArguments.CompilationOptions .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default) .WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths)) .WithMetadataImportOptions(MetadataImportOptions.All) ); }, (compilation, options) => analyser.EndInitialize(compilerArguments, options, compilation), () => analyser.AnalyseCompilation(), performance => analyser.LogPerformance(performance), () => { })); }
/// <summary> /// Command-line driver for the extractor. /// </summary> /// /// <remarks> /// The extractor can be invoked in one of two ways: Either as an "analyser" passed in via the /a /// option to csc.exe, or as a stand-alone executable. In this case, we need to faithfully /// drive Roslyn in the way that csc.exe would. /// </remarks> /// /// <param name="args">Command line arguments as passed to csc.exe</param> /// <returns><see cref="ExitCode"/></returns> public static ExitCode Run(string[] args) { var stopwatch = new Stopwatch(); stopwatch.Start(); Entities.Compilation.Settings = (Directory.GetCurrentDirectory(), args); var options = Options.CreateWithEnvironment(Entities.Compilation.Settings.Args); var fileLogger = new FileLogger(options.Verbosity, GetCSharpLogPath()); using var logger = options.Console ? new CombinedLogger(new ConsoleLogger(options.Verbosity), fileLogger) : (ILogger)fileLogger; if (Environment.GetEnvironmentVariable("SEMMLE_CLRTRACER") == "1" && !options.ClrTracer) { logger.Log(Severity.Info, "Skipping extraction since already extracted from the CLR tracer"); return(ExitCode.Ok); } var canonicalPathCache = CanonicalPathCache.Create(logger, 1000); var pathTransformer = new PathTransformer(canonicalPathCache); using var analyser = new TracingAnalyser(new LogProgressMonitor(logger), logger, options.AssemblySensitiveTrap, pathTransformer); try { if (options.ProjectsToLoad.Any()) { AddSourceFilesFromProjects(options.ProjectsToLoad, options.CompilerArguments, logger); } var compilerVersion = new CompilerVersion(options); if (compilerVersion.SkipExtraction) { logger.Log(Severity.Warning, " Unrecognized compiler '{0}' because {1}", compilerVersion.SpecifiedCompiler, compilerVersion.SkipReason); return(ExitCode.Ok); } var compilerArguments = CSharpCommandLineParser.Default.Parse( compilerVersion.ArgsWithResponse, Entities.Compilation.Settings.Cwd, compilerVersion.FrameworkPath, compilerVersion.AdditionalReferenceDirectories ); if (compilerArguments is null) { var sb = new StringBuilder(); sb.Append(" Failed to parse command line: ").AppendList(" ", Entities.Compilation.Settings.Args); logger.Log(Severity.Error, sb.ToString()); ++analyser.CompilationErrors; return(ExitCode.Failed); } if (!analyser.BeginInitialize(compilerVersion.ArgsWithResponse)) { logger.Log(Severity.Info, "Skipping extraction since files have already been extracted"); return(ExitCode.Ok); } return(AnalyseTracing(analyser, compilerArguments, options, canonicalPathCache, stopwatch)); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { logger.Log(Severity.Error, " Unhandled exception: {0}", ex); return(ExitCode.Errors); } }