diff --git a/include/mrdocs/Metadata/Field.hpp b/include/mrdocs/Metadata/Field.hpp index 16465abc3..f67a0696f 100644 --- a/include/mrdocs/Metadata/Field.hpp +++ b/include/mrdocs/Metadata/Field.hpp @@ -38,6 +38,9 @@ struct FieldInfo */ ExprInfo Default; + /** Whether the field is a variant member */ + bool IsVariant = false; + /** Whether the field is declared mutable */ bool IsMutable = false; diff --git a/share/mrdocs/addons/generator/asciidoc/partials/special-name-suffix.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/special-name-suffix.adoc.hbs index 1e472644e..4db1d48ec 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/special-name-suffix.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/special-name-suffix.adoc.hbs @@ -1,6 +1,8 @@ {{#if (eq kind "overload")}}{{>special-name-suffix (front members)~}} {{else if (eq kind "function")~}} {{#if (eq class "constructor")}}[.small]#[constructor]# -{{~else if (eq class "destructor")~}}[.small]#[destructor]# +{{~else if (eq class "destructor")}}[.small]#[destructor]# {{~/if~}} +{{else if (eq kind "field")~}} +{{#if isVariant}}[.small]#[variant member]#{{/if~}} {{/if}} \ No newline at end of file diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index ebee04a8f..c6229236e 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -547,6 +547,11 @@ class ASTVisitor if(DC->isFileContext() || DC->isFunctionOrMethod()) break; + + if(auto* RD = dyn_cast(DC); + RD && RD->isAnonymousStructOrUnion()) + continue; + // when extracting dependencies, we want to extract // all members of the containing class, not just this one if(auto* TD = dyn_cast(DC)) @@ -1519,6 +1524,16 @@ class ASTVisitor return false; } + // don't extract anonymous unions + if(const auto* RD = dyn_cast(D); + RD && RD->isAnonymousStructOrUnion()) + return false; + + // don't extract implicitly generated declarations + // (except for IndirectFieldDecls) + if(D->isImplicit() && !isa(D)) + return false; + if (!config_->input.include.empty()) { // Get filename @@ -1959,10 +1974,15 @@ class ASTVisitor { switch(D->getKind()) { + case Decl::CXXRecord: + // we treat anonymous unions as "transparent" + if(auto* RD = cast(D); + RD->isAnonymousStructOrUnion()) + break; + [[fallthrough]]; case Decl::TranslationUnit: case Decl::Namespace: case Decl::Enum: - case Decl::CXXRecord: case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: return D; @@ -2373,6 +2393,8 @@ class ASTVisitor I.Type = buildTypeInfo(D->getType()); + I.IsVariant = D->getParent()->isUnion(); + I.IsMutable = D->isMutable(); if(const Expr* E = D->getInClassInitializer()) @@ -2793,6 +2815,17 @@ class ASTVisitor void traverse(FieldDecl*); + /** Traverse a member of an anonymous union. + + This function is called by traverseDecl to traverse + a member of an anonymous union. + + A IndirectFieldDecl inherits from ValueDecl. + + */ + void + traverse(IndirectFieldDecl*); + /** Traverse a concept definition This function is called by traverseDecl to traverse a @@ -3061,6 +3094,14 @@ traverse(FieldDecl* D) auto [I, created] = *exp; buildField(I, created, D); } + +void +ASTVisitor:: +traverse(IndirectFieldDecl* D) +{ + traverse(D->getAnonField()); +} + //------------------------------------------------ // ConceptDecl @@ -3348,9 +3389,8 @@ traverseDecl( { MRDOCS_ASSERT(D); - // Decl had a semantic error or is implicitly - // generated by the implementation - if(D->isInvalidDecl() || D->isImplicit()) + // Decl had a semantic error + if(D->isInvalidDecl()) return; SymbolFilter::FilterScope scope(symbolFilter_); diff --git a/src/lib/Gen/xml/XMLWriter.cpp b/src/lib/Gen/xml/XMLWriter.cpp index 281beffa4..2fe765524 100644 --- a/src/lib/Gen/xml/XMLWriter.cpp +++ b/src/lib/Gen/xml/XMLWriter.cpp @@ -566,6 +566,7 @@ writeField( {"id", "is-mutable"} }); + writeAttr(I.IsVariant, "is-variant", tags_); writeAttr(I.IsMaybeUnused, "maybe-unused", tags_); writeAttr(I.IsDeprecated, "deprecated", tags_); writeAttr(I.HasNoUniqueAddress, "no-unique-address", tags_); diff --git a/src/lib/Metadata/DomMetadata.cpp b/src/lib/Metadata/DomMetadata.cpp index 543708d05..92c9d283d 100644 --- a/src/lib/Metadata/DomMetadata.cpp +++ b/src/lib/Metadata/DomMetadata.cpp @@ -851,6 +851,7 @@ DomInfo::construct() const { "default", dom::stringOrNull(I_.Default.Written) }, { "isMaybeUnused", I_.IsMaybeUnused }, { "isDeprecated", I_.IsDeprecated }, + { "isVariant", I_.IsVariant }, { "isMutable", I_.IsMutable }, { "isBitfield", I_.IsBitfield }, { "hasNoUniqueAddress", I_.HasNoUniqueAddress } diff --git a/src/lib/Metadata/Reduce.cpp b/src/lib/Metadata/Reduce.cpp index e31e62de5..c0cefc450 100644 --- a/src/lib/Metadata/Reduce.cpp +++ b/src/lib/Metadata/Reduce.cpp @@ -292,6 +292,7 @@ void merge(FieldInfo& I, FieldInfo&& Other) mergeExprInfo(I.BitfieldWidth, std::move(Other.BitfieldWidth)); + I.IsVariant |= Other.IsVariant; I.IsMutable |= Other.IsMutable; I.IsMaybeUnused |= Other.IsMaybeUnused; I.IsDeprecated |= Other.IsDeprecated; diff --git a/test-files/golden-tests/union.cpp b/test-files/golden-tests/union.cpp new file mode 100644 index 000000000..7541d180e --- /dev/null +++ b/test-files/golden-tests/union.cpp @@ -0,0 +1,16 @@ +union A +{ + int x; + bool y; +}; + +struct B +{ + union + { + int x; + bool y; + }; + + int z; +}; diff --git a/test-files/golden-tests/union.xml b/test-files/golden-tests/union.xml new file mode 100644 index 000000000..671e5d130 --- /dev/null +++ b/test-files/golden-tests/union.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +