| //===--- DeclXML.cpp - XML implementation for Decl ASTs -------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the XML document class, which provides the means to |
| // dump out the AST in a XML form that exposes type details and other fields. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Frontend/DocumentXML.h" |
| #include "clang/AST/DeclVisitor.h" |
| #include "clang/AST/Expr.h" |
| |
| namespace clang { |
| |
| //--------------------------------------------------------- |
| class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { |
| DocumentXML& Doc; |
| |
| void addSubNodes(FunctionDecl* FD) { |
| for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { |
| Visit(FD->getParamDecl(i)); |
| Doc.toParent(); |
| } |
| } |
| |
| void addFunctionBody(FunctionDecl* FD) { |
| if (FD->isThisDeclarationADefinition()) { |
| Doc.addSubNode("Body"); |
| Doc.PrintStmt(FD->getBody()); |
| Doc.toParent(); |
| } |
| } |
| |
| void addSubNodes(RecordDecl* RD) { |
| for (RecordDecl::field_iterator i = RD->field_begin(), |
| e = RD->field_end(); i != e; ++i) { |
| Visit(*i); |
| Doc.toParent(); |
| } |
| } |
| |
| void addSubNodes(CXXRecordDecl* RD) { |
| addSubNodes(cast<RecordDecl>(RD)); |
| |
| if (RD->isDefinition()) { |
| // FIXME: This breaks XML generation |
| //Doc.addAttribute("num_bases", RD->getNumBases()); |
| |
| for (CXXRecordDecl::base_class_iterator |
| base = RD->bases_begin(), |
| bend = RD->bases_end(); |
| base != bend; |
| ++base) { |
| Doc.addSubNode("Base"); |
| Doc.addAttribute("id", base->getType()); |
| AccessSpecifier as = base->getAccessSpecifierAsWritten(); |
| const char* as_name = ""; |
| switch(as) { |
| case AS_none: as_name = ""; break; |
| case AS_public: as_name = "public"; break; |
| case AS_protected: as_name = "protected"; break; |
| case AS_private: as_name = "private"; break; |
| } |
| Doc.addAttributeOptional("access", as_name); |
| Doc.addAttribute("is_virtual", base->isVirtual()); |
| Doc.toParent(); |
| } |
| |
| for (CXXRecordDecl::method_iterator i = RD->method_begin(), |
| e = RD->method_end(); i != e; ++i) { |
| Visit(*i); |
| Doc.toParent(); |
| } |
| |
| } |
| |
| } |
| |
| void addSubNodes(EnumDecl* ED) { |
| for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(), |
| e = ED->enumerator_end(); i != e; ++i) { |
| Visit(*i); |
| Doc.toParent(); |
| } |
| } |
| |
| void addSubNodes(EnumConstantDecl* ECD) { |
| if (ECD->getInitExpr()) |
| Doc.PrintStmt(ECD->getInitExpr()); |
| } |
| |
| void addSubNodes(FieldDecl* FdD) { |
| if (FdD->isBitField()) |
| Doc.PrintStmt(FdD->getBitWidth()); |
| } |
| |
| void addSubNodes(VarDecl* V) { |
| if (V->getInit()) |
| Doc.PrintStmt(V->getInit()); |
| } |
| |
| void addSubNodes(ParmVarDecl* argDecl) { |
| if (argDecl->getDefaultArg()) |
| Doc.PrintStmt(argDecl->getDefaultArg()); |
| } |
| |
| void addSubNodes(NamespaceDecl* ns) { |
| |
| for (DeclContext::decl_iterator |
| d = ns->decls_begin(), |
| dend = ns->decls_end(); |
| d != dend; |
| ++d) { |
| Visit(*d); |
| Doc.toParent(); |
| } |
| } |
| |
| void addSpecialAttribute(const char* pName, EnumDecl* ED) { |
| const QualType& enumType = ED->getIntegerType(); |
| if (!enumType.isNull()) |
| Doc.addAttribute(pName, enumType); |
| } |
| |
| void addIdAttribute(LinkageSpecDecl* ED) { |
| Doc.addAttribute("id", ED); |
| } |
| |
| void addIdAttribute(NamedDecl* ND) { |
| Doc.addAttribute("id", ND); |
| } |
| |
| public: |
| DeclPrinter(DocumentXML& doc) : Doc(doc) {} |
| |
| #define NODE_XML( CLASS, NAME ) \ |
| void Visit##CLASS(CLASS* T) \ |
| { \ |
| Doc.addSubNode(NAME); |
| |
| #define ID_ATTRIBUTE_XML addIdAttribute(T); |
| #define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); |
| #define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); |
| #define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation()); |
| #define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T); |
| |
| #define ATTRIBUTE_ENUM_XML( FN, NAME ) \ |
| { \ |
| const char* pAttributeName = NAME; \ |
| const bool optional = false; \ |
| switch (T->FN) { \ |
| default: assert(0 && "unknown enum value"); |
| |
| #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ |
| { \ |
| const char* pAttributeName = NAME; \ |
| const bool optional = true; \ |
| switch (T->FN) { \ |
| default: assert(0 && "unknown enum value"); |
| |
| #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; |
| #define END_ENUM_XML } } |
| #define END_NODE_XML } |
| |
| #define SUB_NODE_XML( CLASS ) addSubNodes(T); |
| #define SUB_NODE_SEQUENCE_XML( CLASS ) addSubNodes(T); |
| #define SUB_NODE_OPT_XML( CLASS ) addSubNodes(T); |
| |
| #define SUB_NODE_FN_BODY_XML addFunctionBody(T); |
| |
| #include "clang/Frontend/DeclXML.def" |
| }; |
| |
| |
| //--------------------------------------------------------- |
| void DocumentXML::writeDeclToXML(Decl *D) { |
| DeclPrinter(*this).Visit(D); |
| toParent(); |
| } |
| |
| //--------------------------------------------------------- |
| } // NS clang |
| |