//===--- StmtXML.cpp - XML implementation for Stmt 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 Stmt::dumpXML methods, which dump out the // AST to an XML document. // //===----------------------------------------------------------------------===// #include "clang/Frontend/DocumentXML.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" using namespace clang; //===----------------------------------------------------------------------===// // StmtXML Visitor //===----------------------------------------------------------------------===// namespace { class VISIBILITY_HIDDEN StmtXML : public StmtVisitor { DocumentXML& Doc; //static const char *getOpcodeStr(UnaryOperator::Opcode Op); //static const char *getOpcodeStr(BinaryOperator::Opcode Op); void addSpecialAttribute(const char* pName, StringLiteral* Str) { Doc.addAttribute(pName, Doc.escapeString(Str->getStrData(), Str->getByteLength())); } void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) { if (S->isArgumentType()) Doc.addAttribute(pName, S->getArgumentType()); } void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) { if (S->isTypeOperand()) Doc.addAttribute(pName, S->getTypeOperand()); } public: StmtXML(DocumentXML& doc) : Doc(doc) { } void DumpSubTree(Stmt *S) { if (S) { Visit(S); if (DeclStmt* DS = dyn_cast(S)) { for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); DI != DE; ++DI) { Doc.PrintDecl(*DI); } } else { if (CXXConditionDeclExpr* CCDE = dyn_cast(S)) Doc.PrintDecl(CCDE->getVarDecl()); for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i) DumpSubTree(*i); } Doc.toParent(); } else { Doc.addSubNode("NULL").toParent(); } } #define NODE_XML( CLASS, NAME ) \ void Visit##CLASS(CLASS* S) \ { \ typedef CLASS tStmtType; \ Doc.addSubNode(NAME); #define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN); #define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") #define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN); #define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S); #define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange()); #define ATTRIBUTE_ENUM_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = false; \ switch (S->FN) { \ default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (S->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 ID_ATTRIBUTE_XML Doc.addAttribute("id", S); #define SUB_NODE_XML( CLASS ) #define SUB_NODE_SEQUENCE_XML( CLASS ) #define SUB_NODE_OPT_XML( CLASS ) #include "clang/Frontend/StmtXML.def" #if (0) // Stmts. void VisitStmt(Stmt *Node); void VisitDeclStmt(DeclStmt *Node); void VisitLabelStmt(LabelStmt *Node); void VisitGotoStmt(GotoStmt *Node); // Exprs void VisitExpr(Expr *Node); void VisitDeclRefExpr(DeclRefExpr *Node); void VisitPredefinedExpr(PredefinedExpr *Node); void VisitCharacterLiteral(CharacterLiteral *Node); void VisitIntegerLiteral(IntegerLiteral *Node); void VisitFloatingLiteral(FloatingLiteral *Node); void VisitStringLiteral(StringLiteral *Str); void VisitUnaryOperator(UnaryOperator *Node); void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); void VisitMemberExpr(MemberExpr *Node); void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); void VisitBinaryOperator(BinaryOperator *Node); void VisitCompoundAssignOperator(CompoundAssignOperator *Node); void VisitAddrLabelExpr(AddrLabelExpr *Node); void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); // C++ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); void VisitCXXThisExpr(CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); // ObjC void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); void VisitObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); void VisitObjCSuperExpr(ObjCSuperExpr *Node); #endif }; } //===----------------------------------------------------------------------===// // Stmt printing methods. //===----------------------------------------------------------------------===// #if (0) void StmtXML::VisitStmt(Stmt *Node) { // nothing special to do } void StmtXML::VisitDeclStmt(DeclStmt *Node) { for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); DI != DE; ++DI) { Doc.PrintDecl(*DI); } } void StmtXML::VisitLabelStmt(LabelStmt *Node) { Doc.addAttribute("name", Node->getName()); } void StmtXML::VisitGotoStmt(GotoStmt *Node) { Doc.addAttribute("name", Node->getLabel()->getName()); } //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// void StmtXML::VisitExpr(Expr *Node) { DumpExpr(Node); } void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); const char* pKind; switch (Node->getDecl()->getKind()) { case Decl::Function: pKind = "FunctionDecl"; break; case Decl::Var: pKind = "Var"; break; case Decl::ParmVar: pKind = "ParmVar"; break; case Decl::EnumConstant: pKind = "EnumConstant"; break; case Decl::Typedef: pKind = "Typedef"; break; case Decl::Record: pKind = "Record"; break; case Decl::Enum: pKind = "Enum"; break; case Decl::CXXRecord: pKind = "CXXRecord"; break; case Decl::ObjCInterface: pKind = "ObjCInterface"; break; case Decl::ObjCClass: pKind = "ObjCClass"; break; default: pKind = "Decl"; break; } Doc.addAttribute("kind", pKind); Doc.addAttribute("name", Node->getDecl()->getNameAsString()); Doc.addRefAttribute(Node->getDecl()); } void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) { DumpExpr(Node); switch (Node->getIdentType()) { default: assert(0 && "unknown case"); case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; } } void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) { DumpExpr(Node); Doc.addAttribute("value", Node->getValue()); } void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) { DumpExpr(Node); bool isSigned = Node->getType()->isSignedIntegerType(); Doc.addAttribute("value", Node->getValue().toString(10, isSigned)); } void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) { DumpExpr(Node); // FIXME: output float as written in source (no approximation or the like) //Doc.addAttribute("value", Node->getValueAsApproximateDouble())); Doc.addAttribute("value", "FIXME"); } void StmtXML::VisitStringLiteral(StringLiteral *Str) { DumpExpr(Str); if (Str->isWide()) Doc.addAttribute("is_wide", "1"); Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength())); } const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) { switch (Op) { default: assert(0 && "Unknown unary operator"); case UnaryOperator::PostInc: return "postinc"; case UnaryOperator::PostDec: return "postdec"; case UnaryOperator::PreInc: return "preinc"; case UnaryOperator::PreDec: return "predec"; case UnaryOperator::AddrOf: return "addrof"; case UnaryOperator::Deref: return "deref"; case UnaryOperator::Plus: return "plus"; case UnaryOperator::Minus: return "minus"; case UnaryOperator::Not: return "not"; case UnaryOperator::LNot: return "lnot"; case UnaryOperator::Real: return "__real"; case UnaryOperator::Imag: return "__imag"; case UnaryOperator::Extension: return "__extension__"; case UnaryOperator::OffsetOf: return "__builtin_offsetof"; } } const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) { switch (Op) { default: assert(0 && "Unknown binary operator"); case BinaryOperator::PtrMemD: return "ptrmemd"; case BinaryOperator::PtrMemI: return "ptrmemi"; case BinaryOperator::Mul: return "mul"; case BinaryOperator::Div: return "div"; case BinaryOperator::Rem: return "rem"; case BinaryOperator::Add: return "add"; case BinaryOperator::Sub: return "sub"; case BinaryOperator::Shl: return "shl"; case BinaryOperator::Shr: return "shr"; case BinaryOperator::LT: return "lt"; case BinaryOperator::GT: return "gt"; case BinaryOperator::LE: return "le"; case BinaryOperator::GE: return "ge"; case BinaryOperator::EQ: return "eq"; case BinaryOperator::NE: return "ne"; case BinaryOperator::And: return "and"; case BinaryOperator::Xor: return "xor"; case BinaryOperator::Or: return "or"; case BinaryOperator::LAnd: return "land"; case BinaryOperator::LOr: return "lor"; case BinaryOperator::Assign: return "assign"; case BinaryOperator::MulAssign: return "mulassign"; case BinaryOperator::DivAssign: return "divassign"; case BinaryOperator::RemAssign: return "remassign"; case BinaryOperator::AddAssign: return "addassign"; case BinaryOperator::SubAssign: return "subassign"; case BinaryOperator::ShlAssign: return "shlassign"; case BinaryOperator::ShrAssign: return "shrassign"; case BinaryOperator::AndAssign: return "andassign"; case BinaryOperator::XorAssign: return "xorassign"; case BinaryOperator::OrAssign: return "orassign"; case BinaryOperator::Comma: return "comma"; } } void StmtXML::VisitUnaryOperator(UnaryOperator *Node) { DumpExpr(Node); Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); } void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { DumpExpr(Node); Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof"); Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0"); if (Node->isArgumentType()) DumpTypeExpr(Node->getArgumentType()); } void StmtXML::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0"); Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString()); Doc.addRefAttribute(Node->getMemberDecl()); } void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { DumpExpr(Node); Doc.addAttribute("name", Node->getAccessor().getName()); } void StmtXML::VisitBinaryOperator(BinaryOperator *Node) { DumpExpr(Node); Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); } void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { VisitBinaryOperator(Node); /* FIXME: is this needed in the AST? DumpExpr(Node); CurrentNode = CurrentNode->addSubNode("ComputeLHSTy"); DumpType(Node->getComputationLHSType()); CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy"); DumpType(Node->getComputationResultType()); Doc.toParent(); */ } // GNU extensions. void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) { DumpExpr(Node); Doc.addAttribute("name", Node->getLabel()->getName()); } void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { DumpExpr(Node); DumpTypeExpr(Node->getArgType1()); DumpTypeExpr(Node->getArgType2()); } //===----------------------------------------------------------------------===// // C++ Expressions //===----------------------------------------------------------------------===// void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); Doc.addAttribute("kind", Node->getCastName()); DumpTypeExpr(Node->getTypeAsWritten()); } void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { DumpExpr(Node); Doc.addAttribute("value", Node->getValue() ? "true" : "false"); } void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) { DumpExpr(Node); } void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { DumpExpr(Node); DumpTypeExpr(Node->getTypeAsWritten()); } //===----------------------------------------------------------------------===// // Obj-C Expressions //===----------------------------------------------------------------------===// void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); Doc.addAttribute("selector", Node->getSelector().getAsString()); IdentifierInfo* clsName = Node->getClassName(); if (clsName) Doc.addAttribute("class", clsName->getName()); } void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { DumpExpr(Node); DumpTypeExpr(Node->getEncodedType()); } void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { DumpExpr(Node); Doc.addAttribute("selector", Node->getSelector().getAsString()); } void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString()); } void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); Doc.addAttribute("property", Node->getProperty()->getNameAsString()); } void StmtXML::VisitObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *Node) { DumpExpr(Node); ObjCMethodDecl *Getter = Node->getGetterMethod(); ObjCMethodDecl *Setter = Node->getSetterMethod(); Doc.addAttribute("Getter", Getter->getSelector().getAsString()); Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); } void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) { DumpExpr(Node); Doc.addAttribute("super", "1"); } void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); Doc.addAttribute("kind", Node->getDecl()->getDeclKindName()); Doc.addAttribute("decl", Node->getDecl()->getNameAsString()); if (Node->isFreeIvar()) Doc.addAttribute("isFreeIvar", "1"); } #endif //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void DocumentXML::PrintStmt(const Stmt *S) { StmtXML P(*this); P.DumpSubTree(const_cast(S)); }