-
Notifications
You must be signed in to change notification settings - Fork 1.2k
apicompat: treat IntPtr as nint and UIntPtr as nuint #27601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| internal static string ToComparisonDisplayString(this ISymbol symbol) => symbol.ToDisplayString(Format); | ||
| internal static string ToComparisonDisplayString(this ISymbol symbol) => | ||
| symbol.ToDisplayString(Format) | ||
| .Replace("System.IntPtr", "nint") // Treat IntPtr and nint as the same |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this create confusing diagnostics when someone is actually using IntPtr? Say I had an API that used IntPtr and I removed it on the right, what diagnostic do we emit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code path doesn't impact the Target that is being emitted by rules and APICompat. The ToComparisonDisplayString helper function is only used by the mapping infrastructure to map members together.
I.e.
| $"{itemRef}:[{docId}]"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string is only used for comparing symbols, so the diagnostic that is emitted in that case is still "CP0002 : Member 'CompatTests.First.H(System.IntPtr)' exists on left but not on right".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do end up having to normalize this in comparisons, it might be better to do here:
sdk/src/ApiCompat/Microsoft.DotNet.ApiCompatibility/DefaultSymbolsEqualityComparer.cs
Line 14 in 0975222
| string.Equals(x != null ? GetKey(x) : null, y != null ? GetKey(y) : null, StringComparison.OrdinalIgnoreCase); |
And only after the equality check fails, and only if references are not provided. I'd like us to first see if we can get roslyn to behave as if the feature is supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the ToComparisonDisplayString method is the right place as the name already suggests that it calculates a display string for comparison.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing this on .NET 472 and .NET 7,
if (RuntimeFeature.IsSupported("NumericIntPtr"))
{
return symbol.ToDisplayString(Format);
}
return symbol.ToDisplayString(Format)
.Replace("nint", "System.IntPtr") // Treat nint and IntPtr as the same
.Replace("nuint", "System.UIntPtr"); // Treat nuint and UIntPtr as the sametests fail on .NET 7. It seems like even when NumericIntPtr is defined, Roslyn returns different display strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Off the top of my head the two concerning places are nested types (which probably here use a + instead of .) and explicit interface implementations (e.g. the full method name of IEnumerable.GetEnumerator() => GetEnumerator(); I believe is System.IEnumerable.GetEnumerator. So while "nint" => "System.IntPtr" probably wouldn't create any false positives, '.' probably isn't a guaranteed "eh, it's fine".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that nint is fairly new but it's not unlikely that nint and nuint word parts are used in a member's name. I would expect that replacing "nint" with "System.IntPtr" would result in way more false positives than the other way around. That said, these false positives shouldn't have any negative impact as far as I can tell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (RuntimeFeature.IsSupported("NumericIntPtr"))
This is mixing tooling runtime with target runtime. The check would need to be against whatever the target references that were used when compiling the assembly. Calling the feature RuntimeFeature.IsSupported in the tool runtime has no relevance since we might be using an older runtime to test assemblies built for a newer one.
The way I was imagining this to work was we would add some parameter to DefaultSymbolsEqualityComparer like bool honorRuntimeFeatures and set that as withReferences == true. Then we could say that when it is false we'd do the hack-up in DefaultSymbolsEqualityComparer.GetKey to normalize those symbols.
it's not unlikely that nint and nuint word parts are used in a member's name
That's true. I see we're doing arbitrary replacements here wherever they occur in the string. I'll relent on my suggestion to change the direction of replacement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the premise of the withReferences suggestion was based on the fact that we only face this problem when we don't have the matching references. However, we probably are in this state even when references are provided, since we don't have references for the left-hand-side and that might be the runtime that doesn't support the feature :(
I was really trying to get this to a place where we didn't need this hack indefinitely but I guess that might not be possible at the moment.
ViktorHofer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Thanks for adding a test for it.
|
Approved this as-is. I think given our current architecture (references present only for right hand side) and the only source for this feature information in the compiler coming from references - we'll always be in a state where we need to normalize these types of metadata differences ourselves. That's unfortunate but I can't think of a better solution. |
Previously, ApiCompat would consider `IntPtr` and `nint` (as well as `UIntPtr` and `nuint`) as different types, emitting diagnostics where there shouldn't have been. This change updates the display string used by the SymbolComparer to replace all instances of `IntPtr` with `nint` and `UIntPtr` with `nuint`. Fixes dotnet#25566
Previously, ApiCompat would consider
IntPtrandnint(as well asUIntPtrandnuint) as different types, emitting diagnostics where there shouldn't have been. This change updates the display string used by the SymbolComparer to replace all instances ofIntPtrwithnintandUIntPtrwithnuint.Fixes #25566