예제 #1
0
        /// <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();
            var commandLineArguments = Options.CreateWithEnvironment(args);
            var fileLogger           = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath());

            using var logger = commandLineArguments.Console
                ? new CombinedLogger(new ConsoleLogger(commandLineArguments.Verbosity), fileLogger)
                : (ILogger)fileLogger;

            if (Environment.GetEnvironmentVariable("SEMMLE_CLRTRACER") == "1" && !commandLineArguments.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 Analyser(new LogProgressMonitor(logger), logger, commandLineArguments.AssemblySensitiveTrap, pathTransformer);
            using var references = new BlockingCollection <MetadataReference>();
            try
            {
                var compilerVersion = new CompilerVersion(commandLineArguments);

                if (compilerVersion.SkipExtraction)
                {
                    logger.Log(Severity.Warning, "  Unrecognized compiler '{0}' because {1}", compilerVersion.SpecifiedCompiler, compilerVersion.SkipReason);
                    return(ExitCode.Ok);
                }

                var cwd = Directory.GetCurrentDirectory();
                var compilerArguments = CSharpCommandLineParser.Default.Parse(
                    compilerVersion.ArgsWithResponse,
                    cwd,
                    compilerVersion.FrameworkPath,
                    compilerVersion.AdditionalReferenceDirectories
                    );

                if (compilerArguments == null)
                {
                    var sb = new StringBuilder();
                    sb.Append("  Failed to parse command line: ").AppendList(" ", 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);
                }

                var referenceTasks = ResolveReferences(compilerArguments, analyser, canonicalPathCache, references);

                var syntaxTrees     = new List <SyntaxTree>();
                var syntaxTreeTasks = ReadSyntaxTrees(
                    compilerArguments.SourceFiles.
                    Select(src => canonicalPathCache.GetCanonicalPath(src.Path)),
                    analyser,
                    compilerArguments.ParseOptions,
                    compilerArguments.Encoding,
                    syntaxTrees);

                var sw1 = new Stopwatch();
                sw1.Start();

                Parallel.Invoke(
                    new ParallelOptions {
                    MaxDegreeOfParallelism = commandLineArguments.Threads
                },
                    referenceTasks.Interleave(syntaxTreeTasks).ToArray());

                if (syntaxTrees.Count == 0)
                {
                    logger.Log(Severity.Error, "  No source files");
                    ++analyser.CompilationErrors;
                    return(ExitCode.Failed);
                }

                // 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.
                var compilation = CSharpCompilation.Create(
                    compilerArguments.CompilationName,
                    syntaxTrees,
                    references,
                    compilerArguments.CompilationOptions.
                    WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default).
                    WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths))
                    );

                analyser.EndInitialize(compilerArguments, commandLineArguments, compilation);
                analyser.AnalyseCompilation(cwd, args);
                analyser.AnalyseReferences();

                foreach (var tree in compilation.SyntaxTrees)
                {
                    analyser.AnalyseTree(tree);
                }

                var currentProcess = Process.GetCurrentProcess();
                var cpuTime1       = currentProcess.TotalProcessorTime;
                var userTime1      = currentProcess.UserProcessorTime;
                sw1.Stop();
                logger.Log(Severity.Info, "  Models constructed in {0}", sw1.Elapsed);

                var sw2 = new Stopwatch();
                sw2.Start();
                analyser.PerformExtraction(commandLineArguments.Threads);
                sw2.Stop();
                var cpuTime2  = currentProcess.TotalProcessorTime;
                var userTime2 = currentProcess.UserProcessorTime;

                var performance = new Entities.PerformanceMetrics()
                {
                    Frontend = new Entities.Timings()
                    {
                        Elapsed = sw1.Elapsed, Cpu = cpuTime1, User = userTime1
                    },
                    Extractor = new Entities.Timings()
                    {
                        Elapsed = sw2.Elapsed, Cpu = cpuTime2 - cpuTime1, User = userTime2 - userTime1
                    },
                    Total = new Entities.Timings()
                    {
                        Elapsed = stopwatch.Elapsed, Cpu = cpuTime2, User = userTime2
                    },
                    PeakWorkingSet = currentProcess.PeakWorkingSet64
                };

                analyser.LogPerformance(performance);
                logger.Log(Severity.Info, "  Extraction took {0}", sw2.Elapsed);

                return(analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors);
            }
            catch (Exception ex)  // lgtm[cs/catch-of-all-exceptions]
            {
                logger.Log(Severity.Error, "  Unhandled exception: {0}", ex);
                return(ExitCode.Errors);
            }
        }
예제 #2
0
        /// <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 commandLineArguments = Options.CreateWithEnvironment(args);
            var fileLogger           = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath());
            var logger = commandLineArguments.Console
                ? new CombinedLogger(new ConsoleLogger(commandLineArguments.Verbosity), fileLogger)
                : (ILogger)fileLogger;

            if (Environment.GetEnvironmentVariable("SEMMLE_CLRTRACER") == "1" && !commandLineArguments.ClrTracer)
            {
                logger.Log(Severity.Info, "Skipping extraction since already extracted from the CLR tracer");
                return(ExitCode.Ok);
            }

            using (var analyser = new Analyser(new LogProgressMonitor(logger), logger))
                using (var references = new BlockingCollection <MetadataReference>())
                {
                    try
                    {
                        var compilerVersion = new CompilerVersion(commandLineArguments);

                        bool preserveSymlinks   = Environment.GetEnvironmentVariable("SEMMLE_PRESERVE_SYMLINKS") == "true";
                        var  canonicalPathCache = CanonicalPathCache.Create(logger, 1000, preserveSymlinks ? CanonicalPathCache.Symlinks.Preserve : CanonicalPathCache.Symlinks.Follow);

                        if (compilerVersion.SkipExtraction)
                        {
                            logger.Log(Severity.Warning, "  Unrecognized compiler '{0}' because {1}", compilerVersion.SpecifiedCompiler, compilerVersion.SkipReason);
                            return(ExitCode.Ok);
                        }

                        var cwd = Directory.GetCurrentDirectory();
                        var compilerArguments = CSharpCommandLineParser.Default.Parse(
                            compilerVersion.ArgsWithResponse,
                            cwd,
                            compilerVersion.FrameworkPath,
                            compilerVersion.AdditionalReferenceDirectories
                            );

                        if (compilerArguments == null)
                        {
                            var sb = new StringBuilder();
                            sb.Append("  Failed to parse command line: ").AppendList(" ", args);
                            logger.Log(Severity.Error, sb.ToString());
                            ++analyser.CompilationErrors;
                            return(ExitCode.Failed);
                        }

                        var referenceTasks = ResolveReferences(compilerArguments, analyser, canonicalPathCache, references);

                        var syntaxTrees     = new List <SyntaxTree>();
                        var syntaxTreeTasks = ReadSyntaxTrees(
                            compilerArguments.SourceFiles.
                            Select(src => canonicalPathCache.GetCanonicalPath(src.Path)),
                            analyser,
                            compilerArguments.ParseOptions,
                            compilerArguments.Encoding,
                            syntaxTrees);

                        var sw = new Stopwatch();
                        sw.Start();

                        Parallel.Invoke(
                            new ParallelOptions {
                            MaxDegreeOfParallelism = commandLineArguments.Threads
                        },
                            referenceTasks.Interleave(syntaxTreeTasks).ToArray());

                        if (syntaxTrees.Count == 0)
                        {
                            logger.Log(Severity.Error, "  No source files");
                            ++analyser.CompilationErrors;
                            analyser.LogDiagnostics(compilerVersion.ArgsWithResponse);
                            return(ExitCode.Failed);
                        }

                        var compilation = CSharpCompilation.Create(
                            compilerArguments.CompilationName,
                            syntaxTrees,
                            references,
                            compilerArguments.CompilationOptions.
                            WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default).
                            WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths))
                            // csc.exe (CSharpCompiler.cs) also provides WithMetadataReferenceResolver,
                            // WithXmlReferenceResolver and
                            // WithSourceReferenceResolver.
                            // These would be needed if we hadn't explicitly provided the source/references
                            // already.
                            );

                        analyser.Initialize(compilerArguments, compilation, commandLineArguments, compilerVersion.ArgsWithResponse);
                        analyser.AnalyseReferences();

                        foreach (var tree in compilation.SyntaxTrees)
                        {
                            analyser.AnalyseTree(tree);
                        }

                        sw.Stop();
                        logger.Log(Severity.Info, "  Models constructed in {0}", sw.Elapsed);

                        sw.Restart();
                        analyser.PerformExtraction(commandLineArguments.Threads);
                        sw.Stop();
                        logger.Log(Severity.Info, "  Extraction took {0}", sw.Elapsed);

                        return(analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors);
                    }
                    catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
                    {
                        logger.Log(Severity.Error, "  Unhandled exception: {0}", ex);
                        return(ExitCode.Errors);
                    }
                }
        }
예제 #3
0
        /// <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);
            }
        }