| //===--- 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/Format.h" |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // StmtPrinter Visitor |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> { |
| llvm::raw_ostream &OS; |
| ASTContext &Context; |
| unsigned IndentLevel; |
| clang::PrinterHelper* Helper; |
| PrintingPolicy Policy; |
| |
| public: |
| StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, |
| const PrintingPolicy &Policy, |
| unsigned Indentation = 0) |
| : OS(os), Context(C), IndentLevel(Indentation), Helper(helper), |
| Policy(Policy) {} |
| |
| void PrintStmt(Stmt *S) { |
| PrintStmt(S, Policy.Indentation); |
| } |
| |
| void PrintStmt(Stmt *S, int SubIndent) { |
| 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) { |
| 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) { |
| D->print(OS, Policy, IndentLevel); |
| } |
| |
| void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { |
| DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); |
| llvm::SmallVector<Decl*, 2> Decls; |
| for ( ; Begin != End; ++Begin) |
| Decls.push_back(*Begin); |
| |
| Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel); |
| } |
| |
| void StmtPrinter::VisitNullStmt(NullStmt *Node) { |
| Indent() << ";\n"; |
| } |
| |
| void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { |
| Indent(); |
| PrintRawDeclStmt(Node); |
| 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()); |
| OS << ')'; |
| |
| 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->getOutputConstraintLiteral(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->getInputConstraintLiteral(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->getCatchParamDecl()) { |
| if (Decl *DS = catchStmt->getCatchParamDecl()) |
| PrintRawDecl(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) { |
| NamedDecl *D = Node->getDecl(); |
| |
| Node->getQualifier()->print(OS, Policy); |
| OS << D->getNameAsString(); |
| } |
| |
| void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { |
| Node->getQualifier()->print(OS, Policy); |
| OS << Node->getDeclName().getAsString(); |
| } |
| |
| void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) { |
| if (Node->getQualifier()) |
| Node->getQualifier()->print(OS, Policy); |
| Node->getTemplateName().print(OS, Policy, true); |
| OS << TemplateSpecializationType::PrintTemplateArgumentList( |
| Node->getTemplateArgs(), |
| Node->getNumTemplateArgs(), |
| Policy); |
| } |
| |
| 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::VisitObjCImplicitSetterGetterRefExpr( |
| ObjCImplicitSetterGetterRefExpr *Node) { |
| if (Node->getBase()) { |
| PrintExpr(Node->getBase()); |
| OS << "."; |
| } |
| if (Node->getGetterMethod()) |
| OS << Node->getGetterMethod()->getNameAsString(); |
| |
| } |
| |
| 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) { |
| unsigned char Char = Str->getStrData()[i]; |
| |
| switch (Char) { |
| default: |
| if (isprint(Char)) |
| OS << (char)Char; |
| else // Output anything hard as an octal escape. |
| OS << '\\' |
| << (char)('0'+ ((Char >> 6) & 7)) |
| << (char)('0'+ ((Char >> 3) & 7)) |
| << (char)('0'+ ((Char >> 0) & 7)); |
| break; |
| // Handle some common non-printable cases 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, or if |
| // it might be concatenated incorrectly like '+'. |
| switch (Node->getOpcode()) { |
| default: break; |
| case UnaryOperator::Real: |
| case UnaryOperator::Imag: |
| case UnaryOperator::Extension: |
| OS << ' '; |
| break; |
| case UnaryOperator::Plus: |
| case UnaryOperator::Minus: |
| if (isa<UnaryOperator>(Node->getSubExpr())) |
| OS << ' '; |
| break; |
| } |
| } |
| PrintExpr(Node->getSubExpr()); |
| |
| if (Node->isPostfix()) |
| OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); |
| } |
| |
| bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { |
| if (isa<UnaryOperator>(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 |
| if (NestedNameSpecifier *Qualifier = Node->getQualifier()) |
| Qualifier->print(OS, Policy); |
| |
| OS << Node->getMemberDecl()->getNameAsString(); |
| |
| if (Node->hasExplicitTemplateArgumentList()) |
| OS << TemplateSpecializationType::PrintTemplateArgumentList( |
| Node->getTemplateArgs(), |
| Node->getNumTemplateArgs(), |
| Policy); |
| } |
| void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { |
| PrintExpr(Node->getBase()); |
| OS << (Node->isArrow() ? "->isa" : ".isa"); |
| } |
| |
| 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 extension 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::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) { |
| if (Node->getSyntacticForm()) { |
| Visit(Node->getSyntacticForm()); |
| return; |
| } |
| |
| OS << "{ "; |
| for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { |
| if (i) OS << ", "; |
| if (Node->getInit(i)) |
| PrintExpr(Node->getInit(i)); |
| else |
| OS << "0"; |
| } |
| OS << " }"; |
| } |
| |
| void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) { |
| OS << "( "; |
| for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) { |
| if (i) OS << ", "; |
| PrintExpr(Node->getExpr(i)); |
| } |
| OS << " )"; |
| } |
| |
| void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { |
| for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(), |
| DEnd = Node->designators_end(); |
| D != DEnd; ++D) { |
| if (D->isFieldDesignator()) { |
| if (D->getDotLoc().isInvalid()) |
| OS << D->getFieldName()->getName() << ":"; |
| else |
| OS << "." << D->getFieldName()->getName(); |
| } else { |
| OS << "["; |
| if (D->isArrayDesignator()) { |
| PrintExpr(Node->getArrayIndex(*D)); |
| } else { |
| PrintExpr(Node->getArrayRangeStart(*D)); |
| OS << " ... "; |
| PrintExpr(Node->getArrayRangeEnd(*D)); |
| } |
| OS << "]"; |
| } |
| } |
| |
| OS << " = "; |
| PrintExpr(Node->getInit()); |
| } |
| |
| void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) { |
| if (Policy.LangOpts.CPlusPlus) |
| OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()"; |
| else { |
| OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")"; |
| if (Node->getType()->isRecordType()) |
| OS << "{}"; |
| else |
| OS << 0; |
| } |
| } |
| |
| void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { |
| OS << "__builtin_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::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) { |
| OS << "nullptr"; |
| } |
| |
| 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::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { |
| PrintExpr(Node->getSubExpr()); |
| } |
| |
| void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { |
| OS << Node->getType().getAsString(); |
| OS << "("; |
| for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(), |
| ArgEnd = Node->arg_end(); |
| Arg != ArgEnd; ++Arg) { |
| if (Arg != Node->arg_begin()) |
| OS << ", "; |
| PrintExpr(*Arg); |
| } |
| 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, Context, Helper, Policy); |
| s.flush(); |
| TypeS = "[" + TypeS + "]"; |
| } |
| E->getAllocatedType().getAsStringInternal(TypeS, Policy); |
| 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::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { |
| PrintExpr(E->getBase()); |
| if (E->isArrow()) |
| OS << "->"; |
| else |
| OS << '.'; |
| if (E->getQualifier()) |
| E->getQualifier()->print(OS, Policy); |
| |
| std::string TypeS; |
| E->getDestroyedType().getAsStringInternal(TypeS, Policy); |
| OS << TypeS; |
| } |
| |
| void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { |
| OS << E->getName().getAsString(); |
| } |
| |
| void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { |
| // Nothing to print. |
| } |
| |
| void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { |
| // Just forward to the sub expression. |
| PrintExpr(E->getSubExpr()); |
| } |
| |
| void |
| StmtPrinter::VisitCXXUnresolvedConstructExpr( |
| CXXUnresolvedConstructExpr *Node) { |
| OS << Node->getTypeAsWritten().getAsString(); |
| OS << "("; |
| for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(), |
| ArgEnd = Node->arg_end(); |
| Arg != ArgEnd; ++Arg) { |
| if (Arg != Node->arg_begin()) |
| OS << ", "; |
| PrintExpr(*Arg); |
| } |
| OS << ")"; |
| } |
| |
| void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { |
| PrintExpr(Node->getBase()); |
| OS << (Node->isArrow() ? "->" : "."); |
| if (NestedNameSpecifier *Qualifier = Node->getQualifier()) |
| Qualifier->print(OS, Policy); |
| else if (Node->hasExplicitTemplateArgumentList()) |
| // FIXME: Track use of "template" keyword explicitly? |
| OS << "template "; |
| |
| OS << Node->getMember().getAsString(); |
| |
| if (Node->hasExplicitTemplateArgumentList()) { |
| OS << TemplateSpecializationType::PrintTemplateArgumentList( |
| Node->getTemplateArgs(), |
| Node->getNumTemplateArgs(), |
| Policy); |
| } |
| } |
| |
| 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<FunctionNoProtoType>(AFT)) { |
| OS << "()"; |
| } else if (!BD->param_empty() || cast<FunctionProtoType>(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, Policy); |
| OS << ParamStr; |
| } |
| |
| const FunctionProtoType *FT = cast<FunctionProtoType>(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(ASTContext& Context) const { |
| printPretty(llvm::errs(), Context, 0, |
| PrintingPolicy(Context.getLangOptions())); |
| } |
| |
| void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, |
| PrinterHelper* Helper, |
| const PrintingPolicy &Policy, |
| unsigned Indentation) const { |
| if (this == 0) { |
| OS << "<NULL>"; |
| return; |
| } |
| |
| if (Policy.Dump) { |
| dump(Context.getSourceManager()); |
| return; |
| } |
| |
| StmtPrinter P(OS, Context, Helper, Policy, Indentation); |
| P.Visit(const_cast<Stmt*>(this)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // PrinterHelper |
| //===----------------------------------------------------------------------===// |
| |
| // Implement virtual destructor. |
| PrinterHelper::~PrinterHelper() {} |