Repository: CastXML/CastXML (language: python)

Issue:
Add support for elaborated type specifiers
Elaborated type specifiers may be used to refer to a previously-declared
class name (class, struct, or union) or to a previously-declared enum name.

These type specifiers are important for C code, but are also sometimes
relavant in the context of C++ code.

This patch adds the ElaboratedType xml node.

The castxml output format version number was updated to 1.1.0.

A test was added to demonstrate the purpose of this change (test/input/Elaborated.cxx).


Discussion / hints:
@bradking I rebased the branch and fixed the conflicts.
Done:
- newline added
- if condition for elaborated type was moved back to the case block
- the difference between c++98 and c++11 was due to the throw attributes. I merged both files and am using `( throw="")?` now.
- I added a test file with the output for the old file format
Thanks.  I updated your branch with a couple tweaks.  Please reset your local checkout.

You are right about the original purpose of this pull request. I added a check in Output.cxx, to filter out just the elaborated type specifiers we are interested in.

These 2 test have been reset to their original state (they are unmodified now): `Class-template-member-nontemplate-Typedef` and `qualified-type-name`.

I have also rebased on master. I do not remember if I pulled your tweaks, this was 7 days ago and I already checked out the code, but did not touch it since then. I just thought about it when force pushing. Please double check if I didn't remove your changes. If it is the case, I do apologise for this.
Thanks.  It looks like you did preserve my updates.

I updated your branch to revise the commit message.

Great :) Now I will have some work to do to add all this to pygccxml :)
Nice work!

Fix patch:
diff --git a/doc/manual/castxml.1.rst b/doc/manual/castxml.1.rst
index 06539786..5b185c26 100644
--- a/doc/manual/castxml.1.rst
+++ b/doc/manual/castxml.1.rst
@@ -105,7 +105,7 @@ The XML root element tag will be of the form:
 
 .. code-block:: xml
 
-  <CastXML format="1.3.0">
+  <CastXML format="1.4.0">
 
 * The first component is the ``epic`` format version number given to the
   ``--castxml-output=<v>`` flag, and currently must always be ``1``.
diff --git a/doc/manual/castxml.xsd b/doc/manual/castxml.xsd
index 3c690df8..e2123c50 100644
--- a/doc/manual/castxml.xsd
+++ b/doc/manual/castxml.xsd
@@ -49,6 +49,17 @@
     </xs:restriction>
   </xs:simpleType>
 
+  <xs:simpleType name="elaboration-keyword">
+    <xs:restriction base="xs:token">
+      <xs:enumeration value="enum" />
+      <xs:enumeration value="union" />
+      <xs:enumeration value="class" />
+      <xs:enumeration value="struct" />
+      <xs:enumeration value="typename" />
+      <xs:enumeration value="__interface" />
+    </xs:restriction>
+  </xs:simpleType>
+
   <xs:attributeGroup name="abi">
     <xs:attribute name="size" type="xs:unsignedLong" />
     <xs:attribute name="align" type="xs:unsignedLong" />
@@ -393,6 +404,8 @@
         <xs:complexType>
           <xs:attribute name="id" type="xs:ID" />
           <xs:attribute name="type" type="xs:IDREF" />
+          <xs:attribute name="keyword" type="elaboration-keyword" use="optional" />
+          <xs:attribute name="qualifier" type="name" use="optional" />
         </xs:complexType>
       </xs:element>
 
diff --git a/src/Output.cxx b/src/Output.cxx
index bfcf483e..92cf4421 100644
--- a/src/Output.cxx
+++ b/src/Output.cxx
@@ -29,6 +29,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/Mangle.h"
+#include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/Basic/FileManager.h"
@@ -782,13 +783,19 @@ ASTVisitor::DumpId ASTVisitor::AddTypeDumpNode(DumpType dt, bool complete,
                                      complete, dq);
       }
       break;
-    case clang::Type::Elaborated:
-      if (this->Opts.GccXml || !t->isElaboratedTypeSpecifier()) {
-        return this->AddTypeDumpNode(
-          DumpType(t->getAs<clang::ElaboratedType>()->getNamedType(), c),
-          complete, dq);
+    case clang::Type::Elaborated: {
+      clang::ElaboratedType const* et = t->getAs<clang::ElaboratedType>();
+      if (this->Opts.GccXml ||
+          (et->getKeyword() == clang::ETK_None && !et->getQualifier())) {
+        // The gccxml format does not include ElaboratedType elements,
+        // so replace this one with the underlying type.  Note that this
+        // can cause duplicate PointerType and ReferenceType elements
+        // to appear in the output: each copy corresponds to a different
+        // ElaboratedType, but the gccxml format cannot express this.
+        return this->AddTypeDumpNode(DumpType(et->getNamedType(), c), complete,
+                                     dq);
       }
-      break;
+    } break;
     case clang::Type::Enum:
       return this->AddDeclDumpNodeForType(
         t->getAs<clang::EnumType>()->getDecl(), complete, dq);
@@ -1930,7 +1937,9 @@ void ASTVisitor::OutputRecordDecl(clang::RecordDecl const* d,
   if (!d->isAnonymousStructOrUnion() && !d->isLambda()) {
     std::string s;
     llvm::raw_string_ostream rso(s);
-    d->getNameForDiagnostic(rso, this->PrintingPolicy, false);
+    if (d->getIdentifier()) {
+      d->getNameForDiagnostic(rso, this->PrintingPolicy, false);
+    }
     this->PrintNameAttribute(rso.str());
   }
   clang::AccessSpecifier access = clang::AS_none;
@@ -2388,7 +2397,22 @@ void ASTVisitor::OutputElaboratedType(clang::ElaboratedType const* t,
 {
   this->OS << "  <ElaboratedType";
   this->PrintIdAttribute(dn);
-  this->PrintTypeAttribute(t->getNamedType(), false);
+
+  if (clang::NestedNameSpecifier* nns = t->getQualifier()) {
+    std::string s;
+    llvm::raw_string_ostream rso(s);
+    nns->print(rso, this->PrintingPolicy);
+    this->OS << " qualifier=\"" << encodeXML(rso.str()) << '"';
+  }
+
+  clang::ElaboratedTypeKeyword k = t->getKeyword();
+  if (k != clang::ETK_None) {
+    this->OS << " keyword=\""
+             << encodeXML(clang::TypeWithKeyword::getKeywordName(k).str())
+             << '"';
+  }
+
+  this->PrintTypeAttribute(t->getNamedType(), dn->Complete);
   this->OS << "/>\n";
 }
 
@@ -2403,7 +2427,7 @@ void ASTVisitor::OutputStartXMLTags()
     // Start dump with castxml-compatible format.
     /* clang-format off */
     this->OS <<
-      "<CastXML format=\"" << Opts.CastXmlEpicFormatVersion << ".3.1\">\n"
+      "<CastXML format=\"" << Opts.CastXmlEpicFormatVersion << ".4.0\">\n"
       ;
     /* clang-format on */
   } else if (this->Opts.GccXml) {


Test patch:
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 648ea3cf..fd91e471 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -489,6 +489,7 @@ castxml_test_output(Destructor)
 castxml_test_output(Destructor-annotate)
 castxml_test_output(Destructor-deprecated)
 castxml_test_output(Elaborated)
+castxml_test_output(Elaborated-ns)
 castxml_test_output(Enumeration)
 castxml_test_output(Enumeration-annotate)
 castxml_test_output(Enumeration-annotate-multi)
diff --git a/test/expect/castxml1.any.Atomic-struct.xml.txt b/test/expect/castxml1.any.Atomic-struct.xml.txt
index 06b2f065..d24b10d7 100644
--- a/test/expect/castxml1.any.Atomic-struct.xml.txt
+++ b/test/expect/castxml1.any.Atomic-struct.xml.txt
@@ -3,7 +3,7 @@
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:3" file="f1" line="3"/>
   <AtomicType id="_2" type="_4" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
-  <ElaboratedType id="_4" type="_5"/>
+  <ElaboratedType id="_4" keyword="struct" type="_5"/>
   <Struct id="_5" name="" context="_3" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/Atomic-struct.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.any.Class-friends.xml.txt b/test/expect/castxml1.any.Class-friends.xml.txt
index 39e74156..6c07d1c5 100644
--- a/test/expect/castxml1.any.Class-friends.xml.txt
+++ b/test/expect/castxml1.any.Class-friends.xml.txt
@@ -14,7 +14,7 @@
   <ReferenceType id="_10" type="_1" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_2" name="::"/>
   <Function id="_7" name="f" returns="_11" context="_2" location="f1:4" file="f1" line="4" mangled="[^"]+"/>
-  <ElaboratedType id="_8" type="_12"/>
+  <ElaboratedType id="_8" keyword="class" type="_12"/>
   <FundamentalType id="_11" name="void" size="[0-9]+" align="[0-9]+"/>
   <Class id="_12" name="A" context="_2" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/Class-friends.cxx"/>
diff --git a/test/expect/castxml1.any.Class-member-Struct-anonymous.xml.txt b/test/expect/castxml1.any.Class-member-Struct-anonymous.xml.txt
index c6eb70d7..4502ec0d 100644
--- a/test/expect/castxml1.any.Class-member-Struct-anonymous.xml.txt
+++ b/test/expect/castxml1.any.Class-member-Struct-anonymous.xml.txt
@@ -19,7 +19,7 @@
     <Argument type="_16" location="f1:3" file="f1" line="3"/>
   </OperatorMethod>
   <Destructor id="_12" name="" context="_3" access="public" location="f1:3" file="f1" line="3" inline="1" artificial="1"( throw="")?/>
-  <ElaboratedType id="_13" type="_3"/>
+  <ElaboratedType id="_13" keyword="struct" type="_3"/>
   <ReferenceType id="_14" type="_1c" size="[0-9]+" align="[0-9]+"/>
   <CvQualifiedType id="_1c" type="_1" const="1"/>
   <ReferenceType id="_15" type="_1" size="[0-9]+" align="[0-9]+"/>
diff --git a/test/expect/castxml1.any.Class-member-Union-anonymous.xml.txt b/test/expect/castxml1.any.Class-member-Union-anonymous.xml.txt
index 52c6fb9a..3989aa42 100644
--- a/test/expect/castxml1.any.Class-member-Union-anonymous.xml.txt
+++ b/test/expect/castxml1.any.Class-member-Union-anonymous.xml.txt
@@ -19,7 +19,7 @@
     <Argument type="_16" location="f1:3" file="f1" line="3"/>
   </OperatorMethod>
   <Destructor id="_12" name="" context="_3" access="public" location="f1:3" file="f1" line="3" inline="1" artificial="1"( throw="")?/>
-  <ElaboratedType id="_13" type="_3"/>
+  <ElaboratedType id="_13" keyword="union" type="_3"/>
   <ReferenceType id="_14" type="_1c" size="[0-9]+" align="[0-9]+"/>
   <CvQualifiedType id="_1c" type="_1" const="1"/>
   <ReferenceType id="_15" type="_1" size="[0-9]+" align="[0-9]+"/>
diff --git a/test/expect/castxml1.any.Class-template-friends.xml.txt b/test/expect/castxml1.any.Class-template-friends.xml.txt
index 6013aa90..75ad7371 100644
--- a/test/expect/castxml1.any.Class-template-friends.xml.txt
+++ b/test/expect/castxml1.any.Class-template-friends.xml.txt
@@ -16,7 +16,7 @@
   <Function id="_7" name="f" returns="_11" context="_2" location="f1:9" file="f1" line="9" mangled="[^"]+">
     <Argument type="_11" location="f1:4" file="f1" line="4"/>
   </Function>
-  <ElaboratedType id="_8" type="_12"/>
+  <ElaboratedType id="_8" keyword="class" type="_12"/>
   <FundamentalType id="_11" name="int" size="[0-9]+" align="[0-9]+"/>
   <Class id="_12" name="A&lt;int&gt;" context="_2" location="f1:2" file="f1" line="2" incomplete="1"/>
   <File id="f1" name=".*/test/input/Class-template-friends.cxx"/>
diff --git a/test/expect/castxml1.any.Class-template-member-nontemplate-Typedef.xml.txt b/test/expect/castxml1.any.Class-template-member-nontemplate-Typedef.xml.txt
index 5a53d7c2..df27e161 100644
--- a/test/expect/castxml1.any.Class-template-member-nontemplate-Typedef.xml.txt
+++ b/test/expect/castxml1.any.Class-template-member-nontemplate-Typedef.xml.txt
@@ -1,10 +1,11 @@
 ^<\?xml version="1.0"\?>
 <CastXML[^>]*>
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:10" file="f1" line="10"/>
-  <Typedef id="_2" name="type" type="_4" context="_5" access="public" location="f1:7" file="f1" line="7"/>
-  <FundamentalType id="_4" name="int" size="[0-9]+" align="[0-9]+"/>
+  <ElaboratedType id="_2" qualifier="A&lt;int&gt;::B::" type="_4"/>
+  <Typedef id="_4" name="type" type="_5" context="_6" access="public" location="f1:7" file="f1" line="7"/>
+  <FundamentalType id="_5" name="int" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
-  <Struct id="_5" name="B" context="_6" access="public" location="f1:4" file="f1" line="4" size="[0-9]+" align="[0-9]+"/>
-  <Struct id="_6" name="A&lt;int&gt;" context="_3" location="f1:2" file="f1" line="2" size="[0-9]+" align="[0-9]+"/>
+  <Struct id="_6" name="B" context="_7" access="public" location="f1:4" file="f1" line="4" size="[0-9]+" align="[0-9]+"/>
+  <Struct id="_7" name="A&lt;int&gt;" context="_3" location="f1:2" file="f1" line="2" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/Class-template-member-nontemplate-Typedef.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.any.Elaborated-ns.xml.txt b/test/expect/castxml1.any.Elaborated-ns.xml.txt
new file mode 100644
index 00000000..a1ad2830
--- /dev/null
+++ b/test/expect/castxml1.any.Elaborated-ns.xml.txt
@@ -0,0 +1,13 @@
+^<\?xml version="1.0"\?>
+<CastXML[^>]*>
+  <Namespace id="_1" name="start" context="_2" members="_3 _4"/>
+  <Class id="_3" name="A" context="_1" location="f1:2" file="f1" line="2" incomplete="1"/>
+  <Function id="_4" name="f" returns="_5" context="_1" location="f1:3" file="f1" line="3" mangled="[^"]+">
+    <Argument type="_6" location="f1:3" file="f1" line="3"/>
+  </Function>
+  <PointerType id="_5" type="_7" size="[0-9]+" align="[0-9]+"/>
+  <PointerType id="_6" type="_3" size="[0-9]+" align="[0-9]+"/>
+  <Namespace id="_2" name="::"/>
+  <ElaboratedType id="_7" qualifier="start::" type="_3"/>
+  <File id="f1" name=".*/test/input/Elaborated-ns.cxx"/>
+</CastXML>$
diff --git a/test/expect/castxml1.any.Elaborated.xml.txt b/test/expect/castxml1.any.Elaborated.xml.txt
index 5bb32c64..3823cc25 100644
--- a/test/expect/castxml1.any.Elaborated.xml.txt
+++ b/test/expect/castxml1.any.Elaborated.xml.txt
@@ -91,9 +91,9 @@
   <ReferenceType id="_66" type="_24" size="[0-9]+" align="[0-9]+"/>
   <CvQualifiedType id="_67c" type="_67" const="1"/>
   <Namespace id="_2" name="::"/>
-  <ElaboratedType id="_60" type="_3"/>
-  <ElaboratedType id="_61" type="_10"/>
-  <ElaboratedType id="_64" type="_17"/>
-  <ElaboratedType id="_67" type="_24"/>
+  <ElaboratedType id="_60" keyword="struct" type="_3"/>
+  <ElaboratedType id="_61" keyword="enum" type="_10"/>
+  <ElaboratedType id="_64" keyword="union" type="_17"/>
+  <ElaboratedType id="_67" keyword="class" type="_24"/>
   <File id="f1" name=".*/test/input/Elaborated.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.any.Typedef-to-Enumeration-anonymous.xml.txt b/test/expect/castxml1.any.Typedef-to-Enumeration-anonymous.xml.txt
index 61b48fc8..58fec36e 100644
--- a/test/expect/castxml1.any.Typedef-to-Enumeration-anonymous.xml.txt
+++ b/test/expect/castxml1.any.Typedef-to-Enumeration-anonymous.xml.txt
@@ -1,9 +1,9 @@
 ^<\?xml version="1.0"\?>
 <CastXML[^>]*>
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:3" file="f1" line="3"/>
-  <ElaboratedType id="_2" type="_4"/>
-  <Namespace id="_3" name="::"/>
+  <ElaboratedType id="_2" keyword="enum" type="_4"/>
   <Enumeration id="_4" name="start" type="_5" context="_3" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <FundamentalType id="_5" name="(unsigned )?int" size="[0-9]+" align="[0-9]+"/>
+  <Namespace id="_3" name="::"/>
   <File id="f1" name=".*/test/input/Typedef-to-Enumeration-anonymous.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.any.Typedef-to-Struct-anonymous.xml.txt b/test/expect/castxml1.any.Typedef-to-Struct-anonymous.xml.txt
index 28ee047c..580472db 100644
--- a/test/expect/castxml1.any.Typedef-to-Struct-anonymous.xml.txt
+++ b/test/expect/castxml1.any.Typedef-to-Struct-anonymous.xml.txt
@@ -1,8 +1,19 @@
 ^<\?xml version="1.0"\?>
 <CastXML[^>]*>
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:3" file="f1" line="3"/>
-  <ElaboratedType id="_2" type="_4"/>
+  <ElaboratedType id="_2" keyword="struct" type="_4"/>
+  <Struct id="_4" name="" context="_3" location="f1:1" file="f1" line="1" members="_5 _6 _7 _8" size="[0-9]+" align="[0-9]+"/>
+  <Constructor id="_5" name="" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")?/>
+  <Constructor id="_6" name="" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")?>
+    <Argument type="_9" location="f1:1" file="f1" line="1"/>
+  </Constructor>
+  <OperatorMethod id="_7" name="=" returns="_10" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")? mangled="[^"]+">
+    <Argument type="_9" location="f1:1" file="f1" line="1"/>
+  </OperatorMethod>
+  <Destructor id="_8" name="" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")?/>
+  <ReferenceType id="_9" type="_4c" size="[0-9]+" align="[0-9]+"/>
+  <CvQualifiedType id="_4c" type="_4" const="1"/>
+  <ReferenceType id="_10" type="_4" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
-  <Struct id="_4" name="" context="_3" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/Typedef-to-Struct-anonymous.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.any.Typedef-to-Union-anonymous.xml.txt b/test/expect/castxml1.any.Typedef-to-Union-anonymous.xml.txt
index 39294a07..6a949a74 100644
--- a/test/expect/castxml1.any.Typedef-to-Union-anonymous.xml.txt
+++ b/test/expect/castxml1.any.Typedef-to-Union-anonymous.xml.txt
@@ -1,8 +1,19 @@
 ^<\?xml version="1.0"\?>
 <CastXML[^>]*>
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:3" file="f1" line="3"/>
-  <ElaboratedType id="_2" type="_4"/>
+  <ElaboratedType id="_2" keyword="union" type="_4"/>
+  <Union id="_4" name="" context="_3" location="f1:1" file="f1" line="1" members="_5 _6 _7 _8" size="[0-9]+" align="[0-9]+"/>
+  <Constructor id="_5" name="" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")?/>
+  <Constructor id="_6" name="" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")?>
+    <Argument type="_9" location="f1:1" file="f1" line="1"/>
+  </Constructor>
+  <OperatorMethod id="_7" name="=" returns="_10" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")? mangled="[^"]+">
+    <Argument type="_9" location="f1:1" file="f1" line="1"/>
+  </OperatorMethod>
+  <Destructor id="_8" name="" context="_4" access="public" location="f1:1" file="f1" line="1" inline="1" artificial="1"( throw="")?/>
+  <ReferenceType id="_9" type="_4c" size="[0-9]+" align="[0-9]+"/>
+  <CvQualifiedType id="_4c" type="_4" const="1"/>
+  <ReferenceType id="_10" type="_4" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
-  <Union id="_4" name="" context="_3" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/Typedef-to-Union-anonymous.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.any.qualified-type-name.xml.txt b/test/expect/castxml1.any.qualified-type-name.xml.txt
index d1d4ea43..c231fdd7 100644
--- a/test/expect/castxml1.any.qualified-type-name.xml.txt
+++ b/test/expect/castxml1.any.qualified-type-name.xml.txt
@@ -1,9 +1,10 @@
 ^<\?xml version="1.0"\?>
 <CastXML[^>]*>
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:4" file="f1" line="4"/>
-  <Typedef id="_2" name="type" type="_4" context="_5" location="f1:2" file="f1" line="2"/>
-  <FundamentalType id="_4" name="int" size="[0-9]+" align="[0-9]+"/>
+  <ElaboratedType id="_2" qualifier="ns::" type="_4"/>
+  <Typedef id="_4" name="type" type="_5" context="_6" location="f1:2" file="f1" line="2"/>
+  <FundamentalType id="_5" name="int" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
-  <Namespace id="_5" name="ns" context="_3"/>
+  <Namespace id="_6" name="ns" context="_3"/>
   <File id="f1" name=".*/test/input/qualified-type-name.cxx"/>
 </CastXML>$
diff --git a/test/expect/castxml1.c.Atomic-struct.xml.txt b/test/expect/castxml1.c.Atomic-struct.xml.txt
index 2bda2ed4..2cb4d57f 100644
--- a/test/expect/castxml1.c.Atomic-struct.xml.txt
+++ b/test/expect/castxml1.c.Atomic-struct.xml.txt
@@ -3,7 +3,7 @@
   <Typedef id="_1" name="start" type="_2" context="_3" location="f1:3" file="f1" line="3"/>
   <AtomicType id="_2" type="_4" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
-  <ElaboratedType id="_4" type="_5"/>
+  <ElaboratedType id="_4" keyword="struct" type="_5"/>
   <Struct id="_5" name="" context="_3" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/Atomic-struct.c"/>
 </CastXML>$
diff --git a/test/expect/castxml1.c.GNU-attr-malloc-args.xml.txt b/test/expect/castxml1.c.GNU-attr-malloc-args.xml.txt
index c80c6b6f..44ab8560 100644
--- a/test/expect/castxml1.c.GNU-attr-malloc-args.xml.txt
+++ b/test/expect/castxml1.c.GNU-attr-malloc-args.xml.txt
@@ -4,7 +4,7 @@
   <PointerType id="_2" type="_4" size="[0-9]+" align="[0-9]+"/>
   <Namespace id="_3" name="::"/>
   <Typedef id="_4" name="foo" type="_5" context="_3" location="f1:3" file="f1" line="3"/>
-  <ElaboratedType id="_5" type="_6"/>
+  <ElaboratedType id="_5" keyword="struct" type="_6"/>
   <Struct id="_6" name="foo_s" context="_3" location="f1:1" file="f1" line="1" size="[0-9]+" align="[0-9]+"/>
   <File id="f1" name=".*/test/input/GNU-attr-malloc-args.c"/>
 </CastXML>$
diff --git a/test/expect/gccxml.any.Elaborated-ns.xml.txt b/test/expect/gccxml.any.Elaborated-ns.xml.txt
new file mode 100644
index 00000000..af4b33f8
--- /dev/null
+++ b/test/expect/gccxml.any.Elaborated-ns.xml.txt
@@ -0,0 +1,12 @@
+^<\?xml version="1.0"\?>
+<GCC_XML[^>]*>
+  <Namespace id="_1" name="start" context="_2" members="_3 _4"/>
+  <Class id="_3" name="A" context="_1" location="f1:2" file="f1" line="2" incomplete="1"/>
+  <Function id="_4" name="f" returns="_5" context="_1" location="f1:3" file="f1" line="3" mangled="[^"]+">
+    <Argument type="_6" location="f1:3" file="f1" line="3"/>
+  </Function>
+  <PointerType id="_5" type="_3" size="[0-9]+" align="[0-9]+"/>
+  <PointerType id="_6" type="_3" size="[0-9]+" align="[0-9]+"/>
+  <Namespace id="_2" name="::"/>
+  <File id="f1" name=".*/test/input/Elaborated-ns.cxx"/>
+</GCC_XML>$
diff --git a/test/input/Elaborated-ns.cxx b/test/input/Elaborated-ns.cxx
new file mode 100644
index 00000000..b455694a
--- /dev/null
+++ b/test/input/Elaborated-ns.cxx
@@ -0,0 +1,4 @@
+namespace start {
+class A;
+start::A* f(A*);
+}
diff --git a/test/input/assume_aligned.cxx b/test/input/assume_aligned.cxx
index a6e9dc2d..e9c0b54d 100644
--- a/test/input/assume_aligned.cxx
+++ b/test/input/assume_aligned.cxx
@@ -1,3 +1,4 @@
+#pragma clang diagnostic ignored "-Wundefined-inline"
 constexpr void* __cdecl __builtin_assume_aligned(const void*, size_t,
                                                  ...) noexcept;