提交 c03dd877 编写于 作者: J Jared Parsons

Merge pull request #1134 from jaredpar/fix-1086

Ensure AnalyzerDriver completes during Compilation
......@@ -328,159 +328,174 @@ private int RunCore(TextWriter consoleOutput, CancellationToken cancellationToke
cancellationToken.ThrowIfCancellationRequested();
var analyzerOptions = new AnalyzerOptions(ImmutableArray.Create<AdditionalText, AdditionalTextFile>(additionalTextFiles));
Func<ImmutableArray<Diagnostic>> getAnalyzerDiagnostics = null;
if (!analyzers.IsDefaultOrEmpty)
{
var analyzerManager = new AnalyzerManager();
var analyzerExceptionDiagnostics = new ConcurrentSet<Diagnostic>();
Action<Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic);
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.
if (PrintErrors(compilation.GetParseDiagnostics(), consoleOutput))
{
return Failed;
}
if (PrintErrors(compilation.GetDeclarationDiagnostics(), consoleOutput))
CancellationTokenSource analyzerCts = null;
try
{
return Failed;
}
EmitResult emitResult;
// NOTE: as native compiler does, we generate the documentation file
// NOTE: 'in place', replacing the contents of the file if it exists
string finalOutputPath;
string finalPdbFilePath;
string finalXmlFilePath;
FileStream xml = null;
cancellationToken.ThrowIfCancellationRequested();
Func<ImmutableArray<Diagnostic>> getAnalyzerDiagnostics = null;
if (!analyzers.IsDefaultOrEmpty)
{
analyzerCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
var analyzerManager = new AnalyzerManager();
var analyzerExceptionDiagnostics = new ConcurrentSet<Diagnostic>();
Action<Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic);
var analyzerOptions = new AnalyzerOptions(ImmutableArray.Create<AdditionalText, AdditionalTextFile>(additionalTextFiles));
var analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, out compilation, analyzerCts.Token);
getAnalyzerDiagnostics = () =>
{
var analyzerDiagnostics = analyzerDriver.GetDiagnosticsAsync().Result;
return analyzerDiagnostics.AddRange(analyzerExceptionDiagnostics);
};
}
finalXmlFilePath = Arguments.DocumentationPath;
if (finalXmlFilePath != null)
{
xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
if (xml == null)
// Print the diagnostics produced during the parsing stage and exit if there were any errors.
if (PrintErrors(compilation.GetParseDiagnostics(), consoleOutput))
{
return Failed;
}
xml.SetLength(0);
}
cancellationToken.ThrowIfCancellationRequested();
IEnumerable<DiagnosticInfo> errors;
using (var win32Res = GetWin32Resources(Arguments, compilation, out errors))
using (xml)
{
if (PrintErrors(errors, consoleOutput))
if (PrintErrors(compilation.GetDeclarationDiagnostics(), consoleOutput))
{
return Failed;
}
cancellationToken.ThrowIfCancellationRequested();
EmitResult emitResult;
string outputName = GetOutputFileName(compilation, cancellationToken);
// NOTE: as native compiler does, we generate the documentation file
// NOTE: 'in place', replacing the contents of the file if it exists
finalOutputPath = Path.Combine(Arguments.OutputDirectory, outputName);
finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalOutputPath, ".pdb");
string finalOutputPath;
string finalPdbFilePath;
string finalXmlFilePath;
// NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit.
var emitOptions = Arguments.EmitOptions.
WithOutputNameOverride(outputName).
WithPdbFilePath(finalPdbFilePath);
FileStream xml = null;
var pdbOutputInfo = Arguments.EmitPdb
? new Cci.PdbOutputInfo(finalPdbFilePath)
: Cci.PdbOutputInfo.None;
cancellationToken.ThrowIfCancellationRequested();
using (var peStreamProvider = new CompilerEmitStreamProvider(this, touchedFilesLogger, finalOutputPath))
finalXmlFilePath = Arguments.DocumentationPath;
if (finalXmlFilePath != null)
{
emitResult = compilation.Emit(
peStreamProvider,
pdbOutputInfo,
xml,
win32Res,
Arguments.ManifestResources,
emitOptions,
getAnalyzerDiagnostics,
cancellationToken);
if (emitResult.Success && !pdbOutputInfo.IsNone && touchedFilesLogger != null)
xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
if (xml == null)
{
touchedFilesLogger.AddWritten(pdbOutputInfo.FileName);
return Failed;
}
xml.SetLength(0);
}
}
GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics);
cancellationToken.ThrowIfCancellationRequested();
if (PrintErrors(emitResult.Diagnostics, consoleOutput))
{
return Failed;
}
IEnumerable<DiagnosticInfo> errors;
using (var win32Res = GetWin32Resources(Arguments, compilation, out errors))
using (xml)
{
if (PrintErrors(errors, consoleOutput))
{
return Failed;
}
cancellationToken.ThrowIfCancellationRequested();
cancellationToken.ThrowIfCancellationRequested();
bool errorsReadingAdditionalFiles = false;
foreach (var additionalFile in additionalTextFiles)
{
if (PrintErrors(additionalFile.Diagnostics, consoleOutput))
{
errorsReadingAdditionalFiles = true;
}
}
string outputName = GetOutputFileName(compilation, cancellationToken);
if (errorsReadingAdditionalFiles)
{
return Failed;
}
finalOutputPath = Path.Combine(Arguments.OutputDirectory, outputName);
finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalOutputPath, ".pdb");
cancellationToken.ThrowIfCancellationRequested();
// NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit.
var emitOptions = Arguments.EmitOptions.
WithOutputNameOverride(outputName).
WithPdbFilePath(finalPdbFilePath);
if (Arguments.TouchedFilesPath != null)
{
Debug.Assert(touchedFilesLogger != null);
var pdbOutputInfo = Arguments.EmitPdb
? new Cci.PdbOutputInfo(finalPdbFilePath)
: Cci.PdbOutputInfo.None;
if (finalXmlFilePath != null)
{
touchedFilesLogger.AddWritten(finalXmlFilePath);
using (var peStreamProvider = new CompilerEmitStreamProvider(this, touchedFilesLogger, finalOutputPath))
{
emitResult = compilation.Emit(
peStreamProvider,
pdbOutputInfo,
xml,
win32Res,
Arguments.ManifestResources,
emitOptions,
getAnalyzerDiagnostics,
cancellationToken);
if (emitResult.Success && !pdbOutputInfo.IsNone && touchedFilesLogger != null)
{
touchedFilesLogger.AddWritten(pdbOutputInfo.FileName);
}
}
}
var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, FileMode.OpenOrCreate);
if (readStream == null)
GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics);
if (PrintErrors(emitResult.Diagnostics, consoleOutput))
{
return Failed;
}
using (var writer = new StreamWriter(readStream))
cancellationToken.ThrowIfCancellationRequested();
bool errorsReadingAdditionalFiles = false;
foreach (var additionalFile in additionalTextFiles)
{
touchedFilesLogger.WriteReadPaths(writer);
if (PrintErrors(additionalFile.Diagnostics, consoleOutput))
{
errorsReadingAdditionalFiles = true;
}
}
var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, FileMode.OpenOrCreate);
if (writtenStream == null)
if (errorsReadingAdditionalFiles)
{
return Failed;
}
using (var writer = new StreamWriter(writtenStream))
cancellationToken.ThrowIfCancellationRequested();
if (Arguments.TouchedFilesPath != null)
{
Debug.Assert(touchedFilesLogger != null);
if (finalXmlFilePath != null)
{
touchedFilesLogger.AddWritten(finalXmlFilePath);
}
var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, FileMode.OpenOrCreate);
if (readStream == null)
{
return Failed;
}
using (var writer = new StreamWriter(readStream))
{
touchedFilesLogger.WriteReadPaths(writer);
}
var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, FileMode.OpenOrCreate);
if (writtenStream == null)
{
return Failed;
}
using (var writer = new StreamWriter(writtenStream))
{
touchedFilesLogger.WriteWrittenPaths(writer);
}
}
}
finally
{
// At this point analyzers are already complete in which case this is a no-op. Or they are
// still running because the compilation failed before all of the compilation events were
// raised. In the latter case the driver, and all its associated state, will be waiting around
// for events that are never coming. Cancel now and let the clean up process begin.
if (analyzerCts != null)
{
touchedFilesLogger.WriteWrittenPaths(writer);
analyzerCts.Cancel();
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册