C
C#13mo ago
swagrid

✅ Roslyn analyzer: System.Guid only has _dummyPrimitive field?

I'm currently writing an analyzer that inspects the fields of certain types. One of the tests failed because it analyzed System.Guid and I noticed that, according to this query:
ITypeSymbol type = ... // type is Guid
type.GetMembers().OfType<IFieldSymbol>().Where(f => !f.IsStatic)
ITypeSymbol type = ... // type is Guid
type.GetMembers().OfType<IFieldSymbol>().Where(f => !f.IsStatic)
System.Guid only has a single field: int _dummyPrimitive. I know that guids are larger than 4 bytes and given the field name, I assume this is a placeholder of some sort. I could just ignore System.Guid but I suspect this is not the only type that behaves this way. 1. Why is the ITypeSymbol of System.Guid a placeholder (or whatever this is) and not the original definition? 2. Can I somehow detect when a type is a placeholder?
11 Replies
333fred
333fred13mo ago
First, #roslyn is a channel you might want to get familiar with Second, analyzing types from other assemblies is not a good idea, because other assemblies are very likely to be ref assemblies
333fred
333fred13mo ago
Reference assemblies
Learn about reference assemblies, a special type of assemblies in .NET that contain only the library's public API surface
333fred
333fred13mo ago
You can't really detect such assemblies in any systematic fashion, roslyn neither knows nor cares whether a reference is a real assembly or a ref assembly What are you actually trying to do with this analyzer?
swagrid
swagrid13mo ago
I see, can project references also resolve to reference assemblies? We do quite extensive native interop between C# and C++ and I'm writing an analyzer that ensures we follow some internal guidelines when marshaling data. The analyzer effectively looks at all static extern methods and analyzes their parameters and return types. One part of the analyzer looks at the fields of a type to check if it's a wrapper of a primitive, e.g. struct Bool { byte b; }. That's where I ran into the Guid issue.
333fred
333fred13mo ago
Not usually This strikes me as something that should end going through something with an unmanaged constraint?
swagrid
swagrid13mo ago
I have an analyzer for more complex types that checks for unmanaged (in generics, for example). This specific analyzer is there to flag parameters that are expected to be passed as a pointer. Basically, everything that doesn't fit in a register should be passed as a pointer in some form (e.g. in Guid param1). Since the unmanaged constraint is valid on larger types, I cannot use it here. I'm also aware that doesn't fit in a register is very hard to determine because of the marshaler, so I'm overly pessimistic in the analyzer (which is fine in our scenario).
333fred
333fred13mo ago
Yeah, that's unfortunately going to be basically impossible to determine unless you never use reference assemblies (which slows down the build and increases memory usage) You may have to go extremely pessimistic and have some hard-coded list of types that are acceptable by value
swagrid
swagrid13mo ago
That was my idea as well. It shouldn't be too bad, since we don't use many types outside of our own namespace for marshaling. It's mainly primitives and two or three others like Guid. Thanks a lot for the help!
333fred
333fred13mo ago
Yw. Make sure to $close the thread
MODiX
MODiX13mo ago
Use the /close command to mark a forum thread as answered
swagrid
swagrid13mo ago
Will, do. I had issues last time where it didn't let me close the thread. Lets see if I'm mighty enough this time.