public Compilation CreateCompilation(CompilationOptionsReader compilationOptionsReader, string fileName) { var pdbCompilationOptions = compilationOptionsReader.GetMetadataCompilationOptions(); if (pdbCompilationOptions.Length == 0) { throw new InvalidDataException("Did not find compilation options in pdb"); } var metadataReferenceInfos = compilationOptionsReader.GetMetadataReferences(); var encoding = compilationOptionsReader.GetEncoding(); var sourceFileInfos = compilationOptionsReader.GetSourceFileInfos(encoding); _logger.LogInformation("Locating metadata references"); var metadataReferences = _referenceResolver.ResolveReferences(metadataReferenceInfos); logResolvedMetadataReferences(); var sourceLinks = ResolveSourceLinks(compilationOptionsReader); var sources = ResolveSources(sourceFileInfos, sourceLinks, encoding); logResolvedSources(); if (pdbCompilationOptions.TryGetUniqueOption("language", out var language)) { var compilation = language switch { LanguageNames.CSharp => CreateCSharpCompilation(fileName, compilationOptionsReader, sources, metadataReferences), LanguageNames.VisualBasic => CreateVisualBasicCompilation(fileName, compilationOptionsReader, sources, metadataReferences), _ => throw new InvalidDataException($"{language} is not a known language") }; return(compilation); } throw new InvalidDataException("Did not find language in compilation options"); void logResolvedMetadataReferences() { using var _ = _logger.BeginScope("Metadata References"); for (var i = 0; i < metadataReferenceInfos.Length; i++) { _logger.LogInformation($@"""{metadataReferences[i].Display}"" - {metadataReferenceInfos[i].Mvid}"); } } void logResolvedSources() { using var _ = _logger.BeginScope("Source Names"); foreach (var resolvedSource in sources) { var sourceFileInfo = resolvedSource.SourceFileInfo; var hash = BitConverter.ToString(sourceFileInfo.Hash).Replace("-", ""); var embeddedCompressedHash = sourceFileInfo.EmbeddedCompressedHash is { } compressedHash ? ("[uncompressed]" + BitConverter.ToString(compressedHash).Replace("-", "")) : null; _logger.LogInformation($@"""{resolvedSource.DisplayPath}"" - {sourceFileInfo.HashAlgorithm} - {hash} - {embeddedCompressedHash}"); } } }
private VisualBasicCompilationFactory( string assemblyFileName, CompilationOptionsReader optionsReader, VisualBasicCompilationOptions compilationOptions) : base(assemblyFileName, optionsReader) { CompilationOptions = compilationOptions; }
private CSharpCompilationFactory( string assemblyFileName, CompilationOptionsReader optionsReader, CSharpParseOptions parseOptions, CSharpCompilationOptions compilationOptions) : base(assemblyFileName, optionsReader) { Debug.Assert(optionsReader.GetLanguageName() == LanguageNames.CSharp); ParseOptions = parseOptions; CompilationOptions = compilationOptions; }
private Compilation CreateCSharpCompilation(CompilationOptionsReader pdbReader, string assemblyName) { var(compilationOptions, parseOptions, encoding) = CreateCSharpCompilationOptions(pdbReader); var metadataReferences = CreateMetadataReferences(pdbReader); var sources = GetSources(pdbReader, encoding); return(CSharpCompilation.Create( assemblyName, syntaxTrees: sources.Select(s => CSharpSyntaxTree.ParseText(s, options: parseOptions)).ToImmutableArray(), references: metadataReferences, options: compilationOptions)); }
private ImmutableArray <SourceText> GetSources(CompilationOptionsReader pdbReader, Encoding encoding) { var builder = ImmutableArray.CreateBuilder <SourceText>(); foreach (var srcFile in pdbReader.GetSourceFileNames()) { var text = _sourceResolver.ResolveSource(srcFile, encoding); builder.Add(text); } return(builder.ToImmutable()); }
private Compilation CreateCSharpCompilation( string fileName, CompilationOptionsReader optionsReader, ImmutableArray <ResolvedSource> sources, ImmutableArray <MetadataReference> metadataReferences) { var(compilationOptions, parseOptions) = CreateCSharpCompilationOptions(optionsReader, fileName); return(CSharpCompilation.Create( Path.GetFileNameWithoutExtension(fileName), syntaxTrees: sources.Select(s => CSharpSyntaxTree.ParseText(s.SourceText, options: parseOptions, path: s.SourceFileInfo.SourceFilePath)).ToImmutableArray(), references: metadataReferences, options: compilationOptions)); }
private Compilation CreateCSharpCompilation( string assemblyFileName, CompilationOptionsReader optionsReader, ImmutableArray <SyntaxTreeInfo> syntaxTreeInfos, ImmutableArray <MetadataReference> metadataReferences) { var(compilationOptions, parseOptions) = CreateCSharpCompilationOptions(optionsReader, assemblyFileName); return(CSharpCompilation.Create( Path.GetFileNameWithoutExtension(assemblyFileName), syntaxTrees: syntaxTreeInfos.SelectAsArray(s => CSharpSyntaxTree.ParseText(s.SourceText, options: parseOptions, path: s.FilePath)), references: metadataReferences, options: compilationOptions)); }
public Compilation CreateCompilation( CompilationOptionsReader compilationOptionsReader, string fileName, ImmutableArray <ResolvedSource> sources, ImmutableArray <MetadataReference> metadataReferences) { // We try to handle assemblies missing compilation options gracefully by skipping them. // However, if an assembly has some bad combination of data, for example if it contains // compilation options but not metadata references, then we throw an exception. if (!compilationOptionsReader.TryGetMetadataCompilationOptions(out var pdbCompilationOptions) || pdbCompilationOptions.Length == 0) { throw new Exception($"{fileName} did not contain compilation options in its PDB"); } if (pdbCompilationOptions.TryGetUniqueOption("language", out var language)) { var diagnosticBag = DiagnosticBag.GetInstance(); var compilation = language switch { LanguageNames.CSharp => CreateCSharpCompilation(fileName, compilationOptionsReader, sources, metadataReferences), LanguageNames.VisualBasic => CreateVisualBasicCompilation(fileName, compilationOptionsReader, sources, metadataReferences, diagnosticBag), _ => throw new InvalidDataException($"{language} is not a known language") }; var diagnostics = diagnosticBag.ToReadOnlyAndFree(); var hadError = false; foreach (var diagnostic in diagnostics) { if (diagnostic.Severity == DiagnosticSeverity.Error) { _logger.LogError(diagnostic.ToString()); hadError = true; } else { _logger.LogWarning(diagnostic.ToString()); } } if (hadError) { throw new Exception("Diagnostics creating the compilation"); } return(compilation); } throw new InvalidDataException("Did not find language in compilation options"); }
private ImmutableArray <SourceLink> ResolveSourceLinks(CompilationOptionsReader compilationOptionsReader) { using var _ = _logger.BeginScope("Source Links"); var sourceLinks = compilationOptionsReader.GetSourceLinksOpt(); if (sourceLinks.IsDefault) { _logger.LogInformation("No source links found in pdb"); } else { foreach (var link in sourceLinks) { _logger.LogInformation($@"""{link.Prefix}"": ""{link.Replace}"""); } } return(sourceLinks); }
public Compilation CreateCompilation( string assemblyFileName, CompilationOptionsReader compilationOptionsReader, ImmutableArray <SyntaxTreeInfo> syntaxTreeInfos, ImmutableArray <MetadataReference> metadataReferences) { var diagnosticBag = DiagnosticBag.GetInstance(); var compilation = compilationOptionsReader.GetLanguageName() switch { LanguageNames.CSharp => CreateCSharpCompilation(assemblyFileName, compilationOptionsReader, syntaxTreeInfos, metadataReferences), LanguageNames.VisualBasic => CreateVisualBasicCompilation(assemblyFileName, compilationOptionsReader, syntaxTreeInfos, metadataReferences, diagnosticBag), var language => throw new InvalidDataException($"{assemblyFileName} has unsupported language {language}") }; var diagnostics = diagnosticBag.ToReadOnlyAndFree(); var hadError = false; foreach (var diagnostic in diagnostics) { if (diagnostic.Severity == DiagnosticSeverity.Error) { _logger.LogError(diagnostic.ToString()); hadError = true; } else { _logger.LogWarning(diagnostic.ToString()); } } if (hadError) { throw new Exception("Diagnostics creating the compilation"); } return(compilation); }
public Compilation CreateCompilation(MetadataReader metadataReader, string name) { var pdbReader = new CompilationOptionsReader(metadataReader); var pdbCompilationOptions = pdbReader.GetCompilationOptions(); if (pdbCompilationOptions.Length == 0) { throw new InvalidDataException("Did not find compilation options in pdb"); } if (pdbCompilationOptions.TryGetUniqueOption("language", out var language)) { var compilation = language switch { LanguageNames.CSharp => CreateCSharpCompilation(pdbReader, name), LanguageNames.VisualBasic => CreateVisualBasicCompilation(pdbReader, name), _ => throw new InvalidDataException($"{language} is not a known language") }; return(compilation); } throw new InvalidDataException("Did not find language in compilation options"); }
internal static new CSharpCompilationFactory Create(string assemblyFileName, CompilationOptionsReader optionsReader) { Debug.Assert(optionsReader.GetLanguageName() == LanguageNames.CSharp); var(compilationOptions, parseOptions) = CreateCSharpCompilationOptions(assemblyFileName, optionsReader); return(new CSharpCompilationFactory(assemblyFileName, optionsReader, parseOptions, compilationOptions)); }
private (CSharpCompilationOptions, CSharpParseOptions) CreateCSharpCompilationOptions(CompilationOptionsReader optionsReader, string assemblyName) { using var scope = _logger.BeginScope("Options"); var pdbCompilationOptions = optionsReader.GetMetadataCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption("language-version"); var optimization = pdbCompilationOptions.GetUniqueOption("optimization"); // TODO: Check portability policy if needed // pdbCompilationOptions.TryGetValue("portability-policy", out var portabilityPolicyString); pdbCompilationOptions.TryGetUniqueOption(_logger, "define", out var define); pdbCompilationOptions.TryGetUniqueOption(_logger, "checked", out var checkedString); pdbCompilationOptions.TryGetUniqueOption(_logger, "nullable", out var nullable); pdbCompilationOptions.TryGetUniqueOption(_logger, "unsafe", out var unsafeString); CS.LanguageVersionFacts.TryParse(langVersionString, out var langVersion); var preprocessorSymbols = define == null ? ImmutableArray <string> .Empty : define.Split(',').ToImmutableArray(); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols); var(optimizationLevel, plus) = GetOptimizationLevel(optimization); var nullableOptions = nullable is null ? NullableContextOptions.Disable : (NullableContextOptions)Enum.Parse(typeof(NullableContextOptions), nullable); var compilationOptions = new CSharpCompilationOptions( optionsReader.GetOutputKind(), reportSuppressedDiagnostics: false, // TODO: can't rely on the implicity moduleName here. In the case of .NET Core EXE the output name will // end with .dll but the inferred name will be .exe moduleName: assemblyName + ".dll", mainTypeName: optionsReader.GetMainTypeName(), scriptClassName: null, usings: null, optimizationLevel, !string.IsNullOrEmpty(checkedString) && bool.Parse(checkedString), !string.IsNullOrEmpty(unsafeString) && bool.Parse(unsafeString), cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: optionsReader.GetPublicKey()?.ToImmutableArray() ?? default, delaySign: null, Platform.AnyCpu, // presence of diagnostics is expected to not affect emit. ReportDiagnostic.Suppress, warningLevel: 4, specificDiagnosticOptions: null, concurrentBuild: true, deterministic: true, xmlReferenceResolver: null, sourceReferenceResolver: null, metadataReferenceResolver: null, assemblyIdentityComparer: null, strongNameProvider: null, publicSign: false, metadataImportOptions: MetadataImportOptions.Public, nullableContextOptions: nullableOptions); compilationOptions.DebugPlusMode = plus; return(compilationOptions, parseOptions); }
private static CompilationDiff?ValidateFile(FileInfo originalBinary, BuildConstructor buildConstructor, ILogger logger, Options options) { if (s_ignorePatterns.Any(r => r.IsMatch(originalBinary.FullName))) { logger.LogTrace($"Ignoring {originalBinary.FullName}"); return(null); } MetadataReaderProvider?pdbReaderProvider = null; try { // Find the embedded pdb using var originalBinaryStream = originalBinary.OpenRead(); using var originalPeReader = new PEReader(originalBinaryStream); var pdbOpened = originalPeReader.TryOpenAssociatedPortablePdb( peImagePath: originalBinary.FullName, filePath => File.Exists(filePath) ? File.OpenRead(filePath) : null, out pdbReaderProvider, out var pdbPath); if (!pdbOpened || pdbReaderProvider is null) { logger.LogError($"Could not find pdb for {originalBinary.FullName}"); return(null); } using var _ = logger.BeginScope($"Verifying {originalBinary.FullName} with pdb {pdbPath ?? "[embedded]"}"); var pdbReader = pdbReaderProvider.GetMetadataReader(); var optionsReader = new CompilationOptionsReader(logger, pdbReader, originalPeReader); var compilation = buildConstructor.CreateCompilation( optionsReader, Path.GetFileNameWithoutExtension(originalBinary.Name)); var compilationDiff = CompilationDiff.Create(originalBinary, optionsReader, compilation, getDebugEntryPoint(), logger, options); return(compilationDiff); IMethodSymbol?getDebugEntryPoint() { if (optionsReader.GetMainTypeName() is { } mainTypeName&& optionsReader.GetMainMethodName() is { } mainMethodName) { var typeSymbol = compilation.GetTypeByMetadataName(mainTypeName); if (typeSymbol is object) { var methodSymbols = typeSymbol .GetMembers(mainMethodName) .OfType <IMethodSymbol>(); return(methodSymbols.FirstOrDefault()); } } return(null); } } finally { pdbReaderProvider?.Dispose(); } }
private static VisualBasicCompilationOptions CreateVisualBasicCompilationOptions(string assemblyFileName, CompilationOptionsReader optionsReader) { var pdbCompilationOptions = optionsReader.GetMetadataCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption(CompilationOptionNames.LanguageVersion); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Optimization, out var optimization); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Platform, out var platform); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.GlobalNamespaces, out var globalNamespacesString); IEnumerable <GlobalImport>?globalImports = null; if (!string.IsNullOrEmpty(globalNamespacesString)) { globalImports = GlobalImport.Parse(globalNamespacesString.Split(';')); } VB.LanguageVersion langVersion = default; VB.LanguageVersionFacts.TryParse(langVersionString, ref langVersion); IReadOnlyDictionary <string, object>?preprocessorSymbols = null; if (OptionToString(CompilationOptionNames.Define) is string defineString) { preprocessorSymbols = VisualBasicCommandLineParser.ParseConditionalCompilationSymbols(defineString, out var diagnostics); var diagnostic = diagnostics?.FirstOrDefault(x => x.IsUnsuppressedError); if (diagnostic is object) { throw new Exception($"Cannot create compilation options: {diagnostic}"); } } var parseOptions = VisualBasicParseOptions .Default .WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols.ToImmutableArrayOrEmpty()); var(optimizationLevel, plus) = GetOptimizationLevel(optimization); var isChecked = OptionToBool(CompilationOptionNames.Checked) ?? true; var embedVBRuntime = OptionToBool(CompilationOptionNames.EmbedRuntime) ?? false; var rootNamespace = OptionToString(CompilationOptionNames.RootNamespace); var compilationOptions = new VisualBasicCompilationOptions( optionsReader.GetOutputKind(), moduleName: assemblyFileName, mainTypeName: optionsReader.GetMainTypeName(), scriptClassName: "Script", globalImports: globalImports, rootNamespace: rootNamespace, optionStrict: OptionToEnum <OptionStrict>(CompilationOptionNames.OptionStrict) ?? OptionStrict.Off, optionInfer: OptionToBool(CompilationOptionNames.OptionInfer) ?? false, optionExplicit: OptionToBool(CompilationOptionNames.OptionExplicit) ?? false, optionCompareText: OptionToBool(CompilationOptionNames.OptionCompareText) ?? false, parseOptions: parseOptions, embedVbCoreRuntime: embedVBRuntime, optimizationLevel: optimizationLevel, checkOverflow: isChecked, cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: optionsReader.GetPublicKey()?.ToImmutableArray() ?? default, delaySign: null, platform: GetPlatform(platform), generalDiagnosticOption: ReportDiagnostic.Default, specificDiagnosticOptions: null, concurrentBuild: true, deterministic: true, xmlReferenceResolver: null, sourceReferenceResolver: null, metadataReferenceResolver: null, assemblyIdentityComparer: null, strongNameProvider: null, publicSign: false, reportSuppressedDiagnostics: false, metadataImportOptions: MetadataImportOptions.Public); compilationOptions.DebugPlusMode = plus; return(compilationOptions); string?OptionToString(string option) => pdbCompilationOptions.TryGetUniqueOption(option, out var value) ? value : null; bool?OptionToBool(string option) => pdbCompilationOptions.TryGetUniqueOption(option, out var value) ? ToBool(value) : null; T?OptionToEnum <T>(string option) where T : struct => pdbCompilationOptions.TryGetUniqueOption(option, out var value) ? ToEnum <T>(value) : null;
private ImmutableArray <MetadataReference> CreateMetadataReferences(CompilationOptionsReader pdbReader) { var referenceInfos = pdbReader.GetMetadataReferences(); return(_referenceResolver.ResolveReferences(referenceInfos)); }
internal static new VisualBasicCompilationFactory Create(string assemblyFileName, CompilationOptionsReader optionsReader) { Debug.Assert(optionsReader.GetLanguageName() == LanguageNames.VisualBasic); var compilationOptions = CreateVisualBasicCompilationOptions(assemblyFileName, optionsReader); return(new VisualBasicCompilationFactory(assemblyFileName, optionsReader, compilationOptions)); }
private static (CSharpCompilationOptions, CSharpParseOptions, Encoding) CreateCSharpCompilationOptions(CompilationOptionsReader pdbReader) { var pdbCompilationOptions = pdbReader.GetCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption("language-version"); var optimization = pdbCompilationOptions.GetUniqueOption("optimization"); // TODO: Check portability policy if needed // pdbCompilationOptions.TryGetValue("portability-policy", out var portabilityPolicyString); pdbCompilationOptions.TryGetUniqueOption("default-encoding", out var defaultEncoding); pdbCompilationOptions.TryGetUniqueOption("fallback-encoding", out var fallbackEncoding); pdbCompilationOptions.TryGetUniqueOption("define", out var define); pdbCompilationOptions.TryGetUniqueOption("checked", out var checkedString); pdbCompilationOptions.TryGetUniqueOption("nullable", out var nullable); pdbCompilationOptions.TryGetUniqueOption("unsafe", out var unsafeString); var encodingString = defaultEncoding ?? fallbackEncoding; var encoding = encodingString is null ? Encoding.UTF8 : Encoding.GetEncoding(encodingString); CS.LanguageVersionFacts.TryParse(langVersionString, out var langVersion); var preprocessorSymbols = define == null ? ImmutableArray <string> .Empty : define.Split(';').ToImmutableArray(); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols); var(optimizationLevel, _) = GetOptimizationLevel(optimization); var nullableOptions = nullable is null ? NullableContextOptions.Disable : (NullableContextOptions)Enum.Parse(typeof(NullableContextOptions), nullable); var compilationOptions = new CSharpCompilationOptions( pdbReader.GetOutputKind(), reportSuppressedDiagnostics: false, moduleName: null, mainTypeName: null, scriptClassName: null, usings: null, optimizationLevel, !string.IsNullOrEmpty(checkedString) && bool.Parse(checkedString), !string.IsNullOrEmpty(unsafeString) && bool.Parse(unsafeString), cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: default,
public (Compilation?compilation, bool isError) CreateCompilation(CompilationOptionsReader compilationOptionsReader, string fileName) { // We try to handle assemblies missing compilation options gracefully by skipping them. // However, if an assembly has some bad combination of data, for example if it contains // compilation options but not metadata references, then we throw an exception. if (!compilationOptionsReader.TryGetMetadataCompilationOptions(out var pdbCompilationOptions) || pdbCompilationOptions.Length == 0) { _logger.LogInformation($"{fileName} did not contain compilation options in its PDB"); return(compilation : null, isError : false); } var metadataReferenceInfos = compilationOptionsReader.GetMetadataReferences(); var encoding = compilationOptionsReader.GetEncoding(); var sourceFileInfos = compilationOptionsReader.GetSourceFileInfos(encoding); _logger.LogInformation("Locating metadata references"); if (!_referenceResolver.TryResolveReferences(metadataReferenceInfos, out var metadataReferences)) { _logger.LogError($"Failed to rebuild {fileName} due to missing metadata references"); return(compilation : null, isError : true); } logResolvedMetadataReferences(); var sourceLinks = ResolveSourceLinks(compilationOptionsReader); var sources = ResolveSources(sourceFileInfos, sourceLinks, encoding); logResolvedSources(); if (pdbCompilationOptions.TryGetUniqueOption("language", out var language)) { var diagnosticBag = DiagnosticBag.GetInstance(); var compilation = language switch { LanguageNames.CSharp => CreateCSharpCompilation(fileName, compilationOptionsReader, sources, metadataReferences), LanguageNames.VisualBasic => CreateVisualBasicCompilation(fileName, compilationOptionsReader, sources, metadataReferences, diagnosticBag), _ => throw new InvalidDataException($"{language} is not a known language") }; var diagnostics = diagnosticBag.ToReadOnlyAndFree(); var hadError = false; foreach (var diagnostic in diagnostics) { if (diagnostic.Severity == DiagnosticSeverity.Error) { _logger.LogError(diagnostic.ToString()); hadError = true; } else { _logger.LogWarning(diagnostic.ToString()); } } compilation = hadError ? null : compilation; return(compilation, isError : compilation is null); } throw new InvalidDataException("Did not find language in compilation options"); void logResolvedMetadataReferences() { using var _ = _logger.BeginScope("Metadata References"); for (var i = 0; i < metadataReferenceInfos.Length; i++) { _logger.LogInformation($@"""{metadataReferences[i].Display}"" - {metadataReferenceInfos[i].Mvid}"); } } void logResolvedSources() { using var _ = _logger.BeginScope("Source Names"); foreach (var resolvedSource in sources) { var sourceFileInfo = resolvedSource.SourceFileInfo; var hash = BitConverter.ToString(sourceFileInfo.Hash).Replace("-", ""); var embeddedCompressedHash = sourceFileInfo.EmbeddedCompressedHash is { } compressedHash ? ("[uncompressed]" + BitConverter.ToString(compressedHash).Replace("-", "")) : null; _logger.LogInformation($@"""{resolvedSource.DisplayPath}"" - {sourceFileInfo.HashAlgorithm} - {hash} - {embeddedCompressedHash}"); } } }
public static CompilationFactory Create(string assemblyFileName, CompilationOptionsReader optionsReader) => optionsReader.GetLanguageName() switch {
private static (CSharpCompilationOptions, CSharpParseOptions) CreateCSharpCompilationOptions(string assemblyFileName, CompilationOptionsReader optionsReader) { var pdbCompilationOptions = optionsReader.GetMetadataCompilationOptions(); var langVersionString = pdbCompilationOptions.GetUniqueOption(CompilationOptionNames.LanguageVersion); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Optimization, out var optimization); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Platform, out var platform); // TODO: Check portability policy if needed // pdbCompilationOptions.TryGetValue("portability-policy", out var portabilityPolicyString); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Define, out var define); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Checked, out var checkedString); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Nullable, out var nullable); pdbCompilationOptions.TryGetUniqueOption(CompilationOptionNames.Unsafe, out var unsafeString); CS.LanguageVersionFacts.TryParse(langVersionString, out var langVersion); var preprocessorSymbols = define == null ? ImmutableArray <string> .Empty : define.Split(',').ToImmutableArray(); var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(langVersion) .WithPreprocessorSymbols(preprocessorSymbols); var(optimizationLevel, plus) = GetOptimizationLevel(optimization); var nullableOptions = nullable is null ? NullableContextOptions.Disable : (NullableContextOptions)Enum.Parse(typeof(NullableContextOptions), nullable); var compilationOptions = new CSharpCompilationOptions( optionsReader.GetOutputKind(), reportSuppressedDiagnostics: false, moduleName: assemblyFileName, mainTypeName: optionsReader.GetMainTypeName(), scriptClassName: null, usings: null, optimizationLevel, !string.IsNullOrEmpty(checkedString) && bool.Parse(checkedString), !string.IsNullOrEmpty(unsafeString) && bool.Parse(unsafeString), cryptoKeyContainer: null, cryptoKeyFile: null, cryptoPublicKey: optionsReader.GetPublicKey()?.ToImmutableArray() ?? default, delaySign: null, GetPlatform(platform), // presence of diagnostics is expected to not affect emit. ReportDiagnostic.Suppress, warningLevel: 4, specificDiagnosticOptions: null, concurrentBuild: true, deterministic: true, xmlReferenceResolver: null, sourceReferenceResolver: null, metadataReferenceResolver: null, assemblyIdentityComparer: null, strongNameProvider: null, publicSign: false, metadataImportOptions: MetadataImportOptions.Public, nullableContextOptions: nullableOptions); compilationOptions.DebugPlusMode = plus; return(compilationOptions, parseOptions); }
public static unsafe CompilationDiff Create( FileInfo originalBinaryPath, CompilationOptionsReader optionsReader, Compilation producedCompilation, IMethodSymbol?debugEntryPoint, ILogger logger, Options options) { using var rebuildPeStream = new MemoryStream(); // By default the Roslyn command line adds a resource that we need to replicate here. using var win32ResourceStream = producedCompilation.CreateDefaultWin32Resources( versionResource: true, noManifest: producedCompilation.Options.OutputKind == OutputKind.DynamicallyLinkedLibrary, manifestContents: null, iconInIcoFormat: null); var sourceLink = optionsReader.GetSourceLinkUTF8(); var emitResult = producedCompilation.Emit( peStream: rebuildPeStream, pdbStream: null, xmlDocumentationStream: null, win32Resources: win32ResourceStream, manifestResources: optionsReader.GetManifestResources(), options: new EmitOptions( debugInformationFormat: DebugInformationFormat.Embedded, highEntropyVirtualAddressSpace: true), debugEntryPoint: debugEntryPoint, metadataPEStream: null, pdbOptionsBlobReader: optionsReader.GetMetadataCompilationOptionsBlobReader(), sourceLinkStream: sourceLink != null ? new MemoryStream(sourceLink) : null, embeddedTexts: producedCompilation.SyntaxTrees .Select(st => (path: st.FilePath, text: st.GetText())) .Where(pair => pair.text.CanBeEmbedded) .Select(pair => EmbeddedText.FromSource(pair.path, pair.text)), cancellationToken: CancellationToken.None); if (!emitResult.Success) { using var diagsScope = logger.BeginScope($"Diagnostics"); foreach (var diag in emitResult.Diagnostics) { logger.LogError(diag.ToString()); } return(new CompilationDiff(emitResult.Diagnostics, originalBinaryPath.FullName)); } else { var originalBytes = File.ReadAllBytes(originalBinaryPath.FullName); var rebuildBytes = rebuildPeStream.ToArray(); var bytesEqual = originalBytes.SequenceEqual(rebuildBytes); if (!bytesEqual) { logger.LogError($"Rebuild of {originalBinaryPath.Name} was not equivalent to the original."); if (!options.Debug) { logger.LogInformation("Pass the --debug argument and re-run to write the visualization of the original and rebuild to disk."); } else { logger.LogInformation("Creating a diff..."); var debugPath = options.DebugPath; logger.LogInformation($@"Writing diffs to ""{Path.GetFullPath(debugPath)}"""); var assemblyName = Path.GetFileNameWithoutExtension(originalBinaryPath.Name); var assemblyDebugPath = Path.Combine(debugPath, assemblyName); var originalPath = Path.Combine(assemblyDebugPath, "original"); var rebuildPath = Path.Combine(assemblyDebugPath, "rebuild"); var sourcesPath = Path.Combine(assemblyDebugPath, "sources"); Directory.CreateDirectory(originalPath); Directory.CreateDirectory(rebuildPath); Directory.CreateDirectory(sourcesPath); // TODO: output source files should include the entire relative path instead of just the file name. foreach (var tree in producedCompilation.SyntaxTrees) { var sourceFilePath = Path.Combine(sourcesPath, Path.GetFileName(tree.FilePath)); using var file = File.OpenWrite(sourceFilePath); var writer = new StreamWriter(file); tree.GetText().Write(writer); writer.Flush(); } var originalAssemblyPath = Path.Combine(originalPath, originalBinaryPath.Name); File.WriteAllBytes(originalAssemblyPath, originalBytes); var rebuildAssemblyPath = Path.Combine(rebuildPath, originalBinaryPath.Name); File.WriteAllBytes(rebuildAssemblyPath, rebuildBytes); var originalPeMdvPath = Path.Combine(originalPath, assemblyName + ".pe.mdv"); var originalPdbMdvPath = Path.Combine(originalPath, assemblyName + ".pdb.mdv"); writeVisualization(originalPeMdvPath, optionsReader.PeReader.GetMetadataReader()); writeVisualization(originalPdbMdvPath, optionsReader.PdbReader); var rebuildPeMdvPath = Path.Combine(rebuildPath, assemblyName + ".pe.mdv"); var rebuildPdbMdvPath = Path.Combine(rebuildPath, assemblyName + ".pdb.mdv"); fixed(byte *ptr = rebuildBytes) { using var rebuildPeReader = new PEReader(ptr, rebuildBytes.Length); writeVisualization(rebuildPeMdvPath, rebuildPeReader.GetMetadataReader()); if (rebuildPeReader.TryOpenAssociatedPortablePdb( rebuildAssemblyPath, path => File.Exists(path) ? File.OpenRead(path) : null, out var provider, out _) && provider is { })
protected CompilationFactory(string assemblyFileName, CompilationOptionsReader optionsReader) { AssemblyFileName = assemblyFileName; OptionsReader = optionsReader; }