Use case:
In ReflectionAnalyzers we want to check if types and members exists. For example we want to produce a warning here:
var mi = typeof(Foo).GetMethod("MISSING");
The problem is that all symbols are not always imported so we have no way to determine if the symbol is missing or was not imported when it is from metadata.
Cyrus pointed us to MetadataImportOptions but we have not found a way to use this.
Ideally we would like to:
MetadataImportOptions.All and warn that All should be used with the reflection analyzer.MetadataImportOptions.All in for example CompilationStart if possible.We would need to expose an API that would allow analyzers to ask for MetadataImportOptions.All to be used. I don't know what the performance implications of this are though, @tmat I assume things would slow down for VS users because we would be importing a lot more metadata?
@JohanLarsson MetadataImportOptions.All may not solve your problem. What if the assembly you are looking at is a reference assembly (intentionally has all of its non-public data removed)? In that case there is no additional data to import.
Yes reference assemblies are another problem we would need to detect and handle somehow.
Besides reference assemblies, I'd also want the analyzer to bail if the referenced assembly is not copied to build output. That's a strong indication that you will be running against a different version than the one you compile against, and therefore you don't know anything about the public or private types that might need to be dynamically detected. (Think BCL or NuGet dependencies.) Is there a way an analyzer can figure out if the reference is (probably) going to end up in build output?
I fail to see the point of this analyzer. If I could depend on the member being there I wouldn't use reflection in the first place. Reflection is used for light-up and other scenarios where the member might be actually missing.
@tmat Using MakeGenericType/MakeGenericMethod to invoke a method is not an uncommon reason. You also use reflection when emitting IL against known types, which is the bulk of the IL generation I do.
@tmat could be that we want to invoke an internal method on a type that is not in our source. Also that the analyzer does not find the symbol means it can't check anything that is done with the method info. We have more rules checking that the correct arguments are passed and the return value cast to the correct type etc.
@tmat could be that we want to invoke an internal method on a type that is not in our source. Also that the analyzer does not find the symbol means it can't check anything that is done with the method info. We have more rules checking that the correct arguments are passed and the return value cast to the correct type etc.
Would it possibly make more sense to actually use the real reflection API? Since you're trying to provide messages if it's the case that using the reflection APi will result in problems?
@CyrusNajmabadi You mean from an analyzer? That's not a good idea. You don't want to load the assemblies to the process that's running the analyzer.
Sadly I think the "correct" way to do this is to have an API that does this sort of runtime analysis, which frankly is not roslyn's forte. Any approach here is going to be incomplete unless there is some service that can essentially load all possible runtime assemblies and instrument them.
Would it possibly make more sense to actually use the real reflection API? Since you're trying to provide messages if it's the case that using the reflection APi will result in problems?
Yes it makes sense but even if we use the reflection API it will be nice with symbols.
We would need a more concrete API proposal to evaluate this feature request.
Most helpful comment
@tmat Using MakeGenericType/MakeGenericMethod to invoke a method is not an uncommon reason. You also use reflection when emitting IL against known types, which is the bulk of the IL generation I do.