@@ -51,8 +51,14 @@ public CXChildVisitResult VisitTranslationUnit(CXCursor cursor, CXCursor parent,
5151
5252 private CppContainerContext GetOrCreateDeclarationContainer ( CXCursor cursor , void * data )
5353 {
54- var fullName = clang . getCursorUSR ( cursor ) . CString ;
55- if ( _containers . TryGetValue ( fullName , out var containerContext ) )
54+ var typeAsCString = clang . getCursorUSR ( cursor ) . CString . ToString ( ) ;
55+ if ( string . IsNullOrEmpty ( typeAsCString ) )
56+ {
57+ typeAsCString = clang . getCursorDisplayName ( cursor ) . ToString ( ) ;
58+ }
59+ // Try to workaround anonymous types
60+ var typeKey = $ "{ cursor . Kind } :{ typeAsCString } { ( cursor . IsAnonymous ? "/" + cursor . Hash : string . Empty ) } ";
61+ if ( _containers . TryGetValue ( typeKey , out var containerContext ) )
5662 {
5763 return containerContext ;
5864 }
@@ -153,9 +159,9 @@ private CppContainerContext GetOrCreateDeclarationContainer(CXCursor cursor, voi
153159 containerContext = new CppContainerContext ( symbol ) { CurrentVisibility = defaultContainerVisibility } ;
154160
155161 // The type could have been added separately as part of the GetCppType above TemplateParameters
156- if ( ! _containers . ContainsKey ( fullName ) )
162+ if ( ! _containers . ContainsKey ( typeKey ) )
157163 {
158- _containers . Add ( fullName , containerContext ) ;
164+ _containers . Add ( typeKey , containerContext ) ;
159165 }
160166 return containerContext ;
161167 }
@@ -196,7 +202,6 @@ private CppClass VisitClassDecl(CXCursor cursor, void* data)
196202 private CXChildVisitResult VisitMember ( CXCursor cursor , CXCursor parent , void * data )
197203 {
198204 CppElement element = null ;
199-
200205 switch ( cursor . Kind )
201206 {
202207 case CXCursorKind . CXCursor_FieldDecl :
@@ -230,12 +235,34 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d
230235 case CXCursorKind . CXCursor_StructDecl :
231236 case CXCursorKind . CXCursor_UnionDecl :
232237 {
238+ bool isAnonymous = cursor . IsAnonymous ;
233239 var cppClass = VisitClassDecl ( cursor , data ) ;
234240 // Empty struct/class/union declaration are considered as fields
235- if ( string . IsNullOrEmpty ( cppClass . Name ) )
241+ if ( isAnonymous )
236242 {
243+ Debug . Assert ( string . IsNullOrEmpty ( cppClass . Name ) ) ;
237244 var containerContext = GetOrCreateDeclarationContainer ( parent , data ) ;
238- var cppField = new CppField ( cppClass , string . Empty ) ;
245+
246+ // We try to recover the offset from the previous field
247+ // Might not be always correct (with alignment rules),
248+ // but not sure how to recover the offset without recalculating the entire offsets
249+ var offset = 0 ;
250+ var cppClassContainer = containerContext . Container as CppClass ;
251+ if ( cppClassContainer is object && cppClassContainer . Fields . Count > 0 )
252+ {
253+ var lastField = cppClassContainer . Fields [ cppClassContainer . Fields . Count - 1 ] ;
254+ offset = ( int ) lastField . Offset + lastField . Type . SizeOf ;
255+ }
256+
257+ // Create an anonymous field for the type
258+ var cppField = new CppField ( cppClass , string . Empty )
259+ {
260+ Visibility = containerContext . CurrentVisibility ,
261+ StorageQualifier = GetStorageQualifier ( cursor ) ,
262+ IsAnonymous = true ,
263+ Offset = offset ,
264+ Attributes = ParseAttributes ( cursor )
265+ } ;
239266 containerContext . DeclarationContainer . Fields . Add ( cppField ) ;
240267 element = cppField ;
241268 }
@@ -735,22 +762,34 @@ private CppField VisitFieldOrVariable(CppContainerContext containerContext, CXCu
735762 var fieldName = GetCursorSpelling ( cursor ) ;
736763 var type = GetCppType ( cursor . Type . Declaration , cursor . Type , cursor , data ) ;
737764
738- var cppField = new CppField ( type , fieldName )
765+ var previousField = containerContext . DeclarationContainer . Fields . Count > 0 ? containerContext . DeclarationContainer . Fields [ containerContext . DeclarationContainer . Fields . Count - 1 ] : null ;
766+ CppField cppField ;
767+ // This happen in the type is anonymous, we create implicitly a field for it, but if type is the same
768+ // we should reuse the anonymous field we created just before
769+ if ( previousField != null && previousField . IsAnonymous && ReferenceEquals ( previousField . Type , type ) )
739770 {
740- Visibility = containerContext . CurrentVisibility ,
741- StorageQualifier = GetStorageQualifier ( cursor ) ,
742- IsBitField = cursor . IsBitField ,
743- BitFieldWidth = cursor . FieldDeclBitWidth ,
744- Offset = cursor . OffsetOfField / 8 ,
745- } ;
746- containerContext . DeclarationContainer . Fields . Add ( cppField ) ;
747- cppField . Attributes = ParseAttributes ( cursor ) ;
748-
749- if ( cursor . Kind == CXCursorKind . CXCursor_VarDecl )
771+ cppField = previousField ;
772+ cppField . Offset = cursor . OffsetOfField / 8 ;
773+ }
774+ else
750775 {
751- VisitInitValue ( cursor , data , out var fieldExpr , out var fieldValue ) ;
752- cppField . InitValue = fieldValue ;
753- cppField . InitExpression = fieldExpr ;
776+ cppField = new CppField ( type , fieldName )
777+ {
778+ Visibility = containerContext . CurrentVisibility ,
779+ StorageQualifier = GetStorageQualifier ( cursor ) ,
780+ IsBitField = cursor . IsBitField ,
781+ BitFieldWidth = cursor . FieldDeclBitWidth ,
782+ Offset = cursor . OffsetOfField / 8 ,
783+ } ;
784+ containerContext . DeclarationContainer . Fields . Add ( cppField ) ;
785+ cppField . Attributes = ParseAttributes ( cursor ) ;
786+
787+ if ( cursor . Kind == CXCursorKind . CXCursor_VarDecl )
788+ {
789+ VisitInitValue ( cursor , data , out var fieldExpr , out var fieldValue ) ;
790+ cppField . InitValue = fieldValue ;
791+ cppField . InitExpression = fieldExpr ;
792+ }
754793 }
755794
756795 return cppField ;
0 commit comments