| //===--- StmtPrinter.cpp - Printing 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::dumpPretty/Stmt::printPretty methods, which |
| // pretty print the AST back out to C code. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/StmtVisitor.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/PrettyPrinter.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/Streams.h" |
| #include "llvm/Support/Format.h" |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // StmtPrinter Visitor |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> { |
| llvm::raw_ostream &OS; |
| unsigned IndentLevel; |
| clang::PrinterHelper* Helper; |
| public: |
| StmtPrinter(llvm::raw_ostream &os, PrinterHelper* helper) : |
| OS(os), IndentLevel(0), Helper(helper) {} |
| |
| void PrintStmt(Stmt *S, int SubIndent = 1) { |
| IndentLevel += SubIndent; |
| if (S && isa<Expr>(S)) { |
| // If this is an expr used in a stmt context, indent and newline it. |
| Indent(); |
| Visit(S); |
| OS << ";\n"; |
| } else if (S) { |
| Visit(S); |
| } else { |
| Indent() << "<<<NULL STATEMENT>>>\n"; |
| } |
| IndentLevel -= SubIndent; |
| } |
| |
| void PrintRawCompoundStmt(CompoundStmt *S); |
| void PrintRawDecl(Decl *D); |
| void PrintRawDeclStmt(DeclStmt *S); |
| void PrintRawIfStmt(IfStmt *If); |
| void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); |
| |
| void PrintExpr(Expr *E) { |
| if (E) |
| Visit(E); |
| else |
| OS << "<null expr>"; |
| } |
| |
| llvm::raw_ostream &Indent(int Delta = 0) const { |
| for (int i = 0, e = IndentLevel+Delta; i < e; ++i) |
| OS << " "; |
| return OS; |
| } |
| |
| bool PrintOffsetOfDesignator(Expr *E); |
| void VisitUnaryOffsetOf(UnaryOperator *Node); |
| |
| void Visit(Stmt* S) { |
| if (Helper && Helper->handledStmt(S,OS)) |
| return; |
| else StmtVisitor<StmtPrinter>::Visit(S); |
| } |
| |
| void VisitStmt(Stmt *Node); |
| #define STMT(CLASS, PARENT) \ |
| void Visit##CLASS(CLASS *Node); |
| #include "clang/AST/StmtNodes.def" |
| }; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Stmt printing methods. |
| //===----------------------------------------------------------------------===// |
| |
| void StmtPrinter::VisitStmt(Stmt *Node) { |
| Indent() << "<<unknown stmt type>>\n"; |
| } |
| |
| /// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and |
| /// with no newline after the }. |
| void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { |
| OS << "{\n"; |
| for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); |
| I != E; ++I) |
| PrintStmt(*I); |
| |
| Indent() << "}"; |
| } |
| |
| void StmtPrinter::PrintRawDecl(Decl *D) { |
| // FIXME: Need to complete/beautify this... this code simply shows the |
| // nodes are where they need to be. |
| if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { |
| OS << "typedef " << localType->getUnderlyingType().getAsString(); |
| OS << " " << localType->getNameAsString(); |
| } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { |
| // Emit storage class for vardecls. |
| if (VarDecl *V = dyn_cast<VarDecl>(VD)) { |
| switch (V->getStorageClass()) { |
| default: assert(0 && "Unknown storage class!"); |
| case VarDecl::None: break; |
| case VarDecl::Extern: OS << "extern "; break; |
| case VarDecl::Static: OS << "static "; break; |
| case VarDecl::Auto: OS << "auto "; break; |
| case VarDecl::Register: OS << "register "; break; |
| } |
| } |
| |
| std::string Name = VD->getNameAsString(); |
| VD->getType().getAsStringInternal(Name); |
| OS << Name; |
| |
| // If this is a vardecl with an initializer, emit it. |
| if (VarDecl *V = dyn_cast<VarDecl>(VD)) { |
| if (V->getInit()) { |
| OS << " = "; |
| PrintExpr(V->getInit()); |
| } |
| } |
| } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { |
| // print a free standing tag decl (e.g. "struct x;"). |
| OS << TD->getKindName(); |
| OS << " "; |
| if (const IdentifierInfo *II = TD->getIdentifier()) |
| OS << II->getName(); |
| else |
| OS << "<anonymous>"; |
| // FIXME: print tag bodies. |
| } else { |
| assert(0 && "Unexpected decl"); |
| } |
| } |
| |
| void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { |
| bool isFirst = false; |
| |
| for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end(); |
| I != E; ++I) { |
| |
| if (!isFirst) OS << ", "; |
| else isFirst = false; |
| |
| PrintRawDecl(*I); |
| } |
| } |
| |
| void StmtPrinter::VisitNullStmt(NullStmt *Node) { |
| Indent() << ";\n"; |
| } |
| |
| void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { |
| for (DeclStmt::decl_iterator I = Node->decl_begin(), E = Node->decl_end(); |
| I!=E; ++I) { |
| Indent(); |
| PrintRawDecl(*I); |
| OS << ";\n"; |
| } |
| } |
| |
| void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) { |
| Indent(); |
| PrintRawCompoundStmt(Node); |
| OS << "\n"; |
| } |
| |
| void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { |
| Indent(-1) << "case "; |
| PrintExpr(Node->getLHS()); |
| if (Node->getRHS()) { |
| OS << " ... "; |
| PrintExpr(Node->getRHS()); |
| } |
| OS << ":\n"; |
| |
| PrintStmt(Node->getSubStmt(), 0); |
| } |
| |
| void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) { |
| Indent(-1) << "default:\n"; |
| PrintStmt(Node->getSubStmt(), 0); |
| } |
| |
| void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { |
| Indent(-1) << Node->getName() << ":\n"; |
| PrintStmt(Node->getSubStmt(), 0); |
| } |
| |
| void StmtPrinter::PrintRawIfStmt(IfStmt *If) { |
| OS << "if "; |
| PrintExpr(If->getCond()); |
| |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { |
| OS << ' '; |
| PrintRawCompoundStmt(CS); |
| OS << (If->getElse() ? ' ' : '\n'); |
| } else { |
| OS << '\n'; |
| PrintStmt(If->getThen()); |
| if (If->getElse()) Indent(); |
| } |
| |
| if (Stmt *Else = If->getElse()) { |
| OS << "else"; |
| |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) { |
| OS << ' '; |
| PrintRawCompoundStmt(CS); |
| OS << '\n'; |
| } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) { |
| OS << ' '; |
| PrintRawIfStmt(ElseIf); |
| } else { |
| OS << '\n'; |
| PrintStmt(If->getElse()); |
| } |
| } |
| } |
| |
| void StmtPrinter::VisitIfStmt(IfStmt *If) { |
| Indent(); |
| PrintRawIfStmt(If); |
| } |
| |
| void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { |
| Indent() << "switch ("; |
| PrintExpr(Node->getCond()); |
| OS << ")"; |
| |
| // Pretty print compoundstmt bodies (very common). |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { |
| OS << " "; |
| PrintRawCompoundStmt(CS); |
| OS << "\n"; |
| } else { |
| OS << "\n"; |
| PrintStmt(Node->getBody()); |
| } |
| } |
| |
| void StmtPrinter::VisitSwitchCase(SwitchCase*) { |
| assert(0 && "SwitchCase is an abstract class"); |
| } |
| |
| void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { |
| Indent() << "while ("; |
| PrintExpr(Node->getCond()); |
| OS << ")\n"; |
| PrintStmt(Node->getBody()); |
| } |
| |
| void StmtPrinter::VisitDoStmt(DoStmt *Node) { |
| Indent() << "do "; |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { |
| PrintRawCompoundStmt(CS); |
| OS << " "; |
| } else { |
| OS << "\n"; |
| PrintStmt(Node->getBody()); |
| Indent(); |
| } |
| |
| OS << "while "; |
| PrintExpr(Node->getCond()); |
| OS << ";\n"; |
| } |
| |
| void StmtPrinter::VisitForStmt(ForStmt *Node) { |
| Indent() << "for ("; |
| if (Node->getInit()) { |
| if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit())) |
| PrintRawDeclStmt(DS); |
| else |
| PrintExpr(cast<Expr>(Node->getInit())); |
| } |
| OS << ";"; |
| if (Node->getCond()) { |
| OS << " "; |
| PrintExpr(Node->getCond()); |
| } |
| OS << ";"; |
| if (Node->getInc()) { |
| OS << " "; |
| PrintExpr(Node->getInc()); |
| } |
| OS << ") "; |
| |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { |
| PrintRawCompoundStmt(CS); |
| OS << "\n"; |
| } else { |
| OS << "\n"; |
| PrintStmt(Node->getBody()); |
| } |
| } |
| |
| void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { |
| Indent() << "for ("; |
| if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getElement())) |
| PrintRawDeclStmt(DS); |
| else |
| PrintExpr(cast<Expr>(Node->getElement())); |
| OS << " in "; |
| PrintExpr(Node->getCollection()); |
| OS << ") "; |
| |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { |
| PrintRawCompoundStmt(CS); |
| OS << "\n"; |
| } else { |
| OS << "\n"; |
| PrintStmt(Node->getBody()); |
| } |
| } |
| |
| void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { |
| Indent() << "goto " << Node->getLabel()->getName() << ";\n"; |
| } |
| |
| void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) { |
| Indent() << "goto *"; |
| PrintExpr(Node->getTarget()); |
| OS << ";\n"; |
| } |
| |
| void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) { |
| Indent() << "continue;\n"; |
| } |
| |
| void StmtPrinter::VisitBreakStmt(BreakStmt *Node) { |
| Indent() << "break;\n"; |
| } |
| |
| |
| void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { |
| Indent() << "return"; |
| if (Node->getRetValue()) { |
| OS << " "; |
| PrintExpr(Node->getRetValue()); |
| } |
| OS << ";\n"; |
| } |
| |
| |
| void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { |
| Indent() << "asm "; |
| |
| if (Node->isVolatile()) |
| OS << "volatile "; |
| |
| OS << "("; |
| VisitStringLiteral(Node->getAsmString()); |
| |
| // Outputs |
| if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || |
| Node->getNumClobbers() != 0) |
| OS << " : "; |
| |
| for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { |
| if (i != 0) |
| OS << ", "; |
| |
| if (!Node->getOutputName(i).empty()) { |
| OS << '['; |
| OS << Node->getOutputName(i); |
| OS << "] "; |
| } |
| |
| VisitStringLiteral(Node->getOutputConstraint(i)); |
| OS << " "; |
| Visit(Node->getOutputExpr(i)); |
| } |
| |
| // Inputs |
| if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) |
| OS << " : "; |
| |
| for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { |
| if (i != 0) |
| OS << ", "; |
| |
| if (!Node->getInputName(i).empty()) { |
| OS << '['; |
| OS << Node->getInputName(i); |
| OS << "] "; |
| } |
| |
| VisitStringLiteral(Node->getInputConstraint(i)); |
| OS << " "; |
| Visit(Node->getInputExpr(i)); |
| } |
| |
| // Clobbers |
| if (Node->getNumClobbers() != 0) |
| OS << " : "; |
| |
| for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { |
| if (i != 0) |
| OS << ", "; |
| |
| VisitStringLiteral(Node->getClobber(i)); |
| } |
| |
| OS << ");\n"; |
| } |
| |
| void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { |
| Indent() << "@try"; |
| if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) { |
| PrintRawCompoundStmt(TS); |
| OS << "\n"; |
| } |
| |
| for (ObjCAtCatchStmt *catchStmt = |
| static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts()); |
| catchStmt; |
| catchStmt = |
| static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) { |
| Indent() << "@catch("; |
| if (catchStmt->getCatchParamStmt()) { |
| if (DeclStmt *DS = dyn_cast<DeclStmt>(catchStmt->getCatchParamStmt())) |
| PrintRawDeclStmt(DS); |
| } |
| OS << ")"; |
| if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) |
| { |
| PrintRawCompoundStmt(CS); |
| OS << "\n"; |
| } |
| } |
| |
| if (ObjCAtFinallyStmt *FS =static_cast<ObjCAtFinallyStmt *>( |
| Node->getFinallyStmt())) { |
| Indent() << "@finally"; |
| PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody())); |
| OS << "\n"; |
| } |
| } |
| |
| void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) { |
| } |
| |
| void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) { |
| Indent() << "@catch (...) { /* todo */ } \n"; |
| } |
| |
| void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) { |
| Indent() << "@throw"; |
| if (Node->getThrowExpr()) { |
| OS << " "; |
| PrintExpr(Node->getThrowExpr()); |
| } |
| OS << ";\n"; |
| } |
| |
| void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) { |
| Indent() << "@synchronized ("; |
| PrintExpr(Node->getSynchExpr()); |
| OS << ")"; |
| PrintRawCompoundStmt(Node->getSynchBody()); |
| OS << "\n"; |
| } |
| |
| void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) { |
| OS << "catch ("; |
| if (Decl *ExDecl = Node->getExceptionDecl()) |
| PrintRawDecl(ExDecl); |
| else |
| OS << "..."; |
| OS << ") "; |
| PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock())); |
| } |
| |
| void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) { |
| Indent(); |
| PrintRawCXXCatchStmt(Node); |
| OS << "\n"; |
| } |
| |
| void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { |
| Indent() << "try "; |
| PrintRawCompoundStmt(Node->getTryBlock()); |
| for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { |
| OS << " "; |
| PrintRawCXXCatchStmt(Node->getHandler(i)); |
| } |
| OS << "\n"; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Expr printing methods. |
| //===----------------------------------------------------------------------===// |
| |
| void StmtPrinter::VisitExpr(Expr *Node) { |
| OS << "<<unknown expr type>>"; |
| } |
| |
| void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { |
| OS << Node->getDecl()->getNameAsString(); |
| } |
| |
| void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { |
| // FIXME: Should we keep enough information in QualifiedDeclRefExpr |
| // to produce the same qualification that the user wrote? |
| llvm::SmallVector<DeclContext *, 4> Contexts; |
| |
| NamedDecl *D = Node->getDecl(); |
| |
| // Build up a stack of contexts. |
| DeclContext *Ctx = 0; |
| if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) |
| Ctx = SD->getDeclContext(); |
| else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) |
| Ctx = Ovl->getDeclContext(); |
| for (; Ctx; Ctx = Ctx->getParent()) |
| if (!Ctx->isTransparentContext()) |
| Contexts.push_back(Ctx); |
| |
| while (!Contexts.empty()) { |
| DeclContext *Ctx = Contexts.back(); |
| if (isa<TranslationUnitDecl>(Ctx)) |
| OS << "::"; |
| else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(Ctx)) |
| OS << SD->getNameAsString() << "::"; |
| Contexts.pop_back(); |
| } |
| |
| OS << D->getNameAsString(); |
| } |
| |
| void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { |
| if (Node->getBase()) { |
| PrintExpr(Node->getBase()); |
| OS << (Node->isArrow() ? "->" : "."); |
| } |
| OS << Node->getDecl()->getNameAsString(); |
| } |
| |
| void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { |
| if (Node->getBase()) { |
| PrintExpr(Node->getBase()); |
| OS << "."; |
| } |
| OS << Node->getProperty()->getNameAsCString(); |
| } |
| |
| void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { |
| if (Node->getBase()) { |
| PrintExpr(Node->getBase()); |
| OS << "."; |
| } |
| // FIXME: Setter/Getter names |
| } |
| |
| void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { |
| switch (Node->getIdentType()) { |
| default: |
| assert(0 && "unknown case"); |
| case PredefinedExpr::Func: |
| OS << "__func__"; |
| break; |
| case PredefinedExpr::Function: |
| OS << "__FUNCTION__"; |
| break; |
| case PredefinedExpr::PrettyFunction: |
| OS << "__PRETTY_FUNCTION__"; |
| break; |
| } |
| } |
| |
| void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { |
| unsigned value = Node->getValue(); |
| if (Node->isWide()) |
| OS << "L"; |
| switch (value) { |
| case '\\': |
| OS << "'\\\\'"; |
| break; |
| case '\'': |
| OS << "'\\''"; |
| break; |
| case '\a': |
| // TODO: K&R: the meaning of '\\a' is different in traditional C |
| OS << "'\\a'"; |
| break; |
| case '\b': |
| OS << "'\\b'"; |
| break; |
| // Nonstandard escape sequence. |
| /*case '\e': |
| OS << "'\\e'"; |
| break;*/ |
| case '\f': |
| OS << "'\\f'"; |
| break; |
| case '\n': |
| OS << "'\\n'"; |
| break; |
| case '\r': |
| OS << "'\\r'"; |
| break; |
| case '\t': |
| OS << "'\\t'"; |
| break; |
| case '\v': |
| OS << "'\\v'"; |
| break; |
| default: |
| if (value < 256 && isprint(value)) { |
| OS << "'" << (char)value << "'"; |
| } else if (value < 256) { |
| OS << "'\\x" << llvm::format("%x", value) << "'"; |
| } else { |
| // FIXME what to really do here? |
| OS << value; |
| } |
| } |
| } |
| |
| void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { |
| bool isSigned = Node->getType()->isSignedIntegerType(); |
| OS << Node->getValue().toString(10, isSigned); |
| |
| // Emit suffixes. Integer literals are always a builtin integer type. |
| switch (Node->getType()->getAsBuiltinType()->getKind()) { |
| default: assert(0 && "Unexpected type for integer literal!"); |
| case BuiltinType::Int: break; // no suffix. |
| case BuiltinType::UInt: OS << 'U'; break; |
| case BuiltinType::Long: OS << 'L'; break; |
| case BuiltinType::ULong: OS << "UL"; break; |
| case BuiltinType::LongLong: OS << "LL"; break; |
| case BuiltinType::ULongLong: OS << "ULL"; break; |
| } |
| } |
| void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { |
| // FIXME: print value more precisely. |
| OS << Node->getValueAsApproximateDouble(); |
| } |
| |
| void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { |
| PrintExpr(Node->getSubExpr()); |
| OS << "i"; |
| } |
| |
| void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { |
| if (Str->isWide()) OS << 'L'; |
| OS << '"'; |
| |
| // FIXME: this doesn't print wstrings right. |
| for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { |
| switch (Str->getStrData()[i]) { |
| default: OS << Str->getStrData()[i]; break; |
| // Handle some common ones to make dumps prettier. |
| case '\\': OS << "\\\\"; break; |
| case '"': OS << "\\\""; break; |
| case '\n': OS << "\\n"; break; |
| case '\t': OS << "\\t"; break; |
| case '\a': OS << "\\a"; break; |
| case '\b': OS << "\\b"; break; |
| } |
| } |
| OS << '"'; |
| } |
| void StmtPrinter::VisitParenExpr(ParenExpr *Node) { |
| OS << "("; |
| PrintExpr(Node->getSubExpr()); |
| OS << ")"; |
| } |
| void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { |
| if (!Node->isPostfix()) { |
| OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); |
| |
| // Print a space if this is an "identifier operator" like __real. |
| switch (Node->getOpcode()) { |
| default: break; |
| case UnaryOperator::Real: |
| case UnaryOperator::Imag: |
| case UnaryOperator::Extension: |
| OS << ' '; |
| break; |
| } |
| } |
| PrintExpr(Node->getSubExpr()); |
| |
| if (Node->isPostfix()) |
| OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); |
| } |
| |
| bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { |
| if (isa<CompoundLiteralExpr>(E)) { |
| // Base case, print the type and comma. |
| OS << E->getType().getAsString() << ", "; |
| return true; |
| } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) { |
| PrintOffsetOfDesignator(ASE->getLHS()); |
| OS << "["; |
| PrintExpr(ASE->getRHS()); |
| OS << "]"; |
| return false; |
| } else { |
| MemberExpr *ME = cast<MemberExpr>(E); |
| bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); |
| OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString(); |
| return false; |
| } |
| } |
| |
| void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { |
| OS << "__builtin_offsetof("; |
| PrintOffsetOfDesignator(Node->getSubExpr()); |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { |
| OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); |
| if (Node->isArgumentType()) |
| OS << "(" << Node->getArgumentType().getAsString() << ")"; |
| else { |
| OS << " "; |
| PrintExpr(Node->getArgumentExpr()); |
| } |
| } |
| void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { |
| PrintExpr(Node->getLHS()); |
| OS << "["; |
| PrintExpr(Node->getRHS()); |
| OS << "]"; |
| } |
| |
| void StmtPrinter::VisitCallExpr(CallExpr *Call) { |
| PrintExpr(Call->getCallee()); |
| OS << "("; |
| for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { |
| if (isa<CXXDefaultArgExpr>(Call->getArg(i))) { |
| // Don't print any defaulted arguments |
| break; |
| } |
| |
| if (i) OS << ", "; |
| PrintExpr(Call->getArg(i)); |
| } |
| OS << ")"; |
| } |
| void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { |
| // FIXME: Suppress printing implicit bases (like "this") |
| PrintExpr(Node->getBase()); |
| OS << (Node->isArrow() ? "->" : "."); |
| // FIXME: Suppress printing references to unnamed objects |
| // representing anonymous unions/structs |
| OS << Node->getMemberDecl()->getNameAsString(); |
| } |
| void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { |
| PrintExpr(Node->getBase()); |
| OS << "."; |
| OS << Node->getAccessor().getName(); |
| } |
| void StmtPrinter::VisitCastExpr(CastExpr *) { |
| assert(0 && "CastExpr is an abstract class"); |
| } |
| void StmtPrinter::VisitExplicitCastExpr(ExplicitCastExpr *) { |
| assert(0 && "ExplicitCastExpr is an abstract class"); |
| } |
| void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { |
| OS << "(" << Node->getType().getAsString() << ")"; |
| PrintExpr(Node->getSubExpr()); |
| } |
| void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { |
| OS << "(" << Node->getType().getAsString() << ")"; |
| PrintExpr(Node->getInitializer()); |
| } |
| void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) { |
| // No need to print anything, simply forward to the sub expression. |
| PrintExpr(Node->getSubExpr()); |
| } |
| void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { |
| PrintExpr(Node->getLHS()); |
| OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; |
| PrintExpr(Node->getRHS()); |
| } |
| void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { |
| PrintExpr(Node->getLHS()); |
| OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; |
| PrintExpr(Node->getRHS()); |
| } |
| void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { |
| PrintExpr(Node->getCond()); |
| |
| if (Node->getLHS()) { |
| OS << " ? "; |
| PrintExpr(Node->getLHS()); |
| OS << " : "; |
| } |
| else { // Handle GCC extention where LHS can be NULL. |
| OS << " ?: "; |
| } |
| |
| PrintExpr(Node->getRHS()); |
| } |
| |
| // GNU extensions. |
| |
| void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { |
| OS << "&&" << Node->getLabel()->getName(); |
| } |
| |
| void StmtPrinter::VisitStmtExpr(StmtExpr *E) { |
| OS << "("; |
| PrintRawCompoundStmt(E->getSubStmt()); |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { |
| OS << "__builtin_types_compatible_p("; |
| OS << Node->getArgType1().getAsString() << ","; |
| OS << Node->getArgType2().getAsString() << ")"; |
| } |
| |
| void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { |
| OS << "__builtin_choose_expr("; |
| PrintExpr(Node->getCond()); |
| OS << ", "; |
| PrintExpr(Node->getLHS()); |
| OS << ", "; |
| PrintExpr(Node->getRHS()); |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitGNUNullExpr(GNUNullExpr *) { |
| OS << "__null"; |
| } |
| |
| void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) { |
| OS << "__builtin_overload("; |
| for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { |
| if (i) OS << ", "; |
| PrintExpr(Node->getExpr(i)); |
| } |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) { |
| OS << "__builtin_shufflevector("; |
| for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { |
| if (i) OS << ", "; |
| PrintExpr(Node->getExpr(i)); |
| } |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { |
| OS << "{ "; |
| for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { |
| if (i) OS << ", "; |
| PrintExpr(Node->getInit(i)); |
| } |
| OS << " }"; |
| } |
| |
| void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { |
| OS << "va_arg("; |
| PrintExpr(Node->getSubExpr()); |
| OS << ", "; |
| OS << Node->getType().getAsString(); |
| OS << ")"; |
| } |
| |
| // C++ |
| void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { |
| const char *OpStrings[NUM_OVERLOADED_OPERATORS] = { |
| "", |
| #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ |
| Spelling, |
| #include "clang/Basic/OperatorKinds.def" |
| }; |
| |
| OverloadedOperatorKind Kind = Node->getOperator(); |
| if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { |
| if (Node->getNumArgs() == 1) { |
| OS << OpStrings[Kind] << ' '; |
| PrintExpr(Node->getArg(0)); |
| } else { |
| PrintExpr(Node->getArg(0)); |
| OS << ' ' << OpStrings[Kind]; |
| } |
| } else if (Kind == OO_Call) { |
| PrintExpr(Node->getArg(0)); |
| OS << '('; |
| for (unsigned ArgIdx = 1; ArgIdx < Node->getNumArgs(); ++ArgIdx) { |
| if (ArgIdx > 1) |
| OS << ", "; |
| if (!isa<CXXDefaultArgExpr>(Node->getArg(ArgIdx))) |
| PrintExpr(Node->getArg(ArgIdx)); |
| } |
| OS << ')'; |
| } else if (Kind == OO_Subscript) { |
| PrintExpr(Node->getArg(0)); |
| OS << '['; |
| PrintExpr(Node->getArg(1)); |
| OS << ']'; |
| } else if (Node->getNumArgs() == 1) { |
| OS << OpStrings[Kind] << ' '; |
| PrintExpr(Node->getArg(0)); |
| } else if (Node->getNumArgs() == 2) { |
| PrintExpr(Node->getArg(0)); |
| OS << ' ' << OpStrings[Kind] << ' '; |
| PrintExpr(Node->getArg(1)); |
| } else { |
| assert(false && "unknown overloaded operator"); |
| } |
| } |
| |
| void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) { |
| VisitCallExpr(cast<CallExpr>(Node)); |
| } |
| |
| void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { |
| OS << Node->getCastName() << '<'; |
| OS << Node->getTypeAsWritten().getAsString() << ">("; |
| PrintExpr(Node->getSubExpr()); |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitCXXStaticCastExpr(CXXStaticCastExpr *Node) { |
| VisitCXXNamedCastExpr(Node); |
| } |
| |
| void StmtPrinter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *Node) { |
| VisitCXXNamedCastExpr(Node); |
| } |
| |
| void StmtPrinter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *Node) { |
| VisitCXXNamedCastExpr(Node); |
| } |
| |
| void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) { |
| VisitCXXNamedCastExpr(Node); |
| } |
| |
| void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { |
| OS << "typeid("; |
| if (Node->isTypeOperand()) { |
| OS << Node->getTypeOperand().getAsString(); |
| } else { |
| PrintExpr(Node->getExprOperand()); |
| } |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { |
| OS << (Node->getValue() ? "true" : "false"); |
| } |
| |
| void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) { |
| OS << "this"; |
| } |
| |
| void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { |
| if (Node->getSubExpr() == 0) |
| OS << "throw"; |
| else { |
| OS << "throw "; |
| PrintExpr(Node->getSubExpr()); |
| } |
| } |
| |
| void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { |
| // Nothing to print: we picked up the default argument |
| } |
| |
| void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { |
| OS << Node->getType().getAsString(); |
| OS << "("; |
| PrintExpr(Node->getSubExpr()); |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) { |
| OS << Node->getType().getAsString() << "()"; |
| } |
| |
| void |
| StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) { |
| PrintRawDecl(E->getVarDecl()); |
| } |
| |
| void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { |
| if (E->isGlobalNew()) |
| OS << "::"; |
| OS << "new "; |
| unsigned NumPlace = E->getNumPlacementArgs(); |
| if (NumPlace > 0) { |
| OS << "("; |
| PrintExpr(E->getPlacementArg(0)); |
| for (unsigned i = 1; i < NumPlace; ++i) { |
| OS << ", "; |
| PrintExpr(E->getPlacementArg(i)); |
| } |
| OS << ") "; |
| } |
| if (E->isParenTypeId()) |
| OS << "("; |
| std::string TypeS; |
| if (Expr *Size = E->getArraySize()) { |
| llvm::raw_string_ostream s(TypeS); |
| Size->printPretty(s); |
| s.flush(); |
| TypeS = "[" + TypeS + "]"; |
| } |
| E->getAllocatedType().getAsStringInternal(TypeS); |
| OS << TypeS; |
| if (E->isParenTypeId()) |
| OS << ")"; |
| |
| if (E->hasInitializer()) { |
| OS << "("; |
| unsigned NumCons = E->getNumConstructorArgs(); |
| if (NumCons > 0) { |
| PrintExpr(E->getConstructorArg(0)); |
| for (unsigned i = 1; i < NumCons; ++i) { |
| OS << ", "; |
| PrintExpr(E->getConstructorArg(i)); |
| } |
| } |
| OS << ")"; |
| } |
| } |
| |
| void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { |
| if (E->isGlobalDelete()) |
| OS << "::"; |
| OS << "delete "; |
| if (E->isArrayForm()) |
| OS << "[] "; |
| PrintExpr(E->getArgument()); |
| } |
| |
| void StmtPrinter::VisitCXXDependentNameExpr(CXXDependentNameExpr *E) { |
| OS << E->getName()->getName(); |
| } |
| |
| static const char *getTypeTraitName(UnaryTypeTrait UTT) { |
| switch (UTT) { |
| default: assert(false && "Unknown type trait"); |
| case UTT_HasNothrowAssign: return "__has_nothrow_assign"; |
| case UTT_HasNothrowCopy: return "__has_nothrow_copy"; |
| case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; |
| case UTT_HasTrivialAssign: return "__has_trivial_assign"; |
| case UTT_HasTrivialCopy: return "__has_trivial_copy"; |
| case UTT_HasTrivialConstructor: return "__has_trivial_constructor"; |
| case UTT_HasTrivialDestructor: return "__has_trivial_destructor"; |
| case UTT_HasVirtualDestructor: return "__has_virtual_destructor"; |
| case UTT_IsAbstract: return "__is_abstract"; |
| case UTT_IsClass: return "__is_class"; |
| case UTT_IsEmpty: return "__is_empty"; |
| case UTT_IsEnum: return "__is_enum"; |
| case UTT_IsPOD: return "__is_pod"; |
| case UTT_IsPolymorphic: return "__is_polymorphic"; |
| case UTT_IsUnion: return "__is_union"; |
| } |
| } |
| |
| void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { |
| OS << getTypeTraitName(E->getTrait()) << "(" |
| << E->getQueriedType().getAsString() << ")"; |
| } |
| |
| // Obj-C |
| |
| void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { |
| OS << "@"; |
| VisitStringLiteral(Node->getString()); |
| } |
| |
| void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { |
| OS << "@encode(" << Node->getEncodedType().getAsString() << ')'; |
| } |
| |
| void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { |
| OS << "@selector(" << Node->getSelector().getAsString() << ')'; |
| } |
| |
| void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { |
| OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')'; |
| } |
| |
| void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { |
| OS << "["; |
| Expr *receiver = Mess->getReceiver(); |
| if (receiver) PrintExpr(receiver); |
| else OS << Mess->getClassName()->getName(); |
| OS << ' '; |
| Selector selector = Mess->getSelector(); |
| if (selector.isUnarySelector()) { |
| OS << selector.getIdentifierInfoForSlot(0)->getName(); |
| } else { |
| for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { |
| if (i < selector.getNumArgs()) { |
| if (i > 0) OS << ' '; |
| if (selector.getIdentifierInfoForSlot(i)) |
| OS << selector.getIdentifierInfoForSlot(i)->getName() << ':'; |
| else |
| OS << ":"; |
| } |
| else OS << ", "; // Handle variadic methods. |
| |
| PrintExpr(Mess->getArg(i)); |
| } |
| } |
| OS << "]"; |
| } |
| |
| void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) { |
| OS << "super"; |
| } |
| |
| void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { |
| BlockDecl *BD = Node->getBlockDecl(); |
| OS << "^"; |
| |
| const FunctionType *AFT = Node->getFunctionType(); |
| |
| if (isa<FunctionTypeNoProto>(AFT)) { |
| OS << "()"; |
| } else if (!BD->param_empty() || cast<FunctionTypeProto>(AFT)->isVariadic()) { |
| OS << '('; |
| std::string ParamStr; |
| for (BlockDecl::param_iterator AI = BD->param_begin(), |
| E = BD->param_end(); AI != E; ++AI) { |
| if (AI != BD->param_begin()) OS << ", "; |
| ParamStr = (*AI)->getNameAsString(); |
| (*AI)->getType().getAsStringInternal(ParamStr); |
| OS << ParamStr; |
| } |
| |
| const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT); |
| if (FT->isVariadic()) { |
| if (!BD->param_empty()) OS << ", "; |
| OS << "..."; |
| } |
| OS << ')'; |
| } |
| } |
| |
| void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { |
| OS << Node->getDecl()->getNameAsString(); |
| } |
| //===----------------------------------------------------------------------===// |
| // Stmt method implementations |
| //===----------------------------------------------------------------------===// |
| |
| void Stmt::dumpPretty() const { |
| printPretty(llvm::errs()); |
| } |
| |
| void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const { |
| if (this == 0) { |
| OS << "<NULL>"; |
| return; |
| } |
| |
| StmtPrinter P(OS, Helper); |
| P.Visit(const_cast<Stmt*>(this)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // PrinterHelper |
| //===----------------------------------------------------------------------===// |
| |
| // Implement virtual destructor. |
| PrinterHelper::~PrinterHelper() {} |