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.74k stars 3.99k forks source link

Source Generators: Allow loading referenced assemblies #45060

Open AndriySvyryd opened 4 years ago

AndriySvyryd commented 4 years ago

Background

I'm investigating whether Source Generators can be used to make Entity Framework Core AOT-compatible. Currently EF needs to use reflection to create its model and then compiles lambda expressions to manipulate user-provided types efficiently. We could do this at design time and generate a model that would be compiled along with the user's code instead.

Problem

Users configure the model by overriding the OnModelCreating method on DbContext. To be able to generate a compilable model we first need to run that code, looking at the source code is not enough.

Currently there is no way to get the full file paths of the assemblies referenced from the code being analyzed to be able to load them and run the configuration code.

Proposal

To limit the impact and prevent a leaky abstraction exposing the assembly file paths can be avoided. We only need to be able to run the source generator in an AppDomain that has all the referenced assemblies loaded. So the details can be hidden away behind a method or by implementing an interface.

void ExecuteWithReferencedAssemblies(this SourceGeneratorContext context, Action<SourceGeneratorContext> executeAction);
eostarman commented 3 years ago

When I took a look at the reason it was slow on the first query I found a great deal of the time was in creating the relationships. Maybe there could be a way to create these in a less dynamic fashion (my proof-of-concept changes - using some dictionaries and lazy properties and the like) dropped the time by about 60% or so)? So, rather than a full AOT compilation solution, maybe a slightly more static way of creating the needed relationships. We can't actually use it in our company until the initial-usage time is reduced substantially even though it brings an incredible amount of functionality otherwise.

roji commented 3 years ago

@eostarman this issue is about adding a capability to the Roslyn Source Generator feature, not about Entity Framework Core. Can you please open an issue on the EF Core repo (https://github.com/dotnet/efcore/issues), or add a comment to https://github.com/dotnet/efcore/issues/1906?

fiseni commented 3 years ago

I have the same scenario. I have to run fluent-like configurations and based on that produce some code.

The full file paths of the referenced assemblies can be found under GeneratorExecutionContext.Compilation.References.Display. For now, this is how I do it. It's a terrible hack, but I have no better way of doing it.

ViRuSTriNiTy commented 2 years ago

@fiseni Nice approach. I can confirm that this workaround breaks VS as I did give this a try and it breaks everything from VS to the compiler process running in the background as you have mentioned in the comments of your source. I even tried to use reflection only context as this would be sufficient for my case but to no avail, things get even messier there.

fiseni commented 2 years ago

Oh, that was just an experimental project. That approach shouldn't be used in any case. Refer to this comment here.