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
19.04k stars 4.03k forks source link

Ability to know in Source Generators whether called from Build or from VS intellisense (design-time) #57384

Open HughBuxton opened 3 years ago

HughBuxton commented 3 years ago

Hopefully in right place as couldn't see specific space for Source Generators.

It would improve source generators to be able to determine whether it is being called from a Build or Intellisense in both The Initialize and the Execute parts of ISourceGenerator.

Describe your suggestion here. We have written some quite sophisticated Source Generators (in general very pleased with them) which do a large number of things inevitably can slow down the IDE experience when gone through even when streamlined. It would be useful to choose parts of it to run only during a Build where the small slow down would hardy be noticed on a build, but not run certain parts when called every time the Intellisense is activated as it slows down the Intellisense experience and some of the code we generate like typescript would not benefit the intellisense anyway.

I thought at first there was a way but every method I have tried so far has not worked at worst case scenario even if you when you added the source generator to the project could designate a whole source generator to be for BUILD only not IDE then the parts could be split into multiple generators. But the best would for you to be able to perhaps read in from a new property in GeneratorInitializationContext and GeneratorExecutionContext whether it was a IDE UI base call.

jinujoseph commented 3 years ago

cc @jasonmalinowski

jasonmalinowski commented 3 years ago

@HughBuxton Can you clarify what your generator scenario is here? We also have some new incremental APIs we're bringing online (and are still in the process of writing documentation for) which can help with performance issues in general.

We did also add one flag to our incremental APIs for giving a hint here to avoid running certain parts of the generator in certain cases; I'm not sure we finished that work though. @chsienki where did that end up?

Sergio0694 commented 3 years ago

Seems related to (possibly the same as) https://github.com/dotnet/roslyn/issues/51497? 🙂

HughBuxton commented 3 years ago

Thanks Sergio, yes that issue does look very similar I agree. @jasonmalinowski. We are using source generators to make a large number of things from dto's, controllers, helper libraries, Unit tests and also some typescript we are creating with them model and service files, along with some HTML. and to build up the context file for entity framework amongst other things.

chsienki commented 3 years ago

We did also add one flag to our incremental APIs for giving a hint here to avoid running certain parts of the generator in certain cases; I'm not sure we finished that work though. @chsienki where did that end up?

Yes, we added an API for this exact case ReigisterImplentationSourceOutput(...), but it's only available if you're creating an incremental generator. It's actually not hooked up in the IDE right now (it essentially just runs all the time like regular source output) because its really just a 'hint' to the host, not a guarantee, but I would expect we would support it in the IDE in the near future.

We're also planning on adding a 'mirror' of the implementation source, essentially a 'ref only' that would only run in the IDE, and not in the batch compiler. So you could generate stubs in the IDE for intellisense and the slower implementation in the command line compiler.

amelmusic commented 2 years ago

I'm also facing same issue here: https://github.com/dotnet/roslyn/issues/58008

pCYSl5EDgo commented 2 years ago

See https://github.com/dotnet/runtime/pull/50741

There is a MSBuild property DesignTimeBuild.

amelmusic commented 2 years ago

@pCYSl5EDgo it seems that DesignTimeBuildis not working from VS 2022. My source generator is not triggering. I'm setting it like this: <PackageReference Condition="'$(DesignTimeBuild)'!='true'" Include="X.Core.Generator.Model" OutputItemType="Analyzer" Version="$(XCoreNugetVersion)" /> If I press F5, it's simply not run.

Ideally, we should have a flag that's telling us "did user run build" or he is just typing. For my scenario, if he is just typing I would return previous compilation.

pCYSl5EDgo commented 2 years ago

Why don't you use this msbuild property in your generator? https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md#consume-msbuild-properties-and-metadata

https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.diagnostics.analyzerconfigoptionsprovider.globaloptions?view=roslyn-dotnet-4.0.1#Microsoft_CodeAnalysis_Diagnostics_AnalyzerConfigOptionsProvider_GlobalOptions

amelmusic commented 2 years ago

@pCYSl5EDgo do you have a working example? I've tried getting DesignTimeBuild, but it's always empty. Tried: `

            if (config.GlobalOptions.TryGetValue("DesignTimeBuild", out var dtbSwitch))
            {
                dtbGlobal = dtbSwitch ?? "false";
            }`

and by build_property.DesignTimeBuild it seems that it's always blank. Thank you!

pCYSl5EDgo commented 2 years ago

@amelmusic https://github.com/pCYSl5EDgo/EmbeddingResourceCSharp

Open FileTests/EmbedTests.cs in VS2022, use F12 at GetA() and GetB(ReadOnlySpan s). If Not DesignTimeBuild, Edit csproj by insert crlf appropriate position.