提交 3f1a7557 编写于 作者: T Tomáš Matoušek 提交者: GitHub

Unify code creating debug source documents across C# and VB (#12968)

上级 f081705e
......@@ -2314,7 +2314,7 @@ internal override StrongNameKeys StrongNameKeys
}
else
{
if ((emittingPdb || emitOptions.EmitDynamicAnalysisData) && !StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics))
if ((emittingPdb || emitOptions.EmitDynamicAnalysisData) && !StartSourceChecksumCalculation(moduleBeingBuilt.DebugDocumentsBuilder, diagnostics))
{
return false;
}
......@@ -2381,54 +2381,6 @@ internal override StrongNameKeys StrongNameKeys
return FilterAndAppendAndFreeDiagnostics(diagnostics, ref xmlDiagnostics);
}
// TODO: consider unifying with VB
private bool StartSourceChecksumCalculation(PEModuleBuilder moduleBeingBuilt, DiagnosticBag diagnostics)
{
var syntaxTrees = this.SyntaxTrees;
// Check that all syntax trees are debuggable:
bool allTreesDebuggable = true;
foreach (var tree in syntaxTrees)
{
if (!string.IsNullOrEmpty(tree.FilePath) && tree.GetText().Encoding == null)
{
diagnostics.Add(ErrorCode.ERR_EncodinglessSyntaxTree, tree.GetRoot().GetLocation());
allTreesDebuggable = false;
}
}
if (!allTreesDebuggable)
{
return false;
}
// Add debug documents for all trees with distinct paths.
foreach (var tree in syntaxTrees)
{
if (!string.IsNullOrEmpty(tree.FilePath))
{
// compilation does not guarantee that all trees will have distinct paths.
// Do not attempt adding a document for a particular path if we already added one.
string normalizedPath = moduleBeingBuilt.NormalizeDebugDocumentPath(tree.FilePath, basePath: null);
var existingDoc = moduleBeingBuilt.TryGetDebugDocumentForNormalizedPath(normalizedPath);
if (existingDoc == null)
{
moduleBeingBuilt.AddDebugDocument(MakeDebugSourceDocumentForTree(normalizedPath, tree));
}
}
}
// Add debug documents for all pragmas.
// If there are clashes with already processed directives, report warnings.
// If there are clashes with debug documents that came from actual trees, ignore the pragma.
foreach (var tree in syntaxTrees)
{
AddDebugSourceDocumentsForChecksumDirectives(moduleBeingBuilt, tree, diagnostics);
}
return true;
}
private IEnumerable<string> AddedModulesResourceNames(DiagnosticBag diagnostics)
{
ImmutableArray<ModuleSymbol> modules = SourceAssembly.Modules;
......@@ -2509,8 +2461,8 @@ private string GetRuntimeMetadataVersion(EmitOptions emitOptions)
return emitOptions.RuntimeMetadataVersion;
}
private static void AddDebugSourceDocumentsForChecksumDirectives(
PEModuleBuilder moduleBeingBuilt,
internal override void AddDebugSourceDocumentsForChecksumDirectives(
DebugDocumentsBuilder documentsBuilder,
SyntaxTree tree,
DiagnosticBag diagnostics)
{
......@@ -2523,8 +2475,8 @@ private string GetRuntimeMetadataVersion(EmitOptions emitOptions)
var path = checksumDirective.File.ValueText;
var checksumText = checksumDirective.Bytes.ValueText;
var normalizedPath = moduleBeingBuilt.NormalizeDebugDocumentPath(path, basePath: tree.FilePath);
var existingDoc = moduleBeingBuilt.TryGetDebugDocumentForNormalizedPath(normalizedPath);
var normalizedPath = documentsBuilder.NormalizeDebugDocumentPath(path, basePath: tree.FilePath);
var existingDoc = documentsBuilder.TryGetDebugDocumentForNormalizedPath(normalizedPath);
// duplicate checksum pragmas are valid as long as values match
// if we have seen this document already, check for matching values.
......@@ -2562,7 +2514,7 @@ private string GetRuntimeMetadataVersion(EmitOptions emitOptions)
MakeChecksumBytes(checksumDirective.Bytes.ValueText),
Guid.Parse(checksumDirective.Guid.ValueText));
moduleBeingBuilt.AddDebugDocument(newDocument);
documentsBuilder.AddDebugDocument(newDocument);
}
}
}
......@@ -2606,10 +2558,7 @@ private static ImmutableArray<byte> MakeChecksumBytes(string bytesText)
return builder.ToImmutableAndFree();
}
private static Cci.DebugSourceDocument MakeDebugSourceDocumentForTree(string normalizedPath, SyntaxTree tree)
{
return new Cci.DebugSourceDocument(normalizedPath, Cci.DebugSourceDocument.CorSymLanguageTypeCSharp, () => tree.GetChecksumAndAlgorithm());
}
internal override Guid DebugSourceDocumentLanguageId => Cci.DebugSourceDocument.CorSymLanguageTypeCSharp;
internal override bool HasCodeToEmit()
{
......
......@@ -91,7 +91,7 @@ private void SetGlobalErrorIfTrue(bool arg)
if (emittingPdb || moduleBeingBuiltOpt?.EmitOptions.EmitDynamicAnalysisData == true)
{
_debugDocumentProvider = (path, basePath) => moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile);
_debugDocumentProvider = (path, basePath) => moduleBeingBuiltOpt.DebugDocumentsBuilder.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile);
}
}
......
......@@ -9,7 +9,6 @@
using System.Reflection;
using System.Reflection.PortableExecutable;
using System.Threading;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Emit;
......@@ -289,7 +288,7 @@ private void AddSymbolLocation(MultiDictionary<Cci.DebugSourceDocument, Cci.Defi
{
FileLinePositionSpan span = location.GetLineSpan();
Cci.DebugSourceDocument doc = TryGetDebugDocument(span.Path, basePath: location.SourceTree.FilePath);
Cci.DebugSourceDocument doc = DebugDocumentsBuilder.TryGetDebugDocument(span.Path, basePath: location.SourceTree.FilePath);
if (doc != null)
{
......@@ -1342,7 +1341,7 @@ internal NamedTypeSymbol GetFixedImplementationType(FieldSymbol field)
return result;
}
protected override IMethodDefinition CreatePrivateImplementationDetailsStaticConstructor(PrivateImplementationDetails details, CSharpSyntaxNode syntaxOpt, DiagnosticBag diagnostics)
protected override Cci.IMethodDefinition CreatePrivateImplementationDetailsStaticConstructor(PrivateImplementationDetails details, CSharpSyntaxNode syntaxOpt, DiagnosticBag diagnostics)
{
return new SynthesizedPrivateImplementationDetailsStaticConstructor(SourceModule, details, GetUntranslatedSpecialType(SpecialType.System_Void, syntaxOpt, diagnostics));
}
......
......@@ -121,46 +121,46 @@ public override ReportDiagnostic GetDiagnosticReport(DiagnosticInfo diagnosticIn
out hasPragmaSuppression);
}
public override int ERR_FailedToCreateTempFile { get { return (int)ErrorCode.ERR_CantMakeTempFile; } }
public override int ERR_FailedToCreateTempFile => (int)ErrorCode.ERR_CantMakeTempFile;
// command line:
public override int ERR_ExpectedSingleScript { get { return (int)ErrorCode.ERR_ExpectedSingleScript; } }
public override int ERR_OpenResponseFile { get { return (int)ErrorCode.ERR_OpenResponseFile; } }
public override int ERR_InvalidPathMap { get { return (int)ErrorCode.ERR_InvalidPathMap; } }
public override int FTL_InputFileNameTooLong { get { return (int)ErrorCode.FTL_InputFileNameTooLong; } }
public override int ERR_FileNotFound { get { return (int)ErrorCode.ERR_FileNotFound; } }
public override int ERR_NoSourceFile { get { return (int)ErrorCode.ERR_NoSourceFile; } }
public override int ERR_CantOpenFileWrite { get { return (int)ErrorCode.ERR_CantOpenFileWrite; } }
public override int ERR_OutputWriteFailed { get { return (int)ErrorCode.ERR_OutputWriteFailed; } }
public override int WRN_NoConfigNotOnCommandLine { get { return (int)ErrorCode.WRN_NoConfigNotOnCommandLine; } }
public override int ERR_BinaryFile { get { return (int)ErrorCode.ERR_BinaryFile; } }
public override int WRN_AnalyzerCannotBeCreated { get { return (int)ErrorCode.WRN_AnalyzerCannotBeCreated; } }
public override int WRN_NoAnalyzerInAssembly { get { return (int)ErrorCode.WRN_NoAnalyzerInAssembly; } }
public override int WRN_UnableToLoadAnalyzer { get { return (int)ErrorCode.WRN_UnableToLoadAnalyzer; } }
public override int INF_UnableToLoadSomeTypesInAnalyzer { get { return (int)ErrorCode.INF_UnableToLoadSomeTypesInAnalyzer; } }
public override int ERR_CantReadRulesetFile { get { return (int)ErrorCode.ERR_CantReadRulesetFile; } }
public override int ERR_CompileCancelled { get { return (int)ErrorCode.ERR_CompileCancelled; } }
public override int ERR_ExpectedSingleScript => (int)ErrorCode.ERR_ExpectedSingleScript;
public override int ERR_OpenResponseFile => (int)ErrorCode.ERR_OpenResponseFile;
public override int ERR_InvalidPathMap => (int)ErrorCode.ERR_InvalidPathMap;
public override int FTL_InputFileNameTooLong => (int)ErrorCode.FTL_InputFileNameTooLong;
public override int ERR_FileNotFound => (int)ErrorCode.ERR_FileNotFound;
public override int ERR_NoSourceFile => (int)ErrorCode.ERR_NoSourceFile;
public override int ERR_CantOpenFileWrite => (int)ErrorCode.ERR_CantOpenFileWrite;
public override int ERR_OutputWriteFailed => (int)ErrorCode.ERR_OutputWriteFailed;
public override int WRN_NoConfigNotOnCommandLine => (int)ErrorCode.WRN_NoConfigNotOnCommandLine;
public override int ERR_BinaryFile => (int)ErrorCode.ERR_BinaryFile;
public override int WRN_AnalyzerCannotBeCreated => (int)ErrorCode.WRN_AnalyzerCannotBeCreated;
public override int WRN_NoAnalyzerInAssembly => (int)ErrorCode.WRN_NoAnalyzerInAssembly;
public override int WRN_UnableToLoadAnalyzer => (int)ErrorCode.WRN_UnableToLoadAnalyzer;
public override int INF_UnableToLoadSomeTypesInAnalyzer => (int)ErrorCode.INF_UnableToLoadSomeTypesInAnalyzer;
public override int ERR_CantReadRulesetFile => (int)ErrorCode.ERR_CantReadRulesetFile;
public override int ERR_CompileCancelled => (int)ErrorCode.ERR_CompileCancelled;
// compilation options:
public override int ERR_BadCompilationOptionValue { get { return (int)ErrorCode.ERR_BadCompilationOptionValue; } }
public override int ERR_BadCompilationOptionValue => (int)ErrorCode.ERR_BadCompilationOptionValue;
public override int ERR_MutuallyExclusiveOptions => (int)ErrorCode.ERR_MutuallyExclusiveOptions;
// emit options:
public override int ERR_InvalidDebugInformationFormat { get { return (int)ErrorCode.ERR_InvalidDebugInformationFormat; } }
public override int ERR_InvalidOutputName { get { return (int)ErrorCode.ERR_InvalidOutputName; } }
public override int ERR_InvalidFileAlignment { get { return (int)ErrorCode.ERR_InvalidFileAlignment; } }
public override int ERR_InvalidSubsystemVersion { get { return (int)ErrorCode.ERR_InvalidSubsystemVersion; } }
public override int ERR_InvalidDebugInformationFormat => (int)ErrorCode.ERR_InvalidDebugInformationFormat;
public override int ERR_InvalidOutputName => (int)ErrorCode.ERR_InvalidOutputName;
public override int ERR_InvalidFileAlignment => (int)ErrorCode.ERR_InvalidFileAlignment;
public override int ERR_InvalidSubsystemVersion => (int)ErrorCode.ERR_InvalidSubsystemVersion;
// reference manager:
public override int ERR_MetadataFileNotAssembly { get { return (int)ErrorCode.ERR_ImportNonAssembly; } }
public override int ERR_MetadataFileNotModule { get { return (int)ErrorCode.ERR_AddModuleAssembly; } }
public override int ERR_InvalidAssemblyMetadata { get { return (int)ErrorCode.FTL_MetadataCantOpenFile; } }
public override int ERR_InvalidModuleMetadata { get { return (int)ErrorCode.FTL_MetadataCantOpenFile; } }
public override int ERR_ErrorOpeningAssemblyFile { get { return (int)ErrorCode.FTL_MetadataCantOpenFile; } }
public override int ERR_ErrorOpeningModuleFile { get { return (int)ErrorCode.FTL_MetadataCantOpenFile; } }
public override int ERR_MetadataFileNotFound { get { return (int)ErrorCode.ERR_NoMetadataFile; } }
public override int ERR_MetadataReferencesNotSupported { get { return (int)ErrorCode.ERR_MetadataReferencesNotSupported; } }
public override int ERR_LinkedNetmoduleMetadataMustProvideFullPEImage { get { return (int)ErrorCode.ERR_LinkedNetmoduleMetadataMustProvideFullPEImage; } }
public override int ERR_MetadataFileNotAssembly => (int)ErrorCode.ERR_ImportNonAssembly;
public override int ERR_MetadataFileNotModule => (int)ErrorCode.ERR_AddModuleAssembly;
public override int ERR_InvalidAssemblyMetadata => (int)ErrorCode.FTL_MetadataCantOpenFile;
public override int ERR_InvalidModuleMetadata => (int)ErrorCode.FTL_MetadataCantOpenFile;
public override int ERR_ErrorOpeningAssemblyFile => (int)ErrorCode.FTL_MetadataCantOpenFile;
public override int ERR_ErrorOpeningModuleFile => (int)ErrorCode.FTL_MetadataCantOpenFile;
public override int ERR_MetadataFileNotFound => (int)ErrorCode.ERR_NoMetadataFile;
public override int ERR_MetadataReferencesNotSupported => (int)ErrorCode.ERR_MetadataReferencesNotSupported;
public override int ERR_LinkedNetmoduleMetadataMustProvideFullPEImage => (int)ErrorCode.ERR_LinkedNetmoduleMetadataMustProvideFullPEImage;
public override void ReportDuplicateMetadataReferenceStrong(DiagnosticBag diagnostics, Location location, MetadataReference reference, AssemblyIdentity identity, MetadataReference equivalentReference, AssemblyIdentity equivalentIdentity)
{
......@@ -177,36 +177,37 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost
}
// signing:
public override int ERR_PublicKeyFileFailure { get { return (int)ErrorCode.ERR_PublicKeyFileFailure; } }
public override int ERR_PublicKeyContainerFailure { get { return (int)ErrorCode.ERR_PublicKeyContainerFailure; } }
public override int ERR_OptionMustBeAbsolutePath { get { return (int)ErrorCode.ERR_OptionMustBeAbsolutePath; } }
public override int ERR_PublicKeyFileFailure => (int)ErrorCode.ERR_PublicKeyFileFailure;
public override int ERR_PublicKeyContainerFailure => (int)ErrorCode.ERR_PublicKeyContainerFailure;
public override int ERR_OptionMustBeAbsolutePath => (int)ErrorCode.ERR_OptionMustBeAbsolutePath;
// resources:
public override int ERR_CantReadResource { get { return (int)ErrorCode.ERR_CantReadResource; } }
public override int ERR_CantOpenWin32Resource { get { return (int)ErrorCode.ERR_CantOpenWin32Res; } }
public override int ERR_CantOpenWin32Manifest { get { return (int)ErrorCode.ERR_CantOpenWin32Manifest; } }
public override int ERR_CantOpenWin32Icon { get { return (int)ErrorCode.ERR_CantOpenIcon; } }
public override int ERR_ErrorBuildingWin32Resource { get { return (int)ErrorCode.ERR_ErrorBuildingWin32Resources; } }
public override int ERR_BadWin32Resource { get { return (int)ErrorCode.ERR_BadWin32Res; } }
public override int ERR_ResourceFileNameNotUnique { get { return (int)ErrorCode.ERR_ResourceFileNameNotUnique; } }
public override int ERR_ResourceNotUnique { get { return (int)ErrorCode.ERR_ResourceNotUnique; } }
public override int ERR_ResourceInModule { get { return (int)ErrorCode.ERR_CantRefResource; } }
public override int ERR_CantReadResource => (int)ErrorCode.ERR_CantReadResource;
public override int ERR_CantOpenWin32Resource => (int)ErrorCode.ERR_CantOpenWin32Res;
public override int ERR_CantOpenWin32Manifest => (int)ErrorCode.ERR_CantOpenWin32Manifest;
public override int ERR_CantOpenWin32Icon => (int)ErrorCode.ERR_CantOpenIcon;
public override int ERR_ErrorBuildingWin32Resource => (int)ErrorCode.ERR_ErrorBuildingWin32Resources;
public override int ERR_BadWin32Resource => (int)ErrorCode.ERR_BadWin32Res;
public override int ERR_ResourceFileNameNotUnique => (int)ErrorCode.ERR_ResourceFileNameNotUnique;
public override int ERR_ResourceNotUnique => (int)ErrorCode.ERR_ResourceNotUnique;
public override int ERR_ResourceInModule => (int)ErrorCode.ERR_CantRefResource;
// pseudo-custom attributes:
public override int ERR_PermissionSetAttributeFileReadError { get { return (int)ErrorCode.ERR_PermissionSetAttributeFileReadError; } }
public override int ERR_PermissionSetAttributeFileReadError => (int)ErrorCode.ERR_PermissionSetAttributeFileReadError;
// PDB Writer:
public override int WRN_PdbUsingNameTooLong { get { return (int)ErrorCode.WRN_DebugFullNameTooLong; } }
public override int WRN_PdbLocalNameTooLong { get { return (int)ErrorCode.WRN_PdbLocalNameTooLong; } }
public override int ERR_PdbWritingFailed { get { return (int)ErrorCode.FTL_DebugEmitFailure; } }
public override int ERR_EncodinglessSyntaxTree => (int)ErrorCode.ERR_EncodinglessSyntaxTree;
public override int WRN_PdbUsingNameTooLong => (int)ErrorCode.WRN_DebugFullNameTooLong;
public override int WRN_PdbLocalNameTooLong => (int)ErrorCode.WRN_PdbLocalNameTooLong;
public override int ERR_PdbWritingFailed => (int)ErrorCode.FTL_DebugEmitFailure;
// PE Writer:
public override int ERR_MetadataNameTooLong { get { return (int)ErrorCode.ERR_MetadataNameTooLong; } }
public override int ERR_EncReferenceToAddedMember { get { return (int)ErrorCode.ERR_EncReferenceToAddedMember; } }
public override int ERR_TooManyUserStrings { get { return (int)ErrorCode.ERR_TooManyUserStrings; } }
public override int ERR_PeWritingFailure { get { return (int)ErrorCode.ERR_PeWritingFailure; } }
public override int ERR_ModuleEmitFailure { get { return (int)ErrorCode.ERR_ModuleEmitFailure; } }
public override int ERR_EncUpdateFailedMissingAttribute { get { return (int)ErrorCode.ERR_EncUpdateFailedMissingAttribute; } }
public override int ERR_MetadataNameTooLong => (int)ErrorCode.ERR_MetadataNameTooLong;
public override int ERR_EncReferenceToAddedMember => (int)ErrorCode.ERR_EncReferenceToAddedMember;
public override int ERR_TooManyUserStrings => (int)ErrorCode.ERR_TooManyUserStrings;
public override int ERR_PeWritingFailure => (int)ErrorCode.ERR_PeWritingFailure;
public override int ERR_ModuleEmitFailure => (int)ErrorCode.ERR_ModuleEmitFailure;
public override int ERR_EncUpdateFailedMissingAttribute => (int)ErrorCode.ERR_EncUpdateFailedMissingAttribute;
public override void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute)
{
......
......@@ -51,6 +51,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CodeGen\ItemTokenMap.cs" />
<Compile Include="Emit\DebugDocumentsBuilder.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="InternalUtilities\IncrementalHash.cs" />
<Compile Include="PEWriter\ExportedType.cs" />
......
......@@ -1527,6 +1527,58 @@ internal bool IsRealSigned
Predicate<ISymbol> filterOpt,
CancellationToken cancellationToken);
internal bool StartSourceChecksumCalculation(DebugDocumentsBuilder documentsBuilder, DiagnosticBag diagnostics)
{
// Check that all syntax trees are debuggable:
bool allTreesDebuggable = true;
foreach (var tree in SyntaxTrees)
{
if (!string.IsNullOrEmpty(tree.FilePath) && tree.GetText().Encoding == null)
{
diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_EncodinglessSyntaxTree, tree.GetRoot().GetLocation()));
allTreesDebuggable = false;
}
}
if (!allTreesDebuggable)
{
return false;
}
// Add debug documents for all trees with distinct paths.
foreach (var tree in SyntaxTrees)
{
if (!string.IsNullOrEmpty(tree.FilePath))
{
// compilation does not guarantee that all trees will have distinct paths.
// Do not attempt adding a document for a particular path if we already added one.
string normalizedPath = documentsBuilder.NormalizeDebugDocumentPath(tree.FilePath, basePath: null);
var existingDoc = documentsBuilder.TryGetDebugDocumentForNormalizedPath(normalizedPath);
if (existingDoc == null)
{
documentsBuilder.AddDebugDocument(new Cci.DebugSourceDocument(
normalizedPath,
DebugSourceDocumentLanguageId,
() => tree.GetChecksumAndAlgorithm()));
}
}
}
// Add debug documents for all pragmas.
// If there are clashes with already processed directives, report warnings.
// If there are clashes with debug documents that came from actual trees, ignore the pragma.
foreach (var tree in SyntaxTrees)
{
AddDebugSourceDocumentsForChecksumDirectives(documentsBuilder, tree, diagnostics);
}
return true;
}
internal abstract Guid DebugSourceDocumentLanguageId { get; }
internal abstract void AddDebugSourceDocumentsForChecksumDirectives(DebugDocumentsBuilder documentsBuilder, SyntaxTree tree, DiagnosticBag diagnostics);
/// <summary>
/// Update resources and generate XML documentation comments.
/// </summary>
......
......@@ -197,6 +197,7 @@ public DiagnosticInfo FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, Compil
public abstract int ERR_PermissionSetAttributeFileReadError { get; }
// PDB writing:
public abstract int ERR_EncodinglessSyntaxTree { get; }
public abstract int WRN_PdbUsingNameTooLong { get; }
public abstract int WRN_PdbLocalNameTooLong { get; }
public abstract int ERR_PdbWritingFailed { get; }
......
......@@ -30,14 +30,16 @@ internal abstract class CommonPEModuleBuilder
internal abstract Cci.ITypeReference EncTranslateType(ITypeSymbol type, DiagnosticBag diagnostics);
internal abstract Cci.DebugSourceDocument GetSourceDocumentFromIndex(uint index);
internal readonly DebugDocumentsBuilder DebugDocumentsBuilder;
internal readonly IEnumerable<ResourceDescription> ManifestResources;
internal IEnumerable<Cci.IWin32Resource> Win32Resources;
internal Cci.ResourceSection Win32ResourceSection;
internal Stream SourceLinkStreamOpt;
public CommonPEModuleBuilder(IEnumerable<ResourceDescription> manifestResources)
public CommonPEModuleBuilder(IEnumerable<ResourceDescription> manifestResources, Compilation compilation)
{
ManifestResources = manifestResources;
DebugDocumentsBuilder = new DebugDocumentsBuilder(compilation.Options.SourceReferenceResolver, compilation.IsCaseSensitive);
}
}
......@@ -62,7 +64,6 @@ internal abstract class PEModuleBuilder<TCompilation, TSourceModuleSymbol, TAsse
private readonly OutputKind _outputKind;
private readonly EmitOptions _emitOptions;
private readonly Cci.ModulePropertiesForSerialization _serializationProperties;
private readonly ConcurrentCache<ValueTuple<string, string>, string> _normalizedPathsCache = new ConcurrentCache<ValueTuple<string, string>, string>(16);
private readonly TokenMap<Cci.IReference> _referencesInILMap = new TokenMap<Cci.IReference>();
private readonly ItemTokenMap<string> _stringsInILMap = new ItemTokenMap<string>();
......@@ -78,14 +79,6 @@ internal abstract class PEModuleBuilder<TCompilation, TSourceModuleSymbol, TAsse
internal readonly TModuleCompilationState CompilationState;
// This is a map from the document "name" to the document.
// Document "name" is typically a file path like "C:\Abc\Def.cs". However, that is not guaranteed.
// For compatibility reasons the names are treated as case-sensitive in C# and case-insensitive in VB.
// Neither language trims the names, so they are both sensitive to the leading and trailing whitespaces.
// NOTE: We are not considering how filesystem or debuggers do the comparisons, but how native implementations did.
// Deviating from that may result in unexpected warnings or different behavior (possibly without warnings).
private readonly ConcurrentDictionary<string, Cci.DebugSourceDocument> _debugDocuments;
public abstract TEmbeddedTypesManager EmbeddedTypesManagerOpt { get; }
/// <summary>
......@@ -122,7 +115,7 @@ internal void SetMethodTestData(ConcurrentDictionary<IMethodSymbol, CompilationT
OutputKind outputKind,
EmitOptions emitOptions,
TModuleCompilationState compilationState)
: base(manifestResources)
: base(manifestResources, compilation)
{
Debug.Assert(sourceModule != null);
Debug.Assert(serializationProperties != null);
......@@ -133,10 +126,6 @@ internal void SetMethodTestData(ConcurrentDictionary<IMethodSymbol, CompilationT
_outputKind = outputKind;
_emitOptions = emitOptions;
this.CompilationState = compilationState;
_debugDocuments = new ConcurrentDictionary<string, Cci.DebugSourceDocument>(
compilation.IsCaseSensitive ?
StringComparer.Ordinal :
StringComparer.OrdinalIgnoreCase);
}
internal sealed override void CompilationFinished()
......@@ -922,7 +911,7 @@ int Cci.IModule.HintNumberOfMethodDefinitions
}
}
int Cci.IModule.DebugDocumentCount => _debugDocuments.Count;
int Cci.IModule.DebugDocumentCount => DebugDocumentsBuilder.DebugDocumentCount;
#endregion
......@@ -952,49 +941,5 @@ Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context)
}
#endregion
#region Debug Documents
internal void AddDebugDocument(Cci.DebugSourceDocument document)
{
_debugDocuments.Add(document.Location, document);
}
internal Cci.DebugSourceDocument TryGetDebugDocument(string path, string basePath)
{
return TryGetDebugDocumentForNormalizedPath(NormalizeDebugDocumentPath(path, basePath));
}
internal Cci.DebugSourceDocument TryGetDebugDocumentForNormalizedPath(string normalizedPath)
{
Cci.DebugSourceDocument document;
_debugDocuments.TryGetValue(normalizedPath, out document);
return document;
}
internal Cci.DebugSourceDocument GetOrAddDebugDocument(string path, string basePath, Func<string, Cci.DebugSourceDocument> factory)
{
return _debugDocuments.GetOrAdd(NormalizeDebugDocumentPath(path, basePath), factory);
}
internal string NormalizeDebugDocumentPath(string path, string basePath)
{
var resolver = _compilation.Options.SourceReferenceResolver;
if (resolver == null)
{
return path;
}
var key = ValueTuple.Create(path, basePath);
string normalizedPath;
if (!_normalizedPathsCache.TryGetValue(key, out normalizedPath))
{
normalizedPath = resolver.NormalizePath(path, basePath) ?? path;
_normalizedPathsCache.TryAdd(key, normalizedPath);
}
return normalizedPath;
}
#endregion
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Roslyn.Utilities;
using System;
using System.Collections.Concurrent;
namespace Microsoft.CodeAnalysis.Emit
{
internal sealed class DebugDocumentsBuilder
{
// This is a map from the document "name" to the document.
// Document "name" is typically a file path like "C:\Abc\Def.cs". However, that is not guaranteed.
// For compatibility reasons the names are treated as case-sensitive in C# and case-insensitive in VB.
// Neither language trims the names, so they are both sensitive to the leading and trailing whitespaces.
// NOTE: We are not considering how filesystem or debuggers do the comparisons, but how native implementations did.
// Deviating from that may result in unexpected warnings or different behavior (possibly without warnings).
private readonly ConcurrentDictionary<string, Cci.DebugSourceDocument> _debugDocuments;
private readonly ConcurrentCache<ValueTuple<string, string>, string> _normalizedPathsCache;
private readonly SourceReferenceResolver _resolverOpt;
public DebugDocumentsBuilder(SourceReferenceResolver resolverOpt, bool isDocumentNameCaseSensitive)
{
_resolverOpt = resolverOpt;
_debugDocuments = new ConcurrentDictionary<string, Cci.DebugSourceDocument>(
isDocumentNameCaseSensitive ?
StringComparer.Ordinal :
StringComparer.OrdinalIgnoreCase);
_normalizedPathsCache = new ConcurrentCache<ValueTuple<string, string>, string>(16);
}
internal int DebugDocumentCount => _debugDocuments.Count;
internal void AddDebugDocument(Cci.DebugSourceDocument document)
{
_debugDocuments.Add(document.Location, document);
}
internal Cci.DebugSourceDocument TryGetDebugDocument(string path, string basePath)
{
return TryGetDebugDocumentForNormalizedPath(NormalizeDebugDocumentPath(path, basePath));
}
internal Cci.DebugSourceDocument TryGetDebugDocumentForNormalizedPath(string normalizedPath)
{
Cci.DebugSourceDocument document;
_debugDocuments.TryGetValue(normalizedPath, out document);
return document;
}
internal Cci.DebugSourceDocument GetOrAddDebugDocument(string path, string basePath, Func<string, Cci.DebugSourceDocument> factory)
{
return _debugDocuments.GetOrAdd(NormalizeDebugDocumentPath(path, basePath), factory);
}
internal string NormalizeDebugDocumentPath(string path, string basePath)
{
if (_resolverOpt == null)
{
return path;
}
var key = ValueTuple.Create(path, basePath);
string normalizedPath;
if (!_normalizedPathsCache.TryGetValue(key, out normalizedPath))
{
normalizedPath = _resolverOpt.NormalizePath(path, basePath) ?? path;
_normalizedPathsCache.TryAdd(key, normalizedPath);
}
return normalizedPath;
}
}
}
......@@ -94,7 +94,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
_filterOpt = filter
If emittingPdb OrElse moduleBeingBuiltOpt?.EmitOptions.EmitDynamicAnalysisData Then
_debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
_debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.DebugDocumentsBuilder.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
End If
If compilation.Options.ConcurrentBuild Then
......
......@@ -2219,7 +2219,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
SynthesizedMetadataCompiler.ProcessSynthesizedMembers(Me, moduleBeingBuilt, cancellationToken)
Else
' start generating PDB checksums if we need to emit PDBs
If emittingPdb AndAlso Not StartSourceChecksumCalculation(moduleBeingBuilt, diagnostics) Then
If emittingPdb AndAlso Not StartSourceChecksumCalculation(moduleBeingBuilt.DebugDocumentsBuilder, diagnostics) Then
Return False
End If
......@@ -2286,43 +2286,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return FilterAndAppendAndFreeDiagnostics(diagnostics, xmlDiagnostics)
End Function
Private Function StartSourceChecksumCalculation(moduleBeingBuilt As PEModuleBuilder, diagnostics As DiagnosticBag) As Boolean
' Check that all syntax trees are debuggable
Dim allTreesDebuggable = True
For Each tree In Me.SyntaxTrees
If Not String.IsNullOrEmpty(tree.FilePath) AndAlso tree.GetText().Encoding Is Nothing Then
diagnostics.Add(ERRID.ERR_EncodinglessSyntaxTree, tree.GetRoot().GetLocation())
allTreesDebuggable = False
End If
Next
If Not allTreesDebuggable Then
Return False
End If
' Add debug documents for all trees with distinct paths.
For Each tree In Me.SyntaxTrees
If Not String.IsNullOrEmpty(tree.FilePath) Then
' compilation does not guarantee that all trees will have distinct paths.
' Do not attempt adding a document for a particular path if we already added one.
Dim normalizedPath = moduleBeingBuilt.NormalizeDebugDocumentPath(tree.FilePath, basePath:=Nothing)
Dim existingDoc = moduleBeingBuilt.TryGetDebugDocumentForNormalizedPath(normalizedPath)
If existingDoc Is Nothing Then
moduleBeingBuilt.AddDebugDocument(MakeDebugSourceDocumentForTree(normalizedPath, tree))
End If
End If
Next
' Add debug documents for all directives.
' If there are clashes with already processed directives, report warnings.
' If there are clashes with debug documents that came from actual trees, ignore the directive.
For Each tree In Me.SyntaxTrees
AddDebugSourceDocumentsForChecksumDirectives(moduleBeingBuilt, tree, diagnostics)
Next
Return True
End Function
Private Iterator Function AddedModulesResourceNames(diagnostics As DiagnosticBag) As IEnumerable(Of String)
Dim modules As ImmutableArray(Of ModuleSymbol) = SourceAssembly.Modules
......@@ -2368,8 +2331,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return If(corLibrary Is Nothing, String.Empty, corLibrary.Assembly.ManifestModule.MetadataVersion)
End Function
Private Shared Sub AddDebugSourceDocumentsForChecksumDirectives(
moduleBeingBuilt As PEModuleBuilder,
Friend Overrides Sub AddDebugSourceDocumentsForChecksumDirectives(
documentsBuilder As DebugDocumentsBuilder,
tree As SyntaxTree,
diagnosticBag As DiagnosticBag)
......@@ -2381,15 +2344,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim path = checksumDirective.ExternalSource.ValueText
Dim checkSumText = checksumDirective.Checksum.ValueText
Dim normalizedPath = moduleBeingBuilt.NormalizeDebugDocumentPath(path, basePath:=tree.FilePath)
Dim existingDoc = moduleBeingBuilt.TryGetDebugDocumentForNormalizedPath(normalizedPath)
Dim normalizedPath = documentsBuilder.NormalizeDebugDocumentPath(path, basePath:=tree.FilePath)
Dim existingDoc = documentsBuilder.TryGetDebugDocumentForNormalizedPath(normalizedPath)
If existingDoc IsNot Nothing Then
' directive matches a file path on an actual tree.
' Dev12 compiler just ignores the directive in this case which means that
' checksum of the actual tree always wins and no warning is given.
' We will continue doing the same.
If (existingDoc.IsComputedChecksum) Then
If existingDoc.IsComputedChecksum Then
Continue For
End If
......@@ -2412,7 +2375,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
MakeCheckSumBytes(checksumDirective.Checksum.ValueText),
Guid.Parse(checksumDirective.Guid.ValueText))
moduleBeingBuilt.AddDebugDocument(newDocument)
documentsBuilder.AddDebugDocument(newDocument)
End If
Next
End Sub
......@@ -2449,12 +2412,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return builder.ToImmutableAndFree()
End Function
Private Shared Function MakeDebugSourceDocumentForTree(normalizedPath As String, tree As SyntaxTree) As DebugSourceDocument
Return New DebugSourceDocument(normalizedPath, DebugSourceDocument.CorSymLanguageTypeBasic, Function() tree.GetChecksumAndAlgorithm())
End Function
Friend Overrides ReadOnly Property DebugSourceDocumentLanguageId As Guid
Get
Return DebugSourceDocument.CorSymLanguageTypeBasic
End Get
End Property
Friend Overrides Function HasCodeToEmit() As Boolean
' TODO (tomat):
For Each syntaxTree In SyntaxTrees
Dim unit = syntaxTree.GetCompilationUnitRoot()
If unit.Members.Count > 0 Then
......
......@@ -274,7 +274,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Private Sub AddSymbolLocation(result As MultiDictionary(Of Cci.DebugSourceDocument, Cci.DefinitionWithLocation), location As Location, definition As Cci.IDefinition)
Dim span As FileLinePositionSpan = location.GetLineSpan()
Dim doc As Cci.DebugSourceDocument = Me.TryGetDebugDocument(span.Path, basePath:=location.SourceTree.FilePath)
Dim doc As Cci.DebugSourceDocument = DebugDocumentsBuilder.TryGetDebugDocument(span.Path, basePath:=location.SourceTree.FilePath)
If (doc IsNot Nothing) Then
result.Add(doc,
New Cci.DefinitionWithLocation(
......
......@@ -456,6 +456,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Sub
' PDB Writer
Public Overrides ReadOnly Property ERR_EncodinglessSyntaxTree As Integer
Get
Return ERRID.ERR_EncodinglessSyntaxTree
End Get
End Property
Public Overrides ReadOnly Property WRN_PdbUsingNameTooLong As Integer
Get
Return ERRID.WRN_PdbUsingNameTooLong
......
......@@ -29,6 +29,11 @@ public override ReportDiagnostic GetDiagnosticReport(DiagnosticInfo diagnosticIn
throw new NotImplementedException();
}
public override int ERR_EncodinglessSyntaxTree
{
get { throw new NotImplementedException(); }
}
public override int ERR_InvalidPathMap
{
get { throw new NotImplementedException(); }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册