@@ -367,61 +367,65 @@ public static ICollection<ITypeSymbol> GetSortedTypeHierarchy(this ITypeSymbol t
367367 }
368368 }
369369
370- public static IEnumerable < ISymbol > GetAllMembers ( this ITypeSymbol type )
371- => type . GetSortedTypeHierarchy ( ) . SelectMany ( t => t . GetMembers ( ) ) ;
372-
373- public static IEnumerable < ( IMethodSymbol Symbol , bool IsAmbiguous ) > GetAllMethods ( this ITypeSymbol type )
370+ /// <summary>
371+ /// Resolves all members that are visible on the specified type,
372+ /// accounting for overrides and shadowing in the type hierarchy.
373+ /// </summary>
374+ public static IEnumerable < ( ISymbol Symbol , bool IsAmbiguous ) > ResolveVisibleMembers ( this ITypeSymbol type )
374375 {
375- List < ( IMethodSymbol Symbol , bool IsAmbiguous ) > methods = [ ] ;
376- Dictionary < string , int > foundSignatures = new ( ) ;
376+ Dictionary < string , List < int > > membersInScope = new ( StringComparer . Ordinal ) ;
377+ List < ( ISymbol Symbol , bool IsAmbiguous ) > results = [ ] ;
377378
379+ // Walk the type hierarchy, from most derived to least derived.
378380 foreach ( ITypeSymbol current in type . GetSortedTypeHierarchy ( ) )
379381 {
380- foreach ( IMethodSymbol method in current . GetMembers ( ) . OfType < IMethodSymbol > ( ) )
382+ foreach ( ISymbol member in current . GetMembers ( ) )
381383 {
382- // Create a signature key that includes name, parameters, and return type
383- string signature = GetMethodSignature ( method ) ;
384- if ( foundSignatures . TryGetValue ( signature , out int index ) )
384+ // To account for overloads, method identifiers include the method name and parameter types but not the return type.
385+ string identifier = member is IMethodSymbol method
386+ ? $ "{ method . Name } ({ string . Join ( ", " , method . Parameters . Select ( p => p . Type . GetFullyQualifiedName ( ) ) ) } )"
387+ : member . Name ;
388+
389+ bool isAmbiguous ;
390+ if ( membersInScope . TryGetValue ( identifier , out List < int > conflictingMemberIndices ) )
385391 {
386- IMethodSymbol conflictingMethod = methods [ index ] . Symbol ;
387- if ( ! current . IsAssignableFrom ( conflictingMethod . ContainingType ) )
392+ if ( conflictingMemberIndices . Exists ( i => current . IsAssignableFrom ( results [ i ] . Symbol . ContainingType ) ) )
388393 {
389- // We have a method with the same signature in an unrelated type,
390- // due to diamond ambiguity in an interface hierarchy.
394+ continue ; // Member is overridden or shadowed by a more derived type in the hierarchy.
395+ }
391396
392- Debug . Assert ( type . TypeKind is TypeKind . Interface ) ;
393- methods [ index ] = ( conflictingMethod , IsAmbiguous : true ) ;
394- methods . Add ( ( method , IsAmbiguous : true ) ) ;
397+ if ( conflictingMemberIndices is [ int singleIndex ] )
398+ {
399+ // We found our first ambiguity, update the previous entry accordingly.
400+ results [ singleIndex ] = ( results [ singleIndex ] . Symbol , IsAmbiguous : true ) ;
395401 }
396402
397- continue ; // This method is shadowed by a derived type, skip it.
403+ // Member forms diamond ambiguity, include in case there is disambiguation on attribute configs.
404+ Debug . Assert ( type . TypeKind is TypeKind . Interface ) ;
405+ isAmbiguous = true ;
406+ }
407+ else
408+ {
409+ membersInScope [ identifier ] = conflictingMemberIndices = [ ] ;
410+ isAmbiguous = false ;
398411 }
399412
400- foundSignatures . Add ( signature , methods . Count ) ;
401- methods . Add ( ( method , IsAmbiguous : false ) ) ;
413+ conflictingMemberIndices . Add ( results . Count ) ;
414+ results . Add ( ( member , isAmbiguous ) ) ;
402415 }
403416 }
404417
405- return methods ;
406-
407- static string GetMethodSignature ( IMethodSymbol method )
408- {
409- string parameters = string . Join ( "," , method . Parameters . Select ( p => p . Type . ToDisplayString ( ) ) ) ;
410- return $ "{ method . ReturnType . ToDisplayString ( ) } { method . Name } ({ parameters } )";
411- }
418+ return results ;
412419 }
413420
414- public static IEnumerable < IEventSymbol > GetAllEvents ( this ITypeSymbol type )
421+ public static IEnumerable < ( TMember Symbol , bool IsAmbiguous ) > ResolveVisibleMembers < TMember > ( this ITypeSymbol type )
422+ where TMember : ISymbol
415423 {
416- HashSet < string > foundNames = [ ] ;
417- foreach ( ITypeSymbol current in type . GetSortedTypeHierarchy ( ) )
424+ foreach ( ( ISymbol symbol , bool isAmbiguous ) in type . ResolveVisibleMembers ( ) )
418425 {
419- foreach ( IEventSymbol eventSymbol in current . GetMembers ( ) . OfType < IEventSymbol > ( ) )
426+ if ( symbol is TMember member )
420427 {
421- if ( foundNames . Add ( eventSymbol . Name ) )
422- {
423- yield return eventSymbol ;
424- }
428+ yield return ( member , isAmbiguous ) ;
425429 }
426430 }
427431 }
0 commit comments