IEnumerable <EmbeddedText> CollectAdditionalEmbeddedTexts() { return(this.SourceSymbolCollection .GetFiles() .Select(f => f.SyntaxTree) .Where(tree => tree.IsPharEntry || tree.FilePath.IsPharFile()) .Select(tree => EmbeddedText.FromSource(tree.FilePath, tree.GetText())) .ToList()); }
public void FromStream_IOErrors() { Assert.Throws <IOException>(() => EmbeddedText.FromStream("path", new HugeStream())); Assert.Throws <EndOfStreamException>(() => EmbeddedText.FromStream("path", new TruncatingStream(10))); Assert.Throws <EndOfStreamException>(() => EmbeddedText.FromStream("path", new TruncatingStream(1000))); // Should be Assert.Throws<IOException>, but impeded by https://github.com/dotnet/roslyn/issues/12926 Assert.Throws <IOException>(() => EmbeddedText.FromStream("path", new ReadFailsStream())); }
public void FromBytes_Empty() { var text = EmbeddedText.FromBytes("pathToEmpty", new ArraySegment <byte>(new byte[0], 0, 0), SourceHashAlgorithm.Sha1); Assert.Equal("pathToEmpty", text.FilePath); Assert.Equal(text.ChecksumAlgorithm, SourceHashAlgorithm.Sha1); AssertEx.Equal(SourceText.CalculateChecksum(new byte[0], 0, 0, SourceHashAlgorithm.Sha1), text.Checksum); AssertEx.Equal(new byte[] { 0, 0, 0, 0 }, text.Blob); }
public void FromStream_ArgumentErrors() { Assert.Throws <ArgumentNullException>("filePath", () => EmbeddedText.FromStream(null, null)); Assert.Throws <ArgumentException>("filePath", () => EmbeddedText.FromStream("", null)); Assert.Throws <ArgumentNullException>("stream", () => EmbeddedText.FromStream("path", null)); Assert.Throws <ArgumentException>("stream", () => EmbeddedText.FromStream("path", new CannotReadStream())); Assert.Throws <ArgumentException>("stream", () => EmbeddedText.FromStream("path", new CannotSeekStream())); Assert.Throws <ArgumentException>("checksumAlgorithm", () => EmbeddedText.FromStream("path", new MemoryStream(), SourceHashAlgorithm.None)); }
public void FromBytes_EncodingFallbackCase() { var source = EncodedStringText.Create(new MemoryStream(new byte[] { 0xA9, 0x0D, 0x0A }), canBeEmbedded: true); var text = EmbeddedText.FromSource("pathToLarge", source); Assert.Equal("pathToLarge", text.FilePath); Assert.Equal(SourceHashAlgorithm.Sha1, text.ChecksumAlgorithm); AssertEx.Equal(source.GetChecksum(), text.Checksum); }
/// <summary> /// Constructs a <see cref="SourceText"/> from stream content. /// </summary> /// <param name="stream">Stream. The stream must be seekable.</param> /// <param name="encoding"> /// Data encoding to use if the stream doesn't start with Byte Order Mark specifying the encoding. /// <see cref="Encoding.UTF8"/> if not specified. /// </param> /// <param name="checksumAlgorithm"> /// Hash algorithm to use to calculate checksum of the text that's saved to PDB. /// </param> /// <param name="throwIfBinaryDetected">If the decoded text contains at least two consecutive NUL /// characters, then an <see cref="InvalidDataException"/> is thrown.</param> /// <param name="canBeEmbedded">True if the text can be passed to <see cref="EmbeddedText.FromSource"/> and be embedded in a PDB.</param> /// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception> /// <exception cref="ArgumentException"> /// <paramref name="stream"/> doesn't support reading or seeking. /// <paramref name="checksumAlgorithm"/> is not supported. /// </exception> /// <exception cref="DecoderFallbackException">If the given encoding is set to use a throwing decoder as a fallback</exception> /// <exception cref="InvalidDataException">Two consecutive NUL characters were detected in the decoded text and <paramref name="throwIfBinaryDetected"/> was true.</exception> /// <exception cref="IOException">An I/O error occurs.</exception> /// <remarks>Reads from the beginning of the stream. Leaves the stream open.</remarks> public static SourceText From( Stream stream, Encoding?encoding = null, SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1, bool throwIfBinaryDetected = false, bool canBeEmbedded = false ) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (!stream.CanRead) { throw new ArgumentException( CodeAnalysisResources.StreamMustSupportReadAndSeek, nameof(stream) ); } ValidateChecksumAlgorithm(checksumAlgorithm); encoding = encoding ?? s_utf8EncodingWithNoBOM; if (stream.CanSeek) { // If the resulting string would end up on the large object heap, then use LargeEncodedText. if (encoding.GetMaxCharCountOrThrowIfHuge(stream) >= LargeObjectHeapLimitInChars) { return(LargeText.Decode( stream, encoding, checksumAlgorithm, throwIfBinaryDetected, canBeEmbedded )); } } string text = Decode(stream, encoding, out encoding); if (throwIfBinaryDetected && IsBinary(text)) { throw new InvalidDataException(); } // We must compute the checksum and embedded text blob now while we still have the original bytes in hand. // We cannot re-encode to obtain checksum and blob as the encoding is not guaranteed to round-trip. var checksum = CalculateChecksum(stream, checksumAlgorithm); var embeddedTextBlob = canBeEmbedded ? EmbeddedText.CreateBlob(stream) : default(ImmutableArray <byte>); return(new StringText(text, encoding, checksum, checksumAlgorithm, embeddedTextBlob)); }
public void FromStream_Empty() { var text = EmbeddedText.FromStream("pathToEmpty", new MemoryStream(new byte[0]), SourceHashAlgorithm.Sha1); var checksum = SourceText.CalculateChecksum(new byte[0], 0, 0, SourceHashAlgorithm.Sha1); Assert.Equal("pathToEmpty", text.FilePath); Assert.Equal(text.ChecksumAlgorithm, SourceHashAlgorithm.Sha1); AssertEx.Equal(checksum, text.Checksum); AssertEx.Equal(new byte[] { 0, 0, 0, 0 }, text.Blob); }
public async Task BuildAndExecuteAsync(string code, OptimizationLevel?optimizationLevel, string codePath, bool onlyBuild = true) { await new NoContextYieldAwaitable(); try { _running = true; using var executeCts = new CancellationTokenSource(); var cancellationToken = executeCts.Token; _assemblyPath = Path.Combine(BuildPath, $"{Name}.dll"); _depsFile = Path.ChangeExtension(_assemblyPath, ".deps.json"); var encoding = Encoding.UTF8; var buffer = encoding.GetBytes(code); var sourceText = SourceText.From(buffer, buffer.Length, encoding, canBeEmbedded: true); var scriptRunner = CreateScriptRunner(sourceText, codePath, optimizationLevel); CopyDependencies(); var embeddedTexts = new List <EmbeddedText>() { EmbeddedText.FromSource(codePath, sourceText), }; var diagnostics = await scriptRunner.SaveAssembly(_assemblyPath, embeddedTexts, cancellationToken) .ConfigureAwait(false); SendDiagnostics(diagnostics); if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) { return; } _executeCts = executeCts; if (!onlyBuild) { await RunProcess(_assemblyPath, cancellationToken); } } finally { _executeCts = null; _running = false; if (_initializeBuildPathAfterRun) { _initializeBuildPathAfterRun = false; InitializeBuildPath(stop: false); } } }
public void FromSource_Large() { var source = SourceText.From(LargeSource, Encoding.Unicode, SourceHashAlgorithm.Sha256); var text = EmbeddedText.FromSource("pathToLarge", source); Assert.Equal("pathToLarge", text.FilePath); Assert.Equal(SourceHashAlgorithm.Sha256, text.ChecksumAlgorithm); AssertEx.Equal(source.GetChecksum(), text.Checksum); AssertEx.Equal(BitConverter.GetBytes(Encoding.Unicode.GetPreamble().Length + LargeSource.Length * sizeof(char)), text.Blob.Take(4)); AssertEx.Equal(Encoding.Unicode.GetPreamble().Concat(Encoding.Unicode.GetBytes(LargeSource)), Decompress(text.Blob.Skip(4))); }
public CompileResult Run(string sourceCodePath, string sourceCode, bool isReleaseBuild) { using var asmImage = new MemoryStream(); var symbolsName = Path.ChangeExtension("compiled.dll", ".pdb"); var buffer = Encoding.UTF8.GetBytes(sourceCode); var sourceText = SourceText.From(buffer, buffer.Length, Encoding.UTF8, canBeEmbedded: true); var compilation = GenerateCode("compiled.dll", sourceText, sourceCodePath, isReleaseBuild); var emitOptions = new EmitOptions( debugInformationFormat: DebugInformationFormat.Embedded, pdbFilePath: symbolsName ); var result = compilation.Emit( asmImage, embeddedTexts: new[] { EmbeddedText.FromSource(sourceCodePath, sourceText) }, options: emitOptions); if (result.Success) { asmImage.Seek(0, SeekOrigin.Begin); return(new CompileResult(asmImage.ToArray(), Array.Empty <CompileResult.Message>())); } else { var messages = result.Diagnostics .Where(x => x.IsWarningAsError || x.Severity == DiagnosticSeverity.Error) .OrderBy(x => x.Location.SourceSpan.Start); return(new CompileResult(Array.Empty <byte>(), messages.Select(x => { var lineSpan = x.Location.GetMappedLineSpan().Span; var startLine = lineSpan.Start.Line; var startCharacter = lineSpan.Start.Character; var endLine = lineSpan.End.Line; var endCharacter = lineSpan.End.Character; var severity = x.Severity.ToString().ToLower(); return new CompileResult.Message( startLine, startCharacter, endLine, endCharacter, severity, x.Id, x.GetMessage() ); }).ToArray())); } }
public void FromSource_Empty() { var source = SourceText.From("", new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), SourceHashAlgorithm.Sha1); var text = EmbeddedText.FromSource("pathToEmpty", source); var checksum = SourceText.CalculateChecksum(new byte[0], 0, 0, SourceHashAlgorithm.Sha1); Assert.Equal("pathToEmpty", text.FilePath); Assert.Equal(SourceHashAlgorithm.Sha1, text.ChecksumAlgorithm); AssertEx.Equal(checksum, text.Checksum); AssertEx.Equal(new byte[] { 0, 0, 0, 0 }, text.Blob); }
public void FromSource_Small() { var source = SourceText.From(SmallSource, Encoding.UTF8, SourceHashAlgorithm.Sha1); var text = EmbeddedText.FromSource("pathToSmall", source); Assert.Equal("pathToSmall", text.FilePath); Assert.Equal(SourceHashAlgorithm.Sha1, text.ChecksumAlgorithm); AssertEx.Equal(source.GetChecksum(), text.Checksum); AssertEx.Equal(new byte[] { 0, 0, 0, 0 }, text.Blob.Take(4)); AssertEx.Equal(Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(SmallSource)), text.Blob.Skip(4)); }
public Assembly CompileSourceCode(string path, string sourceCode, string dllName) { var wrapLog = Log.Call($"Source code compilation: {dllName}."); var encoding = Encoding.UTF8; var pdbName = $"{dllName}.pdb"; using (var peStream = new MemoryStream()) using (var pdbStream = new MemoryStream()) { var options = new EmitOptions( debugInformationFormat: DebugInformationFormat.PortablePdb, pdbFilePath: pdbName); var buffer = encoding.GetBytes(sourceCode); var sourceText = SourceText.From(buffer, buffer.Length, encoding, canBeEmbedded: true); var embeddedTexts = new List <EmbeddedText> { EmbeddedText.FromSource(path, sourceText), }; var result = GenerateCode(path, sourceText, dllName).Emit(peStream, pdbStream, embeddedTexts: embeddedTexts, options: options); if (!result.Success) { wrapLog("Compilation done with error."); var errors = new List <string>(); var failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); foreach (var diagnostic in failures) { Log.Add("{0}: {1}", diagnostic.Id, diagnostic.GetMessage()); errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}"); } throw new Exception(String.Join("\n", errors)); } wrapLog("Compilation done without any error."); peStream.Seek(0, SeekOrigin.Begin); pdbStream?.Seek(0, SeekOrigin.Begin); var assemblyLoadContext = new SimpleUnloadableAssemblyLoadContext(); var assembly = assemblyLoadContext.LoadFromStream(peStream, pdbStream); return(assembly); } }
public void EmbeddedPdb() { string source = @" using System; class C { public static void Main() { Console.WriteLine(); } } "; var tree = Parse(source, "f:/build/goo.cs"); var c = CreateCompilation(tree, options: TestOptions.DebugDll); var pdbStream = new MemoryStream(); var peBlob = c.EmitToArray( EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.Embedded), embeddedTexts: new[] { EmbeddedText.FromSource(tree.FilePath, tree.GetText()) } ); pdbStream.Position = 0; using (var peReader = new PEReader(peBlob)) { var embeddedEntry = peReader .ReadDebugDirectory() .Single(e => e.Type == DebugDirectoryEntryType.EmbeddedPortablePdb); using ( var embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedEntry) ) { var pdbReader = embeddedMetadataProvider.GetMetadataReader(); var embeddedSource = ( from documentHandle in pdbReader.Documents let document = pdbReader.GetDocument(documentHandle) select new { FilePath = pdbReader.GetString(document.Name), Text = pdbReader.GetEmbeddedSource(documentHandle) } ).Single(); Assert.Equal("f:/build/goo.cs", embeddedSource.FilePath); Assert.Equal(source, embeddedSource.Text.ToString()); } } }
internal static SourceText Decode( Stream stream, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, bool throwIfBinaryDetected, bool canBeEmbedded ) { stream.Seek(0, SeekOrigin.Begin); long longLength = stream.Length; if (longLength == 0) { return(SourceText.From(string.Empty, encoding, checksumAlgorithm)); } var maxCharRemainingGuess = encoding.GetMaxCharCountOrThrowIfHuge(stream); Debug.Assert(longLength > 0 && longLength <= int.MaxValue); // GetMaxCharCountOrThrowIfHuge should have thrown. int length = (int)longLength; using ( var reader = new StreamReader( stream, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: Math.Min(length, 4096), leaveOpen: true ) ) { var chunks = ReadChunksFromTextReader( reader, maxCharRemainingGuess, throwIfBinaryDetected ); // We must compute the checksum and embedded text blob now while we still have the original bytes in hand. // We cannot re-encode to obtain checksum and blob as the encoding is not guaranteed to round-trip. var checksum = CalculateChecksum(stream, checksumAlgorithm); var embeddedTextBlob = canBeEmbedded ? EmbeddedText.CreateBlob(stream) : default(ImmutableArray <byte>); return(new LargeText( chunks, reader.CurrentEncoding, checksum, checksumAlgorithm, embeddedTextBlob )); } }
public void FromBytes_Large() { var bytes = Encoding.Unicode.GetBytes(LargeSource); var checksum = SourceText.CalculateChecksum(bytes, 0, bytes.Length, SourceHashAlgorithm.Sha256); var text = EmbeddedText.FromBytes("pathToLarge", new ArraySegment <byte>(bytes, 0, bytes.Length), SourceHashAlgorithm.Sha256); Assert.Equal("pathToLarge", text.FilePath); Assert.Equal(SourceHashAlgorithm.Sha256, text.ChecksumAlgorithm); AssertEx.Equal(checksum, text.Checksum); AssertEx.Equal(BitConverter.GetBytes(bytes.Length), text.Blob.Take(4)); AssertEx.Equal(bytes, Decompress(text.Blob.Skip(4))); }
public void FromBytes_Small() { var bytes = Encoding.UTF8.GetBytes(SmallSource); var checksum = SourceText.CalculateChecksum(bytes, 0, bytes.Length, SourceHashAlgorithm.Sha1); var text = EmbeddedText.FromBytes("pathToSmall", new ArraySegment <byte>(bytes, 0, bytes.Length)); Assert.Equal("pathToSmall", text.FilePath); Assert.Equal(text.ChecksumAlgorithm, SourceHashAlgorithm.Sha1); AssertEx.Equal(checksum, text.Checksum); AssertEx.Equal(new byte[] { 0, 0, 0, 0 }, text.Blob.Take(4)); AssertEx.Equal(bytes, text.Blob.Skip(4)); }
public void FromTextReader_Large() { var expected = SourceText.From(LargeSource, Encoding.UTF8, SourceHashAlgorithm.Sha1); var expectedEmbeded = EmbeddedText.FromSource("pathToSmall", expected); var actual = SourceText.From(new StringReader(LargeSource), LargeSource.Length, Encoding.UTF8, SourceHashAlgorithm.Sha1); var actualEmbeded = EmbeddedText.FromSource(expectedEmbeded.FilePath, actual); Assert.Equal(expectedEmbeded.FilePath, actualEmbeded.FilePath); Assert.Equal(expectedEmbeded.ChecksumAlgorithm, actualEmbeded.ChecksumAlgorithm); AssertEx.Equal(expectedEmbeded.Checksum, actualEmbeded.Checksum); AssertEx.Equal(expectedEmbeded.Blob, actualEmbeded.Blob); }
IEnumerable <EmbeddedText> CollectAdditionalEmbeddedTexts() { // TODO: if (EmbedPharContentIntoPdb): foreach (var f in this.SourceSymbolCollection.GetFiles()) { var tree = f.SyntaxTree; if (tree.IsPharEntry || tree.IsPharStub) { yield return(EmbeddedText.FromSource(tree.GetDebugSourceDocumentPath(), tree.GetText())); } } }
public void FromStream_IOErrors() { Assert.Throws <IOException>(() => EmbeddedText.FromStream("path", new HugeStream())); Assert.Throws <EndOfStreamException>( () => EmbeddedText.FromStream("path", new TruncatingStream(10)) ); Assert.Throws <EndOfStreamException>( () => EmbeddedText.FromStream("path", new TruncatingStream(1000)) ); Assert.Throws <IOException>( () => EmbeddedText.FromStream("path", new ReadFailsStream()) ); }
public void FromSource_ArgumentErrors() { Assert.Throws <ArgumentNullException>("filePath", () => EmbeddedText.FromSource(null, null)); Assert.Throws <ArgumentException>("filePath", () => EmbeddedText.FromSource("", null)); Assert.Throws <ArgumentNullException>("text", () => EmbeddedText.FromSource("path", null)); // no encoding Assert.Throws <ArgumentException>("text", () => EmbeddedText.FromSource("path", SourceText.From("source"))); // embedding not allowed Assert.Throws <ArgumentException>("text", () => EmbeddedText.FromSource("path", SourceText.From(new byte[0], 0, Encoding.UTF8, canBeEmbedded: false))); Assert.Throws <ArgumentException>("text", () => EmbeddedText.FromSource("path", SourceText.From(new MemoryStream(new byte[0]), Encoding.UTF8, canBeEmbedded: false))); }
public Source(Stream s, string name, bool includeText) { Name = name; SourceText source = SourceText.From(s, canBeEmbedded: includeText); if (includeText) { Text = EmbeddedText.FromSource(name, source); Tree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Latest), name); } else { Tree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Latest)); } }
public async Task <bool> BuildAsync(string code, OptimizationLevel?optimizationLevel, string codePath, CancellationToken cancellationToken = default) { await new NoContextYieldAwaitable(); _logger.LogInformation($"{Name}: Start to build..."); var sw = Stopwatch.StartNew(); try { _assemblyPath = Path.Combine(BuildPath, $"{Name}.dll"); _depsFile = Path.ChangeExtension(_assemblyPath, ".deps.json"); var encoding = Encoding.UTF8; var buffer = encoding.GetBytes(code); var sourceText = SourceText.From(buffer, buffer.Length, encoding, canBeEmbedded: true); var scriptRunner = CreateScriptRunner(sourceText, codePath, optimizationLevel); CopyDependencies(); var embeddedTexts = new List <EmbeddedText>() { EmbeddedText.FromSource(codePath, sourceText), }; var diagnostics = await scriptRunner.SaveAssembly(_assemblyPath, embeddedTexts, cancellationToken) .ConfigureAwait(false); SendDiagnostics(diagnostics); var error = diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error); _logger.LogInformation($"{Name}: Build {(error ? "error": "successfully")} , time: {sw.ElapsedMilliseconds}ms"); if (error) { return(false); } CreateRuntimeConfig(); } catch (Exception e) { _logger?.LogError(e.Message + e.StackTrace); return(false); } return(true); }
public EmitResult Emit( Stream rebuildPeStream, Compilation rebuildCompilation, CancellationToken cancellationToken) { var embeddedTexts = rebuildCompilation.SyntaxTrees .Select(st => (path: st.FilePath, text: st.GetText())) .Where(pair => pair.text.CanBeEmbedded) .Select(pair => EmbeddedText.FromSource(pair.path, pair.text)) .ToImmutableArray(); return(Emit( rebuildPeStream, rebuildCompilation, embeddedTexts, cancellationToken)); }
private void AddCode(string desiredPath, MemberDeclarationSyntax member) { var compilationUnit = SyntaxFactory.CompilationUnit().AddMembers(member); var sourceText = compilationUnit.ToString(); var sourceBytes = Encoding.UTF8.GetBytes(sourceText); var embeddableText = SourceText.From(sourceBytes, sourceBytes.Length, Encoding.UTF8, canBeEmbedded: true); embeddedSource.Add(EmbeddedText.FromSource(desiredPath, embeddableText)); var tree = CSharpSyntaxTree.Create(compilationUnit, null, desiredPath, Encoding.UTF8); this.compilation = this.compilation.AddSyntaxTrees(tree); if (string.IsNullOrWhiteSpace(this.generatedScriptOutput) == false) { File.WriteAllText(Path.Combine(this.generatedScriptOutput, desiredPath), sourceText); } }
public void FromSource_Precomputed() { byte[] bytes = Encoding.ASCII.GetBytes(LargeSource); bytes[0] = 0xFF; // invalid ASCII, should be reflected in checksum, blob. foreach (bool useStream in new[] { true, false }) { var source = useStream ? SourceText.From(new MemoryStream(bytes), Encoding.ASCII, SourceHashAlgorithm.Sha1, canBeEmbedded: true) : SourceText.From(bytes, bytes.Length, Encoding.ASCII, SourceHashAlgorithm.Sha1, canBeEmbedded: true); var text = EmbeddedText.FromSource("pathToPrecomputed", source); Assert.Equal("pathToPrecomputed", text.FilePath); Assert.Equal(SourceHashAlgorithm.Sha1, text.ChecksumAlgorithm); AssertEx.Equal(SourceText.CalculateChecksum(bytes, 0, bytes.Length, SourceHashAlgorithm.Sha1), source.GetChecksum()); AssertEx.Equal(source.GetChecksum(), text.Checksum); AssertEx.Equal(BitConverter.GetBytes(bytes.Length), text.Blob.Take(4)); AssertEx.Equal(bytes, Decompress(text.Blob.Skip(4))); } }
public void EmbeddedSource() { string source = @" using System; class C { public static void Main() { Console.WriteLine(); } } "; var tree = Parse(source, "f:/build/foo.cs"); var c = CreateCompilationWithMscorlib(tree, options: TestOptions.DebugDll); var pdbStream = new MemoryStream(); c.EmitToArray( EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.PortablePdb), pdbStream: pdbStream, embeddedTexts: new[] { EmbeddedText.FromSource(tree.FilePath, tree.GetText()) }); pdbStream.Position = 0; using (var provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream)) { var pdbReader = provider.GetMetadataReader(); var embeddedSource = (from documentHandle in pdbReader.Documents let document = pdbReader.GetDocument(documentHandle) select new { FilePath = pdbReader.GetString(document.Name), Text = pdbReader.GetEmbeddedSource(documentHandle) }).Single(); Assert.Equal(embeddedSource.FilePath, "f:/build/foo.cs"); Assert.Equal(source, embeddedSource.Text.ToString()); } }
public static void CompileCSharpWithPdb(string assemblyName, Dictionary <string, string> sourceFiles) { var parseOptions = new CSharpParseOptions(languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.Latest); List <EmbeddedText> embeddedTexts = new List <EmbeddedText>(); List <SyntaxTree> syntaxTrees = new List <SyntaxTree>(); foreach (KeyValuePair <string, string> file in sourceFiles) { var sourceText = SourceText.From(file.Value, new UTF8Encoding(false), SourceHashAlgorithm.Sha256); syntaxTrees.Add(SyntaxFactory.ParseSyntaxTree(sourceText, parseOptions, file.Key)); embeddedTexts.Add(EmbeddedText.FromSource(file.Key, sourceText)); } var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(assemblyName), syntaxTrees, roslynDefaultReferences.Value.Select(r => MetadataReference.CreateFromFile(r)), new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, platform: Platform.AnyCpu, optimizationLevel: OptimizationLevel.Release, allowUnsafe: true, deterministic: true )); using (FileStream peStream = File.Open(assemblyName + ".dll", FileMode.OpenOrCreate, FileAccess.ReadWrite)) using (FileStream pdbStream = File.Open(assemblyName + ".pdb", FileMode.OpenOrCreate, FileAccess.ReadWrite)) { var emitResult = compilation.Emit(peStream, pdbStream, options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb, pdbFilePath: assemblyName + ".pdb"), embeddedTexts: embeddedTexts); if (!emitResult.Success) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var diag in emitResult.Diagnostics) { b.AppendLine(diag.ToString()); } throw new Exception(b.ToString()); } } }
/// <inheritdoc /> public Assembly Compile(string sourceTextHash, CSharpCompilation compilation, Action <EmitResult> check) { this._logger.LogInformation("Compiling source to an in-memory DLL with embedded source"); using var assemblyStream = new MemoryStream(); using var symbolsStream = new MemoryStream(); var emitOptions = new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb); var embeddedTexts = compilation.SyntaxTrees.Select(s => EmbeddedText.FromSource(s.FilePath, s.GetText())); var result = compilation.Emit( peStream: assemblyStream, pdbStream: symbolsStream, embeddedTexts: embeddedTexts, options: emitOptions); check(result); assemblyStream.Seek(0, SeekOrigin.Begin); symbolsStream.Seek(0, SeekOrigin.Begin); return(AssemblyLoadContext.Default.LoadFromStream(assemblyStream, symbolsStream)); }
/// <summary> /// Constructs a <see cref="SourceText"/> from a byte array. /// </summary> /// <param name="buffer">The encoded source buffer.</param> /// <param name="length">The number of bytes to read from the buffer.</param> /// <param name="encoding"> /// Data encoding to use if the encoded buffer doesn't start with Byte Order Mark. /// <see cref="Encoding.UTF8"/> if not specified. /// </param> /// <param name="checksumAlgorithm"> /// Hash algorithm to use to calculate checksum of the text that's saved to PDB. /// </param> /// <param name="throwIfBinaryDetected">If the decoded text contains at least two consecutive NUL /// characters, then an <see cref="InvalidDataException"/> is thrown.</param> /// <returns>The decoded text.</returns> /// <param name="canBeEmbedded">True if the text can be passed to <see cref="EmbeddedText.FromSource"/> and be embedded in a PDB.</param> /// <exception cref="ArgumentNullException">The <paramref name="buffer"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException">The <paramref name="length"/> is negative or longer than the <paramref name="buffer"/>.</exception> /// <exception cref="ArgumentException"><paramref name="checksumAlgorithm"/> is not supported.</exception> /// <exception cref="DecoderFallbackException">If the given encoding is set to use a throwing decoder as a fallback</exception> /// <exception cref="InvalidDataException">Two consecutive NUL characters were detected in the decoded text and <paramref name="throwIfBinaryDetected"/> was true.</exception> public static SourceText From( byte[] buffer, int length, Encoding?encoding = null, SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1, bool throwIfBinaryDetected = false, bool canBeEmbedded = false ) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (length < 0 || length > buffer.Length) { throw new ArgumentOutOfRangeException(nameof(length)); } ValidateChecksumAlgorithm(checksumAlgorithm); string text = Decode(buffer, length, encoding ?? s_utf8EncodingWithNoBOM, out encoding); if (throwIfBinaryDetected && IsBinary(text)) { throw new InvalidDataException(); } // We must compute the checksum and embedded text blob now while we still have the original bytes in hand. // We cannot re-encode to obtain checksum and blob as the encoding is not guaranteed to round-trip. var checksum = CalculateChecksum(buffer, 0, length, checksumAlgorithm); var embeddedTextBlob = canBeEmbedded ? EmbeddedText.CreateBlob(new ArraySegment <byte>(buffer, 0, length)) : default(ImmutableArray <byte>); return(new StringText(text, encoding, checksum, checksumAlgorithm, embeddedTextBlob)); }