diff --git a/src/Compilers/CSharp/Test/Emit/PDB/CheckSumTest.cs b/src/Compilers/CSharp/Test/Emit/PDB/CheckSumTest.cs index b6fc2670df011..7afd473af8a6e 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/CheckSumTest.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/CheckSumTest.cs @@ -232,6 +232,7 @@ static void Main() + @@ -286,7 +287,7 @@ void M() "); } - [Fact] + [ConditionalFact(typeof(WindowsOnly))] public void NoResolver() { var comp = CSharpCompilation.Create( @@ -305,6 +306,7 @@ class C { void M() { } } + diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs index 1c9e77910f56c..057305e027ace 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBTests.cs @@ -10511,6 +10511,7 @@ public async void M1() @" + @@ -10577,6 +10578,7 @@ partial class C + @@ -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(@" + + + + + + + + + + + + + + + + + + + + + + + +"); + } + + [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(@" + + + + + + +"); + } } } diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 6e49054c93979..04e878455375d 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -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.GetInstance(); - foreach (var text in embeddedTexts) { Debug.Assert(!string.IsNullOrEmpty(text.FilePath)); @@ -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. diff --git a/src/Compilers/Core/Portable/Emit/DebugDocumentsBuilder.cs b/src/Compilers/Core/Portable/Emit/DebugDocumentsBuilder.cs index 96d42c1181cde..70b5bee1bc1f9 100644 --- a/src/Compilers/Core/Portable/Emit/DebugDocumentsBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/DebugDocumentsBuilder.cs @@ -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 { @@ -19,7 +18,6 @@ internal sealed class DebugDocumentsBuilder private readonly ConcurrentDictionary _debugDocuments; private readonly ConcurrentCache<(string, string), string> _normalizedPathsCache; private readonly SourceReferenceResolver _resolverOpt; - private ImmutableArray _embeddedDocuments; public DebugDocumentsBuilder(SourceReferenceResolver resolverOpt, bool isDocumentNameCaseSensitive) { @@ -31,13 +29,6 @@ public DebugDocumentsBuilder(SourceReferenceResolver resolverOpt, bool isDocumen StringComparer.OrdinalIgnoreCase); _normalizedPathsCache = new ConcurrentCache<(string, string), string>(16); - _embeddedDocuments = ImmutableArray.Empty; - } - - internal ImmutableArray EmbeddedDocuments - { - get { return _embeddedDocuments; } - set { Debug.Assert(value != null); _embeddedDocuments = value; } } internal int DebugDocumentCount => _debugDocuments.Count; @@ -47,6 +38,9 @@ internal void AddDebugDocument(Cci.DebugSourceDocument document) _debugDocuments.Add(document.Location, document); } + internal IReadOnlyDictionary DebugDocuments + => _debugDocuments; + internal Cci.DebugSourceDocument TryGetDebugDocument(string path, string basePath) { return TryGetDebugDocumentForNormalizedPath(NormalizeDebugDocumentPath(path, basePath)); diff --git a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs index abd0a16ff0623..b316c2e506fa2 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs @@ -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; @@ -572,6 +571,11 @@ private int GetDocumentIndex(DebugSourceDocument document) return documentIndex; } + return AddDocumentIndex(document); + } + + private int AddDocumentIndex(DebugSourceDocument document) + { Guid algorithmId; ReadOnlySpan checksum; ReadOnlySpan embeddedSource; @@ -597,7 +601,7 @@ private int GetDocumentIndex(DebugSourceDocument document) embeddedSource = null; } - documentIndex = _symWriter.DefineDocument( + int documentIndex = _symWriter.DefineDocument( document.Location, document.Language, document.LanguageVendor, @@ -742,18 +746,19 @@ public void EmbedSourceLink(Stream stream) } /// - /// 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. /// /// /// This is done after serializing method debug info to ensure that we embed all requested /// text even if there are no corresponding sequence points. /// - public void WriteRemainingEmbeddedDocuments(IEnumerable embeddedDocuments) + public void WriteRemainingDebugDocuments(IReadOnlyDictionary 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); } } } diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs index c24f59a87e41e..bb52611ff267b 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs @@ -727,44 +727,52 @@ private void SerializeDeltaLinesAndColumns(BlobBuilder writer, SequencePoint seq private DocumentHandle GetOrAddDocument(DebugSourceDocument document, Dictionary 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 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; } /// - /// 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. /// /// /// This is done after serializing method debug info to ensure that we embed all requested /// text even if there are no corresponding sequence points. /// - public void AddRemainingEmbeddedDocuments(IEnumerable documents) + public void AddRemainingDebugDocuments(IReadOnlyDictionary 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); } } diff --git a/src/Compilers/Core/Portable/PEWriter/PeWriter.cs b/src/Compilers/Core/Portable/PEWriter/PeWriter.cs index 225bb1439835d..7d47c15c803f0 100644 --- a/src/Compilers/Core/Portable/PEWriter/PeWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/PeWriter.cs @@ -103,7 +103,7 @@ internal static bool WritePeToStream( #endif } - nativePdbWriterOpt.WriteRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments); + nativePdbWriterOpt.WriteRemainingDebugDocuments(mdWriter.Module.DebugDocumentsBuilder.DebugDocuments); } Stream peStream = getPeStream(); @@ -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); diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/ChecksumTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/ChecksumTests.vb index aae0339291564..6ad4992c88f1a 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/ChecksumTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/ChecksumTests.vb @@ -248,6 +248,7 @@ End Class + @@ -312,6 +313,7 @@ End Class + @@ -363,6 +365,7 @@ End Class + diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBExternalSourceDirectiveTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBExternalSourceDirectiveTests.vb index 21dfb7a05ff10..3b42eea4ddf97 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBExternalSourceDirectiveTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBExternalSourceDirectiveTests.vb @@ -46,6 +46,7 @@ End Class + @@ -120,6 +121,7 @@ End Class + @@ -359,6 +361,9 @@ End Class ' Care about the fact that there are no sequence points or referenced files compilation.VerifyPdb( + + + @@ -418,6 +423,9 @@ End Class ' Care about the fact that no files are referenced compilation.VerifyPdb( + + + @@ -503,6 +511,9 @@ End Class + + + @@ -704,6 +715,7 @@ End Module + @@ -757,6 +769,7 @@ End Class + diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb index 93cc3be4d0658..63cbb709ed30e 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb @@ -4614,5 +4614,70 @@ End Class" result.Diagnostics.Verify(Diagnostic(ERRID.FTL_InvalidInputFileName).WithArguments("test\\?.pdb").WithLocation(1, 1)) End Using End Sub + + + + Public Sub FilesOneWithNoMethodBody() + Dim source1 = +"Imports System + +Class C + Public Shared Sub Main() + Console.WriteLine() + End Sub +End Class +" + Dim source2 = +" +' no code +" + + Dim tree1 = Parse(source1, "f:/build/goo.vb") + Dim tree2 = Parse(source2, "f:/build/nocode.vb") + Dim c = CreateCompilation({tree1, tree2}, options:=TestOptions.DebugDll) + + c.VerifyPdb(" + + + + + + + + + + + + + + + + + + + +") + End Sub + + + + Public Sub SingleFileWithNoMethodBody() + Dim source = +" +' no code +" + + Dim tree = Parse(source, "f:/build/nocode.vb") + Dim c = CreateCompilation({tree}, options:=TestOptions.DebugDll) + + c.VerifyPdb(" + + + + + + +") + End Sub End Class End Namespace diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index c4220f77c9179..e0c2984de4af1 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -972,7 +972,7 @@ public async Task BreakMode_RudeEdits_DocumentOutOfSync() }, _telemetryLog); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/39271")] public async Task BreakMode_RudeEdits_DocumentWithoutSequencePoints() { var source1 = "abstract class C { public abstract void M(); }";