New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Order PDB document table to match compiler arguments #50615
Conversation
@@ -847,6 +847,7 @@ private void EmbedCompilationOptions(CommonPEModuleBuilder module) | |||
WriteValue(CompilationOptionNames.CompilerVersion, compilerVersion); | |||
|
|||
WriteValue(CompilationOptionNames.Language, module.CommonCompilation.Options.Language); | |||
WriteValue(CompilationOptionNames.SourceFileCount, module.CommonCompilation.SyntaxTrees.Count().ToString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Count() [](start = 100, length = 7)
Minor thing and not related to your change but just noticed that SyntaxTrees is IEnumerable but both C# and VB represent it as ImmutableArray. So we are boxing it unnecessarily. Can't change public API but could change and use CommonSyntaxTrees.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a good idea. Let's spin it off into its own issue.
Does this PR need to target 16.9? edit: It looks like master currently targets 16.9-preview4, so we can keep this base branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could probably use an update to the name of the tests too fwiw. |
Adding the "version" field was very straightforward so I decided to just do it in this PR. |
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double blink line
// Ensure document table lists files in command line order | ||
var documentsBuilder = Module.DebugDocumentsBuilder; | ||
var documents = documentsBuilder.DebugDocuments; | ||
foreach (var tree in Module.CommonCompilation.SyntaxTrees) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point in the code does this include SyntaxTree
that come from source generators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great question. I think the answer is yes because this is emit-phase work which we are only expected to do for the "final" compilation which includes source generator outputs.
It feels like it would be appropriate to have a test here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely need a test - it should also cover that all source generated files are embedded in the PDB.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not yet certain how to formulate this test. See this simple source generators test:
roslyn/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs
Lines 113 to 140 in a163778
[Fact] | |
public void Single_File_Is_Added() | |
{ | |
var source = @" | |
class C { } | |
"; | |
var generatorSource = @" | |
class GeneratedClass { } | |
"; | |
var parseOptions = TestOptions.Regular; | |
Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); | |
compilation.VerifyDiagnostics(); | |
Assert.Single(compilation.SyntaxTrees); | |
SingleFileTestGenerator testGenerator = new SingleFileTestGenerator(generatorSource); | |
GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions); | |
driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _); | |
Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); | |
Assert.NotEqual(compilation, outputCompilation); | |
var generatedClass = outputCompilation.GlobalNamespace.GetTypeMembers("GeneratedClass").Single(); | |
Assert.True(generatedClass.Locations.Single().IsInSource); | |
} |
If I try to imitate the structure of the source generator tests, I will create an original compilation, feed it into the generator driver, then get a final compilation out and try to emit with it. But it seems obvious that the syntax trees for that compilation will include the generated sources, so the test won't really be demonstrating anything useful.
It feels like if we had a higher level test that straight up ran through CommonCompiler.Run
we might be able to demonstrate something meaningful, but I'm not sure it's good to spend the time to come up with the automated test just yet.
I also imagine that in the near future we might write a test harness that allows us to just take any Compilation
and attempt to "round-trip" it, by emitting its dll+pdb, gathering the information to recreate it, and then doing so on the spot. Test failure messages could be given by comparing output of ildasm
or mdv
or something like that on the before and after binaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test could verify that the PDB contains the sources of the generated files. That is, the compilation that comes out of the driver is setup correctly.
@@ -835,6 +835,9 @@ private void EmbedSourceLink(Stream stream) | |||
value: _debugMetadataOpt.GetOrAddBlob(bytes)); | |||
} | |||
|
|||
///<summary>The version of the compilation options schema to be written to the PDB.</summary> | |||
public const int Version = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public const int Version = 1; | |
public const int CompilationOptionsSchemaVersion = 1; |
<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"" /> | ||
<file id=""1"" 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"" /> | ||
<file id=""2"" name=""a\..\a.cs"" language=""C#"" checksumAlgorithm=""406ea660-64cf-4c82-b6f0-42d48172a799"" checksum=""AB-00-7F-1D-23-D5"" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there no checksum algorithm here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the checksum algorithm is present on this line. Am I misunderstanding something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugg, the double quoting fooled me.
@dotnet/roslyn-compiler can we get one more review here? Part of the fix here is for 16.9 important bugs |
@@ -28,5 +29,6 @@ internal static class CompilationOptionNames | |||
public const string Nullable = "nullable"; | |||
public const string Define = "define"; | |||
public const string Strict = "strict"; | |||
public const string SourceFileCount = "source-file-count"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of this property is to let us order the "real" documents at the beginning of the table, then allow documents added for #line
directives to come at positions after this count so that we can skip them when rebuilding.
VerifyCompilationOptions(compilationOptions, originalCompilation, emitOptions, compilationOptionsReader, langVersion); | ||
if (debugDocumentsCount is not null) | ||
{ | ||
Assert.Equal(debugDocumentsCount, pdbReader.Documents.Count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert.Equal(debugDocumentsCount, pdbReader.Documents.Count); [](start = 24, length = 61)
Should we assert unconditionally? Assert.Equal(debugDocumentsCount ?? syntaxTrees.Length, pdbReader.Documents.Count);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could if we ensure every test that doesn't pass 'debugDocumentsCount' passes a unique path of each of its documents, which isn't hard to do.
foreach (var tree in Module.CommonCompilation.SyntaxTrees) | ||
{ | ||
string normalizedPath = documentsBuilder.NormalizeDebugDocumentPath(tree.FilePath, basePath: null); | ||
if (documents.TryGetValue(normalizedPath, out var doc) && !_documentIndex.ContainsKey(doc)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (documents.TryGetDebugDocument(tree.FilePath, basePath: null) is { } doc && ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
PTAL @tmat @jaredpar
@ryzngard are there tests for the compilation options embedded in the PDBs? or would it be practical to add any?
Have filed #50611 to follow up on fixing the document order in native PDBs.