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.89k stars 4.01k forks source link

Provide a mechanism to inspect and modify a project's package references from a code fixer #62904

Open geeknoid opened 2 years ago

geeknoid commented 2 years ago

We have code fixers that are updating the source code to leverage some code in custom nuget packages. As we fix the code, we'd like to add the necessary package references to the relevant project files. As it is, we update the source code, but then the project fails to build until the user manually adds the missing package reference.

genlu commented 2 years ago

We have a VS only internal component IPackageInstallerService that does what you are asking. But I'm not sure this is an API we'd want to make public given the demands. @CyrusNajmabadi thoughts?

@geeknoid would you be able to use reflection to get the internal service?

geeknoid commented 2 years ago

I'd be happy to try that route. I can make it conditional so if reflection can't find it, the fixer still works.

Would you have an example how to get my hands on that interface?

genlu commented 2 years ago

@geeknoid You could get installer service from the solution (here's an example), by using reflection to construct instantiated GetService method (probably something like this)

CyrusNajmabadi commented 2 years ago

Definitely never use these types using reflection. We will absolutely change these at any time for any number of reasons. This is not a supported public Roslyn API.

genlu commented 2 years ago

We will absolutely change these at any time for any number of reasons. This is not a supported public Roslyn API.

@geeknoid In case my previous statement re: API not being public isn't a clear enough indication for this^

CyrusNajmabadi commented 2 years ago

A code fixer runs in the context of VS, and can access the same APIs that roslyn uses. e.g. IVsPackageInstaller2. That is the API that should be used for this purpose.

danmoseley commented 1 year ago

It does appear that IVsPackageUninstaller and IVsPackageInstaller would do what we want.

https://learn.microsoft.com/en-us/nuget/visual-studio-extensibility/nuget-api-in-visual-studio#ivspackageinstaller-interface https://learn.microsoft.com/en-us/nuget/visual-studio-extensibility/nuget-api-in-visual-studio#ivspackageuninstaller-interface

danmoseley commented 1 year ago

@CyrusNajmabadi for the avoidance of ambiguity can you confirm that a fixer can access these supported interfaces, ie., without reflection?

CyrusNajmabadi commented 1 year ago

You should be able to access the IVSPackageInstaller/Unintaller interfaces without need for reflection. We access them as totally supported APIs, and have found them viable for Roslyn's needs as well.

geeknoid commented 1 year ago

So within a fixer, how do I get my hands on IVsPackageUninstaller and IVsPackageInstaller?

CyrusNajmabadi commented 1 year ago

We import it from mef: [Import(AllowDefault = true)] Lazy<IVsPackageInstaller2>? packageInstaller