Track sibling-overload metadata closure in symbol-based mode (#146)#147
Merged
Track sibling-overload metadata closure in symbol-based mode (#146)#147
Conversation
When ReferenceTrimmerUseSymbolAnalysis=true, RT was missing assemblies that the C# compiler eagerly loads during name-based member lookup for overload resolution. The selected overload's containing assembly was tracked, but sibling overloads' parameter/return types were not -- producing false-positive RT0001/RT0002 diagnostics whose application leaves the build broken with CS0012. This fixes: * Constructor overloads at base() / new T(...) sites (#146 primary case). * Constructor overloads on attribute classes (#146 P.S. case). * Method overloads at instance, static, and base-chain call sites. * Method overloads through interfaces. * Method-group / delegate-target conversions. * Indexer overloads. * Extension method overloads (instance-style and method-group form), where name lookup happens on the extension's containing static class rather than on the receiver type. Adds 15 regression tests (positive + negative) covering each shape; each positive test was verified to fail without the analyzer change and pass with it. All 70 analyzer tests pass. Same family as the override-chain gap (PR #143). Out of scope: operator and conversion sibling overloads (compiler is empirically lazier here and does not fire CS0012 on the cases tested). Fixes #146 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #146.
Problem
When
ReferenceTrimmerUseSymbolAnalysis=true(the experimental v3.5 symbol-based detection mode), RT was under-reporting references the C# compiler actually requires. Concretely: when source code performs name-based member lookup on a type — invocation, method-group conversion, indexer access, constructor call, attribute application — the compiler resolves the metadata of every member with that name on the receiving type and its base/interface chain in order to perform overload resolution. Every sibling overload's parameter/return type assemblies must therefore be metadata-resolvable, even ones source code never selects, otherwise CS0012 fires on the unused overload's parameter type.The symbol analyzer tracked only the selected overload (
IInvocationOperation.TargetMethod.ContainingAssemblyetc.) and missed sibling-overload metadata-closure assemblies. Same family of issue as the override-chain gap fixed in #143, just specialized to per-call-site name resolution.The original issue (#146) reports the constructor case (
Provider.Class1withClass1(params string[])andClass1(ProviderDependency.Class1); consumer derives and callsbase(""1""); RT incorrectly trimsProviderDependency). After empirically probing the compiler's behavior across name-resolution shapes, this PR addresses the broader pattern.Fix
Inside
InitializeSymbolBasedAnalysis:TrackInstanceConstructorParameters(INamedTypeSymbol)— wired into the inheritance walk inTrackType; runs once per named type for the type itself and eachBaseTypein its chain. Covers: base(...),new T(...), and attribute application (sinceTrackAttributefeeds the attribute class throughTrackType).TrackOverloadSiblings(receiverType, name)— walksreceiverType+BaseTypechain +AllInterfaces, callingGetMembers(name)per type and tracking each method/property's parameter and return-type assemblies viaTrackType. Wired intoIInvocationOperationand theIMethodReferenceOperationbranch ofIMemberReferenceOperation.TrackIndexerSiblings(receiverType)— same shape but scans forIsIndexer, since indexer lookup isn't keyed on a regular name. Wired into theIPropertyReferenceOperationbranch whenIsIndexer.IsExtensionMethodis true, additionally walk siblings onTargetMethod.ContainingType(the static class), because the compiler's name lookup for extension overload resolution happens on the static class, not on the receiver type.ConcurrentDictionarycaches (memberLookupWalked,indexerLookupWalked) keyed withSymbolEqualityComparer.Defaultto dedup walks across hot call sites.Tests
15 new regression tests in
AnalyzerTests.cscovering each shape:Each positive test was verified to fail without the analyzer change and pass with it. All 70
AnalyzerTestspass; 81 unit tests total green.E2E validation
Reproduced the issue's exact scenario (Consumer/Provider/ProviderDependency with
<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>) plus the expanded shapes (method overload, static method, indexer, method group). Without the fix, RT0002 fires onProviderDependency; with the fix it doesn't. RemovingProviderDependencyfrom the consumer csproj produces CS0012, confirming the fix is necessary and not over-conservative.Out of scope