@@ -3166,9 +3166,19 @@ private string GetRemappedCursorName(NamedDecl namedDecl, out string nativeTypeN
31663166 {
31673167 remappedName = "Dispose" ;
31683168 }
3169- else if ( namedDecl is FieldDecl fieldDecl )
3169+ else if ( ( namedDecl is FieldDecl fieldDecl ) && name . StartsWith ( "__AnonymousFieldDecl_" , StringComparison . Ordinal ) )
31703170 {
3171- if ( name . StartsWith ( "__AnonymousFieldDecl_" , StringComparison . Ordinal ) )
3171+ if ( fieldDecl . Type . AsCXXRecordDecl ? . IsAnonymous == true )
3172+ {
3173+ // For fields of anonymous types, use the name of the type but clean off the type
3174+ // kind tag at the end.
3175+ var typeName = GetRemappedNameForAnonymousRecord ( fieldDecl . Type . AsCXXRecordDecl ) ;
3176+ var tagIndex = typeName . LastIndexOf ( "_e__" , StringComparison . Ordinal ) ;
3177+ Debug . Assert ( typeName [ 0 ] == '_' ) ;
3178+ Debug . Assert ( tagIndex >= 0 ) ;
3179+ remappedName = typeName . Substring ( 1 , tagIndex - 1 ) ;
3180+ }
3181+ else
31723182 {
31733183 remappedName = "Anonymous" ;
31743184
@@ -3184,28 +3194,62 @@ private string GetRemappedCursorName(NamedDecl namedDecl, out string nativeTypeN
31843194 }
31853195 else if ( ( namedDecl is RecordDecl recordDecl ) && name . StartsWith ( "__AnonymousRecord_" , StringComparison . Ordinal ) )
31863196 {
3187- if ( recordDecl . Parent is RecordDecl parentRecordDecl )
3188- {
3189- remappedName = "_Anonymous" ;
3197+ remappedName = GetRemappedNameForAnonymousRecord ( recordDecl ) ;
3198+ }
31903199
3191- var matchingField = parentRecordDecl . Fields . Where ( ( fieldDecl ) => fieldDecl . Type . CanonicalType == recordDecl . TypeForDecl . CanonicalType ) . FirstOrDefault ( ) ;
3200+ return remappedName ;
3201+ }
31923202
3193- if ( matchingField is not null )
3194- {
3195- remappedName = "_" ;
3196- remappedName += GetRemappedCursorName ( matchingField ) ;
3197- }
3198- else if ( parentRecordDecl . AnonymousRecords . Count > 1 )
3203+ private string GetRemappedNameForAnonymousRecord ( RecordDecl recordDecl )
3204+ {
3205+ if ( recordDecl . Parent is RecordDecl parentRecordDecl )
3206+ {
3207+ var remappedNameBuilder = new StringBuilder ( ) ;
3208+ var matchingField = parentRecordDecl . Fields . Where ( ( fieldDecl ) => fieldDecl . Type . CanonicalType == recordDecl . TypeForDecl . CanonicalType ) . FirstOrDefault ( ) ;
3209+
3210+ if ( ( matchingField is not null ) && ! matchingField . IsAnonymousField )
3211+ {
3212+ _ = remappedNameBuilder . Append ( '_' ) ;
3213+ _ = remappedNameBuilder . Append ( GetRemappedCursorName ( matchingField ) ) ;
3214+ }
3215+ else
3216+ {
3217+ _ = remappedNameBuilder . Append ( "_Anonymous" ) ;
3218+
3219+ // If there is more than one anonymous type, then add a numeral to differentiate.
3220+ if ( parentRecordDecl . AnonymousRecords . Count > 1 )
31993221 {
32003222 var index = parentRecordDecl . AnonymousRecords . IndexOf ( recordDecl ) + 1 ;
3201- remappedName += index . ToString ( CultureInfo . InvariantCulture ) ;
3223+ Debug . Assert ( index > 0 ) ;
3224+ _ = remappedNameBuilder . Append ( index ) ;
32023225 }
32033226
3204- remappedName += $ "_e__{ ( recordDecl . IsUnion ? "Union" : "Struct" ) } ";
3227+ // C# doesn't allow a nested type to have the same name as the parent, so if the
3228+ // parent is also anonymous, add the nesting depth as a way to avoid conflicts with
3229+ // the parent's name.
3230+ if ( parentRecordDecl . IsAnonymous )
3231+ {
3232+ var depth = 1 ;
3233+ var currentParent = parentRecordDecl . Parent ;
3234+ while ( ( currentParent is RecordDecl currentParentRecordDecl ) && currentParentRecordDecl . IsAnonymous )
3235+ {
3236+ depth ++ ;
3237+ currentParent = currentParentRecordDecl . Parent ;
3238+ }
3239+ _ = remappedNameBuilder . Append ( '_' ) ;
3240+ _ = remappedNameBuilder . Append ( depth ) ;
3241+ }
32053242 }
3206- }
32073243
3208- return remappedName ;
3244+ // Add the type kind tag.
3245+ _ = remappedNameBuilder . Append ( "_e__" ) ;
3246+ _ = remappedNameBuilder . Append ( recordDecl . IsUnion ? "Union" : "Struct" ) ;
3247+ return remappedNameBuilder . ToString ( ) ;
3248+ }
3249+ else
3250+ {
3251+ return $ "_Anonymous_e__{ ( recordDecl . IsUnion ? "Union" : "Struct" ) } ";
3252+ }
32093253 }
32103254
32113255 private string GetRemappedName ( string name , Cursor ? cursor , bool tryRemapOperatorName , out bool wasRemapped , bool skipUsing = false )
@@ -3304,48 +3348,7 @@ private string GetRemappedTypeName(Cursor? cursor, Cursor? context, Type type, o
33043348 if ( IsType < RecordType > ( cursor , type , out var recordType ) && remappedName . StartsWith ( "__AnonymousRecord_" , StringComparison . Ordinal ) )
33053349 {
33063350 var recordDecl = recordType . Decl ;
3307- remappedName = "_Anonymous" ;
3308-
3309- if ( recordDecl . Parent is RecordDecl parentRecordDecl )
3310- {
3311- var matchingField = parentRecordDecl . Fields . Where ( ( fieldDecl ) => fieldDecl . Type . CanonicalType == recordType ) . FirstOrDefault ( ) ;
3312-
3313- if ( matchingField is not null )
3314- {
3315- remappedName = "_" ;
3316- remappedName += GetRemappedCursorName ( matchingField ) ;
3317- }
3318- else
3319- {
3320- var index = 0 ;
3321-
3322- if ( parentRecordDecl . AnonymousRecords . Count > 1 )
3323- {
3324- index = parentRecordDecl . AnonymousRecords . IndexOf ( cursor ) + 1 ;
3325- }
3326-
3327- while ( parentRecordDecl . IsAnonymousStructOrUnion && ( parentRecordDecl . IsUnion == recordType . Decl . IsUnion ) )
3328- {
3329- index += 1 ;
3330-
3331- if ( parentRecordDecl . Parent is RecordDecl parentRecordDeclParent )
3332- {
3333- if ( parentRecordDeclParent . AnonymousRecords . Count > 0 )
3334- {
3335- index += parentRecordDeclParent . AnonymousRecords . Count - 1 ;
3336- }
3337- parentRecordDecl = parentRecordDeclParent ;
3338- }
3339- }
3340-
3341- if ( index != 0 )
3342- {
3343- remappedName += index . ToString ( CultureInfo . InvariantCulture ) ;
3344- }
3345- }
3346- }
3347-
3348- remappedName += $ "_e__{ ( recordDecl . IsUnion ? "Union" : "Struct" ) } ";
3351+ remappedName = GetRemappedNameForAnonymousRecord ( recordDecl ) ;
33493352 }
33503353 else if ( IsType < EnumType > ( cursor , type , out var enumType ) && remappedName . StartsWith ( "__AnonymousEnum_" , StringComparison . Ordinal ) )
33513354 {
@@ -4572,7 +4575,7 @@ private bool HasBaseField(CXXRecordDecl cxxRecordDecl)
45724575
45734576 private bool HasField ( RecordDecl recordDecl )
45744577 {
4575- var hasField = recordDecl . Fields . Any ( ) || recordDecl . Decls . Any ( ( decl ) => ( decl is RecordDecl nestedRecordDecl ) && nestedRecordDecl . IsAnonymousStructOrUnion && HasField ( nestedRecordDecl ) ) ;
4578+ var hasField = recordDecl . Fields . Any ( ) || recordDecl . Decls . Any ( ( decl ) => ( decl is RecordDecl nestedRecordDecl ) && nestedRecordDecl . IsAnonymous && HasField ( nestedRecordDecl ) ) ;
45764579
45774580 if ( ! hasField && ( recordDecl is CXXRecordDecl cxxRecordDecl ) )
45784581 {
@@ -5123,7 +5126,7 @@ bool IsEmptyRecord(RecordDecl recordDecl)
51235126
51245127 foreach ( var decl in recordDecl . Decls )
51255128 {
5126- if ( ( decl is RecordDecl nestedRecordDecl ) && nestedRecordDecl . IsAnonymousStructOrUnion && ! IsEmptyRecord ( nestedRecordDecl ) )
5129+ if ( ( decl is RecordDecl nestedRecordDecl ) && nestedRecordDecl . IsAnonymous && ! IsEmptyRecord ( nestedRecordDecl ) )
51275130 {
51285131 return false ;
51295132 }
@@ -6150,7 +6153,7 @@ private bool IsUnsafe(RecordDecl recordDecl)
61506153 {
61516154 return true ;
61526155 }
6153- else if ( ( decl is RecordDecl nestedRecordDecl ) && nestedRecordDecl . IsAnonymousStructOrUnion && ( IsUnsafe ( nestedRecordDecl ) || Config . GenerateCompatibleCode ) )
6156+ else if ( ( decl is RecordDecl nestedRecordDecl ) && nestedRecordDecl . IsAnonymous && ( IsUnsafe ( nestedRecordDecl ) || Config . GenerateCompatibleCode ) )
61546157 {
61556158 return true ;
61566159 }
0 commit comments