using System.Collections.Generic; using Semmle.Util.Logging; using CompilationInfo = (string key, string value); namespace Semmle.Extraction { /// /// Implementation of the main extractor state. /// public abstract class Extractor { public abstract ExtractorMode Mode { get; } public string OutputPath { get; } public IEnumerable CompilationInfos { get; } /// /// Creates a new extractor instance for one compilation unit. /// /// The object used for logging. /// The object used for path transformations. protected Extractor(string outputPath, IEnumerable compilationInfos, ILogger logger, PathTransformer pathTransformer) { OutputPath = outputPath; Logger = logger; PathTransformer = pathTransformer; CompilationInfos = compilationInfos; } // Limit the number of error messages in the log file // to handle pathological cases. private const int maxErrors = 1000; private readonly object mutex = new object(); public void Message(Message msg) { lock (mutex) { if (msg.Severity == Severity.Error) { ++Errors; if (Errors == maxErrors) { Logger.LogInfo(" Stopping logging after {0} errors", Errors); } } if (Errors >= maxErrors) { return; } Logger.Log(msg.Severity, $" {msg.ToLogString()}"); } } // Roslyn framework has no apparent mechanism to associate assemblies with their files. // So this lookup table needs to be populated. private readonly Dictionary referenceFilenames = new Dictionary(); public void SetAssemblyFile(string assembly, string file) { referenceFilenames[assembly] = file; } public string GetAssemblyFile(string assembly) { return referenceFilenames[assembly]; } public int Errors { get; private set; } private readonly ISet missingTypes = new SortedSet(); private readonly ISet missingNamespaces = new SortedSet(); public void MissingType(string fqn, bool fromSource) { if (fromSource) { lock (mutex) missingTypes.Add(fqn); } } public void MissingNamespace(string fqdn, bool fromSource) { if (fromSource) { lock (mutex) missingNamespaces.Add(fqdn); } } public IEnumerable MissingTypes => missingTypes; public IEnumerable MissingNamespaces => missingNamespaces; public ILogger Logger { get; private set; } public static string Version => $""; public PathTransformer PathTransformer { get; } } }