Exemplo n.º 1
0
        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}");
                }
            }
        }
Exemplo n.º 2
0
 private VisualBasicCompilationFactory(
     string assemblyFileName,
     CompilationOptionsReader optionsReader,
     VisualBasicCompilationOptions compilationOptions)
     : base(assemblyFileName, optionsReader)
 {
     CompilationOptions = compilationOptions;
 }
Exemplo n.º 3
0
 private CSharpCompilationFactory(
     string assemblyFileName,
     CompilationOptionsReader optionsReader,
     CSharpParseOptions parseOptions,
     CSharpCompilationOptions compilationOptions)
     : base(assemblyFileName, optionsReader)
 {
     Debug.Assert(optionsReader.GetLanguageName() == LanguageNames.CSharp);
     ParseOptions       = parseOptions;
     CompilationOptions = compilationOptions;
 }
Exemplo n.º 4
0
        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));
        }
Exemplo n.º 5
0
        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());
        }
Exemplo n.º 6
0
 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));
 }
Exemplo n.º 7
0
 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));
 }
Exemplo n.º 8
0
        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");
        }
Exemplo n.º 9
0
        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);
        }
Exemplo n.º 10
0
        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);
        }
Exemplo n.º 11
0
        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");
        }
Exemplo n.º 12
0
 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));
 }
Exemplo n.º 13
0
        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);
        }
Exemplo n.º 14
0
        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();
            }
        }
Exemplo n.º 15
0
        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;
Exemplo n.º 16
0
        private ImmutableArray <MetadataReference> CreateMetadataReferences(CompilationOptionsReader pdbReader)
        {
            var referenceInfos = pdbReader.GetMetadataReferences();

            return(_referenceResolver.ResolveReferences(referenceInfos));
        }
Exemplo n.º 17
0
        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));
        }
Exemplo n.º 18
0
        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,
Exemplo n.º 19
0
        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}");
                }
            }
        }
Exemplo n.º 20
0
 public static CompilationFactory Create(string assemblyFileName, CompilationOptionsReader optionsReader)
 => optionsReader.GetLanguageName() switch
 {
Exemplo n.º 21
0
        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);
        }
Exemplo n.º 22
0
        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 { })
Exemplo n.º 23
0
 protected CompilationFactory(string assemblyFileName, CompilationOptionsReader optionsReader)
 {
     AssemblyFileName = assemblyFileName;
     OptionsReader    = optionsReader;
 }