@@ -799,12 +799,11 @@ private static string GetErrorMessage(BorrowedReference value, string fallbackNa
799799
800800 // The candidate member names of a type, cached so the reflection and name conversion
801801 // happen at most once per type rather than on every attribute miss. Instance and static
802- // members are both included, and each is converted so the suggestion matches the name
803- // Python exposes it under: methods become lower_snake, enum values, consts and
804- // static-readonly members become UPPER_SNAKE (e.g. DayOfWeek.SUNDAY, Math.PI,
805- // String.EMPTY), and nested types keep their original name (ClassManager registers no
806- // snake_case alias for them). Each name is tagged with how it is used from Python so
807- // suggestions can be filtered by usage.
802+ // members are both included, and each is converted with ToSnakeCaseMemberName so the
803+ // suggestion matches the name Python exposes it under: methods become lower_snake, enum
804+ // values, consts and static-readonly members become UPPER_SNAKE (e.g. DayOfWeek.SUNDAY,
805+ // Math.PI, String.EMPTY), and nested types keep their original name. Each name is tagged
806+ // with how it is used from Python so suggestions can be filtered by usage.
808807 private static Dictionary < string , SuggestionKind > GetCandidateMemberNames ( Type type )
809808 {
810809 return _candidateNameCache . GetOrAdd ( type , static t =>
@@ -827,15 +826,7 @@ private static Dictionary<string, SuggestionKind> GetCandidateMemberNames(Type t
827826 continue ;
828827 }
829828
830- var ( name , kind ) = member switch
831- {
832- Type => ( member . Name , SuggestionKind . Callable ) ,
833- MethodBase => ( member . Name . ToSnakeCase ( ) , SuggestionKind . Callable ) ,
834- FieldInfo fieldInfo => ( fieldInfo . ToSnakeCase ( ) , SuggestionKind . Data ) ,
835- PropertyInfo propertyInfo => ( propertyInfo . ToSnakeCase ( ) , SuggestionKind . Data ) ,
836- _ => ( member . Name . ToSnakeCase ( ) , SuggestionKind . Data ) ,
837- } ;
838-
829+ var ( name , kind ) = ToSnakeCaseMemberName ( member ) ;
839830 names [ name ] = names . TryGetValue ( name , out var existing ) ? existing | kind : kind ;
840831 }
841832
@@ -887,6 +878,23 @@ private static string ComputeSimilarMemberNames(Type type, string name)
887878 return " Did you mean: " + string . Join ( ", " , suggestions ) + "?" ;
888879 }
889880
881+ // Converts a member to the name Python exposes it under, tagged with how it is used.
882+ // The field/property overloads of ToSnakeCase are used so const and static-readonly
883+ // members are converted to UPPER_CASE. Nested types keep their original name verbatim:
884+ // ClassManager registers no snake_case alias for them, and they count as callable since
885+ // accessing one may be an attempted constructor call.
886+ private static ( string Name , SuggestionKind Kind ) ToSnakeCaseMemberName ( MemberInfo member )
887+ {
888+ return member switch
889+ {
890+ Type => ( member . Name , SuggestionKind . Callable ) ,
891+ MethodBase => ( member . Name . ToSnakeCase ( ) , SuggestionKind . Callable ) ,
892+ FieldInfo fieldInfo => ( fieldInfo . ToSnakeCase ( ) , SuggestionKind . Data ) ,
893+ PropertyInfo propertyInfo => ( propertyInfo . ToSnakeCase ( ) , SuggestionKind . Data ) ,
894+ _ => ( member . Name . ToSnakeCase ( ) , SuggestionKind . Data ) ,
895+ } ;
896+ }
897+
890898 private static int LevenshteinDistance ( string a , string b )
891899 {
892900 a = a . ToLowerInvariant ( ) ;
0 commit comments