Skip to content

Commit

Permalink
Include source files w/o method bodies in the PDB documents (#39136)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanbasov committed Oct 14, 2019
1 parent ba47b2f commit fce41a7
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 48 deletions.
4 changes: 3 additions & 1 deletion src/Compilers/CSharp/Test/Emit/PDB/CheckSumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ static void Main()
<file id=""2"" name=""USED2.cs"" language=""C#"" checksumAlgorithm=""406ea660-64cf-4c82-b6f0-42d48172a799"" checksum=""AB-00-7F-1D-23-D9"" />
<file id=""3"" name=""b.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""C0-51-F0-6F-D3-ED-44-A2-11-4D-03-70-89-20-A6-05-11-62-14-BE"" />
<file id=""4"" name=""a.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""F0-C4-23-63-A5-89-B9-29-AF-94-07-85-2F-3A-40-D3-70-14-8F-9B"" />
<file id=""5"" name=""UNUSED.cs"" language=""C#"" checksumAlgorithm=""406ea660-64cf-4c82-b6f0-42d48172a799"" checksum=""AB-00-7F-1D-23-D9"" />
</files>
<methods>
<method containingType=""C"" name=""Main"">
Expand Down Expand Up @@ -286,7 +287,7 @@ void M()
</symbols>");
}

[Fact]
[ConditionalFact(typeof(WindowsOnly))]
public void NoResolver()
{
var comp = CSharpCompilation.Create(
Expand All @@ -305,6 +306,7 @@ class C { void M() { } }
<symbols>
<files>
<file id=""1"" name=""a\..\a.cs"" language=""C#"" checksumAlgorithm=""406ea660-64cf-4c82-b6f0-42d48172a799"" checksum=""AB-00-7F-1D-23-D5"" />
<file id=""2"" name=""C:\a\..\b.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""36-39-3C-83-56-97-F2-F0-60-95-A4-A0-32-C6-32-C7-B2-4B-16-92"" />
</files>
<methods>
<method containingType=""C"" name=""M"">
Expand Down
73 changes: 73 additions & 0 deletions src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10511,6 +10511,7 @@ public async void M1()
@"<symbols>
<files>
<file id=""1"" name=""C:\Async.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""DB-EB-2A-06-7B-2F-0E-0D-67-8A-00-2C-58-7A-28-06-05-6C-3D-CE"" />
<file id=""2"" name=""HIDDEN.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""8A-92-EE-2F-D6-6F-C0-69-F4-A8-54-CB-11-BE-A3-06-76-2C-9C-98"" />
</files>
<methods>
<method containingType=""C"" name=""M1"">
Expand Down Expand Up @@ -10577,6 +10578,7 @@ partial class C
<symbols>
<files>
<file id=""1"" name=""constructor.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""EA-D6-0A-16-6C-6A-BC-C1-5D-98-0F-B7-4B-78-13-93-FB-C7-C2-5A"" />
<file id=""2"" name=""initializer.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""84-32-24-D7-FE-32-63-BA-41-D5-17-A2-D5-90-23-B8-12-3C-AF-D5"" />
</files>
<methods>
<method containingType=""C"" name="".ctor"">
Expand Down Expand Up @@ -11037,5 +11039,76 @@ public void InvalidCharacterInPdbPath()
Diagnostic(ErrorCode.FTL_InvalidInputFileName).WithArguments("test\\?.pdb").WithLocation(1, 1));
}
}

[Fact]
[WorkItem(38954, "https://github.com/dotnet/roslyn/issues/38954")]
public void FilesOneWithNoMethodBody()
{
string source1 = WithWindowsLineBreaks(@"
using System;
class C
{
public static void Main()
{
Console.WriteLine();
}
}
");
string source2 = WithWindowsLineBreaks(@"
// no code
");

var tree1 = Parse(source1, "f:/build/goo.cs");
var tree2 = Parse(source2, "f:/build/nocode.cs");
var c = CreateCompilation(new[] { tree1, tree2 }, options: TestOptions.DebugDll);

c.VerifyPdb(@"
<symbols>
<files>
<file id=""1"" name=""f:/build/goo.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""5D-7D-CF-1B-79-12-0E-0A-80-13-E0-98-7E-5C-AA-3B-63-D8-7E-4F"" />
<file id=""2"" name=""f:/build/nocode.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""8B-1D-3F-75-E0-A8-8F-90-B2-D3-52-CF-71-9B-17-29-3C-70-7A-42"" />
</files>
<methods>
<method containingType=""C"" name=""Main"">
<customDebugInfo>
<using>
<namespace usingCount=""1"" />
</using>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""7"" startColumn=""5"" endLine=""7"" endColumn=""6"" document=""1"" />
<entry offset=""0x1"" startLine=""8"" startColumn=""9"" endLine=""8"" endColumn=""29"" document=""1"" />
<entry offset=""0x7"" startLine=""9"" startColumn=""5"" endLine=""9"" endColumn=""6"" document=""1"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x8"">
<namespace name=""System"" />
</scope>
</method>
</methods>
</symbols>
");
}

[Fact]
[WorkItem(38954, "https://github.com/dotnet/roslyn/issues/38954")]
public void SingleFileWithNoMethodBody()
{
string source = WithWindowsLineBreaks(@"
// no code
");

var tree = Parse(source, "f:/build/nocode.cs");
var c = CreateCompilation(new[] { tree }, options: TestOptions.DebugDll);

c.VerifyPdb(@"
<symbols>
<files>
<file id=""1"" name=""f:/build/nocode.cs"" language=""C#"" checksumAlgorithm=""SHA1"" checksum=""8B-1D-3F-75-E0-A8-8F-90-B2-D3-52-CF-71-9B-17-29-3C-70-7A-42"" />
</files>
<methods />
</symbols>
");
}
}
}
5 changes: 0 additions & 5 deletions src/Compilers/Core/Portable/Compilation/Compilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2068,8 +2068,6 @@ internal bool CreateDebugDocuments(DebugDocumentsBuilder documentsBuilder, IEnum
// takes priority over the syntax tree pass, which will not embed.
if (!embeddedTexts.IsEmpty())
{
var embeddedDocuments = ArrayBuilder<Cci.DebugSourceDocument>.GetInstance();

foreach (var text in embeddedTexts)
{
Debug.Assert(!string.IsNullOrEmpty(text.FilePath));
Expand All @@ -2083,11 +2081,8 @@ internal bool CreateDebugDocuments(DebugDocumentsBuilder documentsBuilder, IEnum
() => text.GetDebugSourceInfo());

documentsBuilder.AddDebugDocument(document);
embeddedDocuments.Add(document);
}
}

documentsBuilder.EmbeddedDocuments = embeddedDocuments.ToImmutableAndFree();
}

// Add debug documents for all trees with distinct paths.
Expand Down
14 changes: 4 additions & 10 deletions src/Compilers/Core/Portable/Emit/DebugDocumentsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
using Roslyn.Utilities;
using System;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Collections.Generic;

namespace Microsoft.CodeAnalysis.Emit
{
Expand All @@ -19,7 +18,6 @@ internal sealed class DebugDocumentsBuilder
private readonly ConcurrentDictionary<string, Cci.DebugSourceDocument> _debugDocuments;
private readonly ConcurrentCache<(string, string), string> _normalizedPathsCache;
private readonly SourceReferenceResolver _resolverOpt;
private ImmutableArray<Cci.DebugSourceDocument> _embeddedDocuments;

public DebugDocumentsBuilder(SourceReferenceResolver resolverOpt, bool isDocumentNameCaseSensitive)
{
Expand All @@ -31,13 +29,6 @@ public DebugDocumentsBuilder(SourceReferenceResolver resolverOpt, bool isDocumen
StringComparer.OrdinalIgnoreCase);

_normalizedPathsCache = new ConcurrentCache<(string, string), string>(16);
_embeddedDocuments = ImmutableArray<Cci.DebugSourceDocument>.Empty;
}

internal ImmutableArray<Cci.DebugSourceDocument> EmbeddedDocuments
{
get { return _embeddedDocuments; }
set { Debug.Assert(value != null); _embeddedDocuments = value; }
}

internal int DebugDocumentCount => _debugDocuments.Count;
Expand All @@ -47,6 +38,9 @@ internal void AddDebugDocument(Cci.DebugSourceDocument document)
_debugDocuments.Add(document.Location, document);
}

internal IReadOnlyDictionary<string, Cci.DebugSourceDocument> DebugDocuments
=> _debugDocuments;

internal Cci.DebugSourceDocument TryGetDebugDocument(string path, string basePath)
{
return TryGetDebugDocumentForNormalizedPath(NormalizeDebugDocumentPath(path, basePath));
Expand Down
21 changes: 13 additions & 8 deletions src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
Expand Down Expand Up @@ -572,6 +571,11 @@ private int GetDocumentIndex(DebugSourceDocument document)
return documentIndex;
}

return AddDocumentIndex(document);
}

private int AddDocumentIndex(DebugSourceDocument document)
{
Guid algorithmId;
ReadOnlySpan<byte> checksum;
ReadOnlySpan<byte> embeddedSource;
Expand All @@ -597,7 +601,7 @@ private int GetDocumentIndex(DebugSourceDocument document)
embeddedSource = null;
}

documentIndex = _symWriter.DefineDocument(
int documentIndex = _symWriter.DefineDocument(
document.Location,
document.Language,
document.LanguageVendor,
Expand Down Expand Up @@ -742,18 +746,19 @@ public void EmbedSourceLink(Stream stream)
}

/// <summary>
/// Write document entries for any embedded text document that does not yet have an entry.
/// Write document entries for all debug documents that do not yet have an entry.
/// </summary>
/// <remarks>
/// This is done after serializing method debug info to ensure that we embed all requested
/// text even if there are no corresponding sequence points.
/// </remarks>
public void WriteRemainingEmbeddedDocuments(IEnumerable<DebugSourceDocument> embeddedDocuments)
public void WriteRemainingDebugDocuments(IReadOnlyDictionary<string, DebugSourceDocument> documents)
{
foreach (var document in embeddedDocuments)
foreach (var kvp in documents
.Where(kvp => !_documentIndex.ContainsKey(kvp.Value))
.OrderBy(kvp => kvp.Key))
{
Debug.Assert(!document.GetSourceInfo().EmbeddedTextBlob.IsDefault);
GetDocumentIndex(document);
AddDocumentIndex(kvp.Value);
}
}
}
Expand Down
50 changes: 29 additions & 21 deletions src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -727,44 +727,52 @@ private void SerializeDeltaLinesAndColumns(BlobBuilder writer, SequencePoint seq

private DocumentHandle GetOrAddDocument(DebugSourceDocument document, Dictionary<DebugSourceDocument, DocumentHandle> index)
{
DocumentHandle documentHandle;
if (!index.TryGetValue(document, out documentHandle))
if (index.TryGetValue(document, out var documentHandle))
{
DebugSourceInfo info = document.GetSourceInfo();
return documentHandle;
}

documentHandle = _debugMetadataOpt.AddDocument(
name: _debugMetadataOpt.GetOrAddDocumentName(document.Location),
hashAlgorithm: info.Checksum.IsDefault ? default(GuidHandle) : _debugMetadataOpt.GetOrAddGuid(info.ChecksumAlgorithmId),
hash: info.Checksum.IsDefault ? default(BlobHandle) : _debugMetadataOpt.GetOrAddBlob(info.Checksum),
language: _debugMetadataOpt.GetOrAddGuid(document.Language));
return AddDocument(document, index);
}

index.Add(document, documentHandle);
private DocumentHandle AddDocument(DebugSourceDocument document, Dictionary<DebugSourceDocument, DocumentHandle> index)
{
DocumentHandle documentHandle;
DebugSourceInfo info = document.GetSourceInfo();

if (info.EmbeddedTextBlob != null)
{
_debugMetadataOpt.AddCustomDebugInformation(
parent: documentHandle,
kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.EmbeddedSource),
value: _debugMetadataOpt.GetOrAddBlob(info.EmbeddedTextBlob));
}
documentHandle = _debugMetadataOpt.AddDocument(
name: _debugMetadataOpt.GetOrAddDocumentName(document.Location),
hashAlgorithm: info.Checksum.IsDefault ? default(GuidHandle) : _debugMetadataOpt.GetOrAddGuid(info.ChecksumAlgorithmId),
hash: info.Checksum.IsDefault ? default(BlobHandle) : _debugMetadataOpt.GetOrAddBlob(info.Checksum),
language: _debugMetadataOpt.GetOrAddGuid(document.Language));

index.Add(document, documentHandle);

if (info.EmbeddedTextBlob != null)
{
_debugMetadataOpt.AddCustomDebugInformation(
parent: documentHandle,
kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.EmbeddedSource),
value: _debugMetadataOpt.GetOrAddBlob(info.EmbeddedTextBlob));
}

return documentHandle;
}

/// <summary>
/// Add document entries for any embedded text document that does not yet have an entry.
/// Add document entries for all debug documents that do not yet have an entry.
/// </summary>
/// <remarks>
/// This is done after serializing method debug info to ensure that we embed all requested
/// text even if there are no corresponding sequence points.
/// </remarks>
public void AddRemainingEmbeddedDocuments(IEnumerable<DebugSourceDocument> documents)
public void AddRemainingDebugDocuments(IReadOnlyDictionary<string, DebugSourceDocument> documents)
{
foreach (var document in documents)
foreach (var kvp in documents
.Where(kvp => !_documentIndex.ContainsKey(kvp.Value))
.OrderBy(kvp => kvp.Key))
{
Debug.Assert(document.GetSourceInfo().EmbeddedTextBlob != null);
GetOrAddDocument(document, _documentIndex);
AddDocument(kvp.Value, _documentIndex);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/Core/Portable/PEWriter/PeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ internal static bool WritePeToStream(
#endif
}

nativePdbWriterOpt.WriteRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments);
nativePdbWriterOpt.WriteRemainingDebugDocuments(mdWriter.Module.DebugDocumentsBuilder.DebugDocuments);
}

Stream peStream = getPeStream();
Expand Down Expand Up @@ -151,7 +151,7 @@ internal static bool WritePeToStream(
BlobBuilder portablePdbToEmbed = null;
if (mdWriter.EmitPortableDebugMetadata)
{
mdWriter.AddRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments);
mdWriter.AddRemainingDebugDocuments(mdWriter.Module.DebugDocumentsBuilder.DebugDocuments);

// The algorithm must be specified for deterministic builds (checked earlier).
Debug.Assert(!isDeterministic || context.Module.PdbChecksumAlgorithm.Name != null);
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/VisualBasic/Test/Emit/PDB/ChecksumTests.vb
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ End Class
<files>
<file id="1" name="b:\base\line.vb" language="VB"/>
<file id="2" name="q:\absolute\line.vb" language="VB"/>
<file id="3" name="b:\base\b.vb" language="VB" checksumAlgorithm="SHA1" checksum="F9-90-00-9D-9E-45-97-F2-3D-67-1C-D8-47-A8-9B-DA-4A-91-AA-7F"/>
</files>
<methods>
<method containingType="C" name="M">
Expand Down Expand Up @@ -312,6 +313,7 @@ End Class
<file id="3" name="b:\base\c.vb" language="VB" checksumAlgorithm="406ea660-64cf-4c82-b6f0-42d48172a79a" checksum="AB-00-7F-1D-23-DC"/>
<file id="4" name="b:\base\d.vb" language="VB" checksumAlgorithm="406ea660-64cf-4c82-b6f0-42d48172a79a" checksum="AB-00-7F-1D-23-DD"/>
<file id="5" name="b:\base\e.vb" language="VB" checksumAlgorithm="406ea660-64cf-4c82-b6f0-42d48172a79a" checksum="AB-00-7F-1D-23-DE"/>
<file id="6" name="b:\base\file.vb" language="VB" checksumAlgorithm="SHA1" checksum="C2-46-C6-34-F6-20-D3-FE-28-B9-D8-62-0F-A9-FB-2F-89-E7-48-23"/>
</files>
<methods>
<method containingType="C" name="M">
Expand Down Expand Up @@ -363,6 +365,7 @@ End Class
<file id="1" name="a.vb" language="VB" checksumAlgorithm="406ea660-64cf-4c82-b6f0-42d48172a79a" checksum="AB-00-7F-1D-23-DA"/>
<file id="2" name="./a.vb" language="VB"/>
<file id="3" name="b.vb" language="VB"/>
<file id="4" name="file.vb" language="VB" checksumAlgorithm="SHA1" checksum="23-C1-6B-94-B0-D4-06-26-C8-D2-82-21-63-07-53-11-4D-5A-02-BC"/>
</files>
<methods>
<method containingType="C" name="M">
Expand Down
Loading

0 comments on commit fce41a7

Please sign in to comment.