dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.96k stars 4.02k forks source link

INamedTypeSymbol.Constructors - Method sometimes fails to return information for private constructors #72473

Closed WebbertSolutions closed 6 months ago

WebbertSolutions commented 6 months ago

I've included 2 issues which are both related to INamedTypeSymbol.Constructors not returning information about a class.
The class in question has a private constructor with a public static Create() method to ensure that the private constructor doesn't get lost.

The issues are:


Version Used: Microsoft.CodeAnalysis.CSharp" Version="4.7.0

Issue with generating code involving Private Constructors

Steps to Reproduce: https://github.com/WebbertSolutions/SourceGenerators

  1. Set startup to GenerateObjectMother
  2. Set break point on line 74: GenerateObjectMother\BaseClass\BaseGenerator.cs
  3. Press F5
  4. Examine result of classSymbol.Constructors

Depending on the computer, you may or may not get constructors returned for private constructors. The public seems to work fine. Pictures are added to show when it is failing.

image image

Issue when running unit tests involving Private Constructors

When unit tests are run, the generated code does not match what the debugger is running.

Steps to Reproduce: https://github.com/WebbertSolutions/SourceGenerators

  1. Debug Test - PrivateWithBuilderTest
  2. Using the debugger step into code until you get to the actual Build() method
  3. With the debugger still running, go to the source code for PrivateWithBuilder class
  4. Right click and select Go To Implementation and select the generated version
  5. The implementation has valid code but stepping into the debugger has something completely different.

Pictures are added to show the difference between the debugger code running and the go to implementation generated code.

This is the debugger

image


This is the Go To Implementation code

image

jaredpar commented 6 months ago

Depending on the computer, you may or may not get constructors returned for private constructors.

Do these private members exist in source or metadata?

WebbertSolutions commented 6 months ago

Source. They exist before the generator runs.
The generator gets the information about the constructors and then generates code given what type of parameters and scope it has. The second picture above shows what it looks like.

333fred commented 6 months ago

Issue with generating code involving Private Constructors

Rather than sharing screenshots, it would be much more helpful if you could just share a dump of the process. You can save a dump from the Debug menu when you're paused on a breakpoint. This will be very helpful as I've been unable to reproduce your failure condition locally.

Issue when running unit tests involving Private Constructors

I'm entirely unsure what you're saying with this part of the issue; why would the debugger have anything to do with the live IDE state? Are you simply running into the fact that VS cannot pick up changes to source generator project references without a restart (and restart of the build servers)? Either way, let's please keep separate issues in separate issues, rather than a single issue, so that we can properly track things.

WebbertSolutions commented 6 months ago

Ok. Let's deal with the first: Issue with generating code involving Private Constructors

Here is the dump of the generation issue as requested, however the dump exceeded upload max of 25M.
Had to store on ondrive here: https://1drv.ms/f/c/1e01d4a72dbe2024/Emp2GT-VlG5AmpVE1xlGB8YBB3eNb6wSWh0ySpJRsfEMOQ?e=bt01uN

333fred commented 6 months ago

Alright, so your source generator is indeed getting PrivateWith from a metadata reference, not from source. Specifically, it's coming from this assembly: D:\Coding\GitHub\SourceGenerators\Generators\GenerateObjectMother\GenerateObjectMotherTest.Models\obj\Debug\net6.0\ref\GenerateObjectMotherTest.Models.dll. private constructors are not put into the ref assemblies. It seems likely that your source generator will need to handle this case in general.

@chsienki, I would have somewhat expected IsRoslynComponent to pass project references as project references, but it looks like that's not the case? Is that expected behavior?

chsienki commented 6 months ago

@333fred IsRoslynComponent just takes the command line of whatever would be passed to CSC and runs it as the debug target. It doesn't consider project/package references as they dont exist at that level, everything is just a regular reference to an assembly on disk.

333fred commented 6 months ago

Thanks Chris. Given that, I would call the behavior you're seeing here expected @WebbertSolutions.

WebbertSolutions commented 6 months ago

Ok, I think I understand but for clarity...

1) Because I'm debugging, the process running is the generator. As such, it is then referencing back to the project/DLL where the class code exists, which is being done through metadata. Private constructors are not available in the metadata and that is why INamedTypeSymbol.Constructors is returning an empty list.

Is that correct?

2) Under normal circumstances where I'm adding the attribute to a class and the generator runs automatically, then I'm in the context of the source and therefore I do have access to the constructor information through INamedTypeSymbol.Constructors.

Is that correct?

333fred commented 6 months ago

Not quite correct, no. IsRoslynComponent is mimicking the exact semantics you will see with dotnet build. The only time you will see project references as anything other than dll references is in the IDE.

WebbertSolutions commented 6 months ago

hmm.... Not sure of the difference in how it runs then. Either way, I think I understand enough and have an idea how to work around the first issue and will see what I can do on the second.

Thanks for your assistance.

I should also mention, while frustrating at times, I've really enjoyed working with the Source Generator. It has allowed me to do somethings much easier than other ways in the past. Looking forward to seeing what other problems I can solve.

333fred commented 6 months ago

Thanks for the feedback! Feel free to come talk to us on discord as well: https://discord.gg/csharp, a number of us hang out in the roslyn channel and talk to a lot of people about source generators.