diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs index 91e037c847840ecc23f1cded490674040a1ba85f..fcd7824f6fb16af0768cd452ddaf5460b9f1fe73 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs @@ -3875,6 +3875,7 @@ public void SymWriterErrors() win32Resources: null, manifestResources: null, options: null, + getHostDiagnostics: null, testData: new CompilationTestData() { SymWriterFactory = () => new MockSymUnmanagedWriter() }); result.Diagnostics.Verify( diff --git a/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs b/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs index 9056acad83fb1ca213c3cf233d41210801b39f12..f2ec0b0df1acfa9631109826ea08c05bd48e7380 100644 --- a/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs +++ b/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs @@ -10,7 +10,7 @@ internal abstract partial class CommonCompiler { /// /// This implementation of will delay the creation - /// of the PE + PDB file until the compiler determines the compilation has succeeded. This prevents + /// of the PE / PDB file until the compiler determines the compilation has succeeded. This prevents /// the compiler from deleting output from the previous compilation when a new compilation /// fails. /// @@ -18,52 +18,30 @@ private sealed class CompilerEmitStreamProvider : Compilation.EmitStreamProvider { private readonly CommonCompiler _compiler; private readonly TouchedFileLogger _touchedFileLogger; - private readonly string _peFilePath; - private readonly string _pdbFilePath; - private Stream _peStream; - private Stream _pdbStream; + private readonly string _filePath; + private Stream _stream; - internal CompilerEmitStreamProvider(CommonCompiler compiler, TouchedFileLogger touchedFileLogger, string peFilePath, string pdbFilePath) + internal CompilerEmitStreamProvider(CommonCompiler compiler, TouchedFileLogger touchedFileLogger, string filePath) { _compiler = compiler; _touchedFileLogger = touchedFileLogger; - _peFilePath = peFilePath; - _pdbFilePath = pdbFilePath; + _filePath = filePath; } public void Dispose() { - _peStream?.Dispose(); - _peStream = null; - _pdbStream?.Dispose(); - _pdbStream = null; + _stream?.Dispose(); + _stream = null; } - public override bool HasPdbStream + public override Stream GetStream(DiagnosticBag diagnostics) { - get { return _pdbFilePath != null; } - } - - public override Stream GetPeStream(DiagnosticBag diagnostics) - { - if (_peStream == null) + if (_stream == null) { - _peStream = OpenFile(_peFilePath, diagnostics); + _stream = OpenFile(_filePath, diagnostics); } - return _peStream; - } - - public override Stream GetPdbStream(DiagnosticBag diagnostics) - { - Debug.Assert(HasPdbStream); - - if (_pdbStream == null) - { - _pdbStream = OpenFile(_pdbFilePath, diagnostics); - } - - return _pdbStream; + return _stream; } private Stream OpenFile(string filePath, DiagnosticBag diagnostics) @@ -87,35 +65,5 @@ private Stream OpenFile(string filePath, DiagnosticBag diagnostics) } } } - - private sealed class SimpleEmitStreamProvider : Compilation.EmitStreamProvider - { - private readonly Stream _peStream; - private readonly Stream _pdbStream; - - internal SimpleEmitStreamProvider(Stream peStream, Stream pdbStream = null) - { - Debug.Assert(peStream.CanWrite); - Debug.Assert(pdbStream == null || pdbStream.CanWrite); - _peStream = peStream; - _pdbStream = pdbStream; - } - - public override bool HasPdbStream - { - get { return _pdbStream != null; } - } - - public override Stream GetPeStream(DiagnosticBag diagnostics) - { - return _peStream; - } - - public override Stream GetPdbStream(DiagnosticBag diagnostics) - { - Debug.Assert(HasPdbStream); - return _pdbStream; - } - } } } \ No newline at end of file diff --git a/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.cs b/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.cs index f4ca49ffd64457a8f97593a7583bcfa3ee685a54..d1321f22c9c322b1aae3eaed4a5740d2752c2980 100644 --- a/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.cs +++ b/src/Compilers/Core/Desktop/CommandLine/CommonCompiler.cs @@ -330,16 +330,19 @@ private int RunCore(TextWriter consoleOutput, CancellationToken cancellationToke var analyzerOptions = new AnalyzerOptions(ImmutableArray.Create(additionalTextFiles)); - AnalyzerDriver analyzerDriver = null; - AnalyzerManager analyzerManager = null; - ConcurrentSet analyzerExceptionDiagnostics = null; + Func> getAnalyzerDiagnostics = null; if (!analyzers.IsDefaultOrEmpty) { - analyzerManager = new AnalyzerManager(); - analyzerExceptionDiagnostics = new ConcurrentSet(); + var analyzerManager = new AnalyzerManager(); + var analyzerExceptionDiagnostics = new ConcurrentSet(); Action addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic); - analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, out compilation, cancellationToken); + var analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, out compilation, cancellationToken); + getAnalyzerDiagnostics = () => + { + var analyzerDiagnostics = analyzerDriver.GetDiagnosticsAsync().Result; + return analyzerDiagnostics.AddRange(analyzerExceptionDiagnostics); + }; } // Print the diagnostics produced during the parsing stage and exit if there were any errors. @@ -401,9 +404,10 @@ private int RunCore(TextWriter consoleOutput, CancellationToken cancellationToke WithOutputNameOverride(outputName). WithPdbFilePath(finalPdbFilePath); - using (var emitStreamProvider = new CompilerEmitStreamProvider(this, touchedFilesLogger, finalOutputPath, Arguments.EmitPdb ? finalPdbFilePath : null)) + using (var peStreamProvider = new CompilerEmitStreamProvider(this, touchedFilesLogger, finalOutputPath)) + using (var pdbStreamProvider = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, touchedFilesLogger, finalPdbFilePath) : null) { - emitResult = compilation.Emit(emitStreamProvider, xml, win32Res, Arguments.ManifestResources, emitOptions, cancellationToken); + emitResult = compilation.Emit(peStreamProvider, pdbStreamProvider, xml, win32Res, Arguments.ManifestResources, emitOptions, getAnalyzerDiagnostics, cancellationToken); } } @@ -416,19 +420,6 @@ private int RunCore(TextWriter consoleOutput, CancellationToken cancellationToke cancellationToken.ThrowIfCancellationRequested(); - if (analyzerDriver != null) - { - var analyzerDiagnostics = analyzerDriver.GetDiagnosticsAsync().Result; - var allAnalyzerDiagnostics = analyzerDiagnostics.AddRange(analyzerExceptionDiagnostics); - - if (PrintErrors(allAnalyzerDiagnostics, consoleOutput)) - { - return Failed; - } - - cancellationToken.ThrowIfCancellationRequested(); - } - bool errorsReadingAdditionalFiles = false; foreach (var additionalFile in additionalTextFiles) { @@ -749,7 +740,7 @@ internal int RunInteractive(TextWriter consoleOutput) byte[] compiledAssembly; using (MemoryStream output = new MemoryStream()) { - EmitResult emitResult = compilation.Emit(new SimpleEmitStreamProvider(output)); + EmitResult emitResult = compilation.Emit(output); if (PrintErrors(emitResult.Diagnostics, consoleOutput)) { return Failed; diff --git a/src/Compilers/Core/Portable/Compilation.EmitStreamProvider.cs b/src/Compilers/Core/Portable/Compilation.EmitStreamProvider.cs index 0ac6f1d947a1092eaa9db3f1cb4ffcc4bd2b298d..c4f6b5cd38c7d820c475e26dc4e8fa8f8140f5a1 100644 --- a/src/Compilers/Core/Portable/Compilation.EmitStreamProvider.cs +++ b/src/Compilers/Core/Portable/Compilation.EmitStreamProvider.cs @@ -21,42 +21,26 @@ public abstract partial class Compilation /// internal abstract class EmitStreamProvider { - public abstract bool HasPdbStream - { - get; - } - - public abstract Stream GetPeStream(DiagnosticBag diagnostics); - - public abstract Stream GetPdbStream(DiagnosticBag diagnostics); + /// + /// This method will be called once during Emit at the time the Compilation needs the + /// associated for writing. It will not be called in the case of + /// user errors in code. + /// + public abstract Stream GetStream(DiagnosticBag diagnostics); } private sealed class SimpleEmitStreamProvider : EmitStreamProvider { - private readonly Stream _peStream; - private readonly Stream _pdbStream; - - internal SimpleEmitStreamProvider(Stream peStream, Stream pdbStream = null) - { - Debug.Assert(peStream.CanWrite); - Debug.Assert(pdbStream == null || pdbStream.CanWrite); - _peStream = peStream; - _pdbStream = pdbStream; - } - - public override bool HasPdbStream - { - get { return _pdbStream != null; } - } + private readonly Stream _stream; - public override Stream GetPeStream(DiagnosticBag diagnostics) + internal SimpleEmitStreamProvider(Stream stream) { - return _peStream; + _stream = stream; } - public override Stream GetPdbStream(DiagnosticBag diagnostics) + public override Stream GetStream(DiagnosticBag diagnostics) { - return _pdbStream; + return _stream; } } } diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 660b4b0b68ee1c6add284e6b2b7ebd7795aff431..a62c2bd26976ca2560605406041fd646983c9c44 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -1354,39 +1354,48 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) } return Emit( - new SimpleEmitStreamProvider(peStream, pdbStream), + peStream, + pdbStream, xmlDocumentationStream, win32Resources, manifestResources, options, - cancellationToken); + testData: null, + getHostDiagnostics: null, + cancellationToken: cancellationToken); } /// /// Emit the IL for the compiled source code into the specified stream. /// - /// Provides stream the compiler will write to. + /// Provides the PE stream the compiler will write to. + /// Provides the PDB stream the compiler will write to. /// Stream to which the compilation's XML documentation will be written. Null to forego XML generation. /// Stream from which the compilation's Win32 resources will be read (in RES format). /// Null to indicate that there are none. The RES format begins with a null resource entry. /// List of the compilation's managed resources. Null to indicate that there are none. /// Emit options. + /// Returns any extra diagnostics produced by the host of the compiler. /// To cancel the emit process. internal EmitResult Emit( - EmitStreamProvider emitStreamProvider, + EmitStreamProvider peStreamProvider, + EmitStreamProvider pdbStreamProvider, Stream xmlDocumentationStream = null, Stream win32Resources = null, IEnumerable manifestResources = null, EmitOptions options = null, + Func> getHostDiagnostics = null, CancellationToken cancellationToken = default(CancellationToken)) { return Emit( - emitStreamProvider, + peStreamProvider, + pdbStreamProvider, xmlDocumentationStream, win32Resources, manifestResources, options, testData: null, + getHostDiagnostics: getHostDiagnostics, cancellationToken: cancellationToken); } @@ -1486,15 +1495,18 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) IEnumerable manifestResources, EmitOptions options, CompilationTestData testData, + Func> getHostDiagnostics, CancellationToken cancellationToken) { return Emit( - new SimpleEmitStreamProvider(peStream, pdbStream), + new SimpleEmitStreamProvider(peStream), + pdbStream != null ? new SimpleEmitStreamProvider(pdbStream) : null, xmlDocumentationStream, win32Resources, manifestResources, options, testData, + getHostDiagnostics, cancellationToken); } @@ -1504,15 +1516,17 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) /// /// True if emit succeeded. internal EmitResult Emit( - EmitStreamProvider emitStreamProvider, + EmitStreamProvider peStreamProvider, + EmitStreamProvider pdbStreamProvider, Stream xmlDocumentationStream, Stream win32Resources, IEnumerable manifestResources, EmitOptions options, CompilationTestData testData, + Func> getHostDiagnostics, CancellationToken cancellationToken) { - Debug.Assert(emitStreamProvider != null); + Debug.Assert(peStreamProvider != null); DiagnosticBag diagnostics = new DiagnosticBag(); if (options != null) @@ -1558,7 +1572,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) moduleBeingBuilt, win32Resources, xmlDocumentationStream, - generateDebugInfo: emitStreamProvider.HasPdbStream, + generateDebugInfo: pdbStreamProvider != null, diagnostics: diagnostics, filterOpt: null, cancellationToken: cancellationToken)) @@ -1566,9 +1580,19 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken) return ToEmitResultAndFree(diagnostics, success: false); } + var hostDiagnostics = getHostDiagnostics != null + ? getHostDiagnostics() + : ImmutableArray.Empty; + diagnostics.AddRange(hostDiagnostics); + if (hostDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) + { + return ToEmitResultAndFree(diagnostics, success: false); + } + bool success = SerializeToPeStream( moduleBeingBuilt, - emitStreamProvider, + peStreamProvider, + pdbStreamProvider, options.PdbFilePath, (testData != null) ? testData.SymWriterFactory : null, diagnostics, @@ -1585,14 +1609,15 @@ private EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool success) internal bool SerializeToPeStream( CommonPEModuleBuilder moduleBeingBuilt, - EmitStreamProvider emitStreamProvider, + EmitStreamProvider peStreamProvider, + EmitStreamProvider pdbStreamProvider, string pdbFileName, Func testSymWriterFactory, DiagnosticBag diagnostics, bool metadataOnly, CancellationToken cancellationToken) { - Stream peStream = emitStreamProvider.GetPeStream(diagnostics); + Stream peStream = peStreamProvider.GetStream(diagnostics); if (peStream == null) { Debug.Assert(diagnostics.HasAnyErrors()); @@ -1601,9 +1626,9 @@ private EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool success) Debug.Assert(peStream.CanWrite); Stream pdbStream = null; - if (emitStreamProvider.HasPdbStream) + if (pdbStreamProvider != null) { - pdbStream = emitStreamProvider.GetPdbStream(diagnostics); + pdbStream = pdbStreamProvider.GetStream(diagnostics); if (pdbStream == null) { Debug.Assert(diagnostics.HasAnyErrors()); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index 7ed20c4377a25558b0f6b9575fbf4d20187a2068..7b1a89bcf722ef19635dd04b65024e8a9e1236da 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -3761,6 +3761,7 @@ static void M() manifestResources: null, options: EmitOptions.Default, testData: testData0, + getHostDiagnostics: null, cancellationToken: default(CancellationToken)); exeBytes = exeStream.ToArray(); pdbBytes = pdbStream.ToArray(); @@ -3860,6 +3861,7 @@ static void M() manifestResources: null, options: EmitOptions.Default, testData: testData0, + getHostDiagnostics: null, cancellationToken: default(CancellationToken)); exeBytes = exeStream.ToArray(); pdbBytes = pdbStream.ToArray(); diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs index 84fb46f324d567de85e62c5d8930bf4202e2cc61..53c215e141c0bf660775a83bc871a2470e6899e5 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs @@ -172,6 +172,7 @@ internal static ImmutableArray GetLocalNames(this ISymUnmanagedReader sy manifestResources: null, options: EmitOptions.Default, testData: null, + getHostDiagnostics: null, cancellationToken: default(CancellationToken)); if (!result.Success) diff --git a/src/Test/Utilities/CompilationExtensions.cs b/src/Test/Utilities/CompilationExtensions.cs index 05644ce63734369871bf4064656d03e653cb7577..baa5360f6a95e7f937a2cdfed8f1686289156ee4 100644 --- a/src/Test/Utilities/CompilationExtensions.cs +++ b/src/Test/Utilities/CompilationExtensions.cs @@ -31,6 +31,7 @@ public static class CompilationExtensions manifestResources: null, options: options, testData: testData, + getHostDiagnostics: null, cancellationToken: default(CancellationToken)); Assert.True(emitResult.Success, "Diagnostics:\r\n" + string.Join("\r\n, ", emitResult.Diagnostics.Select(d => d.ToString()))); diff --git a/src/Test/Utilities/HostedRuntimeEnvironment.cs b/src/Test/Utilities/HostedRuntimeEnvironment.cs index 2e697114ae4c7161d61107bfb3aaa71088cbc9b8..447dbdc117c06f405942719b016729f64b6925ae 100644 --- a/src/Test/Utilities/HostedRuntimeEnvironment.cs +++ b/src/Test/Utilities/HostedRuntimeEnvironment.cs @@ -222,6 +222,7 @@ private static IEnumerable EnumerateModules(Metadata metadata) manifestResources: manifestResources, options: EmitOptions.Default, testData: testData, + getHostDiagnostics: null, cancellationToken: default(CancellationToken)); } finally