llvm-project/clang/lib/AST/StmtDumper.cpp

723 lines
21 KiB
C++
Raw Normal View History

//===--- StmtDumper.cpp - Dumping 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::dump/Stmt::print methods, which dump out the
// AST in a form that exposes type details and other fields.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// StmtDumper Visitor
//===----------------------------------------------------------------------===//
namespace {
class StmtDumper : public StmtVisitor<StmtDumper> {
SourceManager *SM;
raw_ostream &OS;
unsigned IndentLevel;
/// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
/// the first few levels of an AST. This keeps track of how many ast levels
/// are left.
unsigned MaxDepth;
/// LastLocFilename/LastLocLine - Keep track of the last location we print
/// out so that we can print out deltas from then on out.
const char *LastLocFilename;
unsigned LastLocLine;
public:
StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
: SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) {
LastLocFilename = "";
LastLocLine = ~0U;
}
void DumpSubTree(Stmt *S) {
// Prune the recursion if not using dump all.
if (MaxDepth == 0) return;
++IndentLevel;
if (S) {
if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
VisitDeclStmt(DS);
else {
Visit(S);
// Print out children.
Stmt::child_range CI = S->children();
if (CI) {
while (CI) {
OS << '\n';
DumpSubTree(*CI++);
}
}
}
OS << ')';
} else {
Indent();
OS << "<<<NULL>>>";
}
--IndentLevel;
}
void DumpDeclarator(Decl *D);
void Indent() const {
for (int i = 0, e = IndentLevel; i < e; ++i)
OS << " ";
}
void DumpType(QualType T) {
SplitQualType T_split = T.split();
OS << "'" << QualType::getAsString(T_split) << "'";
if (!T.isNull()) {
// If the type is sugared, also dump a (shallow) desugared type.
SplitQualType D_split = T.getSplitDesugaredType();
if (T_split != D_split)
OS << ":'" << QualType::getAsString(D_split) << "'";
}
}
void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
Indent();
OS << "(" << Node->getStmtClassName()
<< " " << (void*)Node;
DumpSourceRange(Node);
}
void DumpValueKind(ExprValueKind K) {
switch (K) {
case VK_RValue: break;
case VK_LValue: OS << " lvalue"; break;
case VK_XValue: OS << " xvalue"; break;
}
}
void DumpObjectKind(ExprObjectKind K) {
switch (K) {
case OK_Ordinary: break;
case OK_BitField: OS << " bitfield"; break;
case OK_ObjCProperty: OS << " objcproperty"; break;
case OK_VectorComponent: OS << " vectorcomponent"; break;
}
}
void DumpExpr(const Expr *Node) {
DumpStmt(Node);
OS << ' ';
DumpType(Node->getType());
DumpValueKind(Node->getValueKind());
DumpObjectKind(Node->getObjectKind());
}
void DumpSourceRange(const Stmt *Node);
void DumpLocation(SourceLocation Loc);
// Stmts.
void VisitStmt(Stmt *Node);
void VisitDeclStmt(DeclStmt *Node);
void VisitLabelStmt(LabelStmt *Node);
void VisitGotoStmt(GotoStmt *Node);
// Exprs
void VisitExpr(Expr *Node);
void VisitCastExpr(CastExpr *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 VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
void VisitMemberExpr(MemberExpr *Node);
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
void VisitBinaryOperator(BinaryOperator *Node);
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
void VisitAddrLabelExpr(AddrLabelExpr *Node);
void VisitBlockExpr(BlockExpr *Node);
void VisitOpaqueValueExpr(OpaqueValueExpr *Node);
// C++
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
void VisitCXXThisExpr(CXXThisExpr *Node);
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
void VisitExprWithCleanups(ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node);
void DumpCXXTemporary(CXXTemporary *Temporary);
// ObjC
void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
void VisitObjCMessageExpr(ObjCMessageExpr* Node);
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
};
}
//===----------------------------------------------------------------------===//
// Utilities
//===----------------------------------------------------------------------===//
void StmtDumper::DumpLocation(SourceLocation Loc) {
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
// The general format we print out is filename:line:col, but we drop pieces
// that haven't changed since the last loc printed.
PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
if (PLoc.isInvalid()) {
OS << "<invalid sloc>";
return;
}
if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
OS << PLoc.getFilename() << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
LastLocFilename = PLoc.getFilename();
LastLocLine = PLoc.getLine();
} else if (PLoc.getLine() != LastLocLine) {
OS << "line" << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
LastLocLine = PLoc.getLine();
} else {
OS << "col" << ':' << PLoc.getColumn();
}
}
void StmtDumper::DumpSourceRange(const Stmt *Node) {
// Can't translate locations if a SourceManager isn't available.
if (SM == 0) return;
// TODO: If the parent expression is available, we can print a delta vs its
// location.
SourceRange R = Node->getSourceRange();
OS << " <";
DumpLocation(R.getBegin());
if (R.getBegin() != R.getEnd()) {
OS << ", ";
DumpLocation(R.getEnd());
}
OS << ">";
// <t2.c:123:421[blah], t2.c:412:321>
}
//===----------------------------------------------------------------------===//
// Stmt printing methods.
//===----------------------------------------------------------------------===//
void StmtDumper::VisitStmt(Stmt *Node) {
DumpStmt(Node);
}
void StmtDumper::DumpDeclarator(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()
<< ' ' << *localType << '"';
} else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
OS << "\"using " << *localType << " = "
<< localType->getUnderlyingType().getAsString() << '"';
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
OS << "\"";
// Emit storage class for vardecls.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getStorageClass() != SC_None)
OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
<< " ";
}
std::string Name = VD->getNameAsString();
VD->getType().getAsStringInternal(Name,
PrintingPolicy(VD->getASTContext().getLangOptions()));
OS << Name;
// If this is a vardecl with an initializer, emit it.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getInit()) {
OS << " =\n";
DumpSubTree(V->getInit());
}
}
OS << '"';
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
// print a free standing tag decl (e.g. "struct x;").
const char *tagname;
if (const IdentifierInfo *II = TD->getIdentifier())
tagname = II->getNameStart();
else
tagname = "<anonymous>";
OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
// FIXME: print tag bodies.
} else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
// print using-directive decl (e.g. "using namespace x;")
const char *ns;
if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
ns = II->getNameStart();
else
ns = "<anonymous>";
OS << '"' << UD->getDeclKindName() << ns << ";\"";
} else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
// print using decl (e.g. "using std::string;")
const char *tn = UD->isTypeName() ? "typename " : "";
OS << '"' << UD->getDeclKindName() << tn;
UD->getQualifier()->print(OS,
PrintingPolicy(UD->getASTContext().getLangOptions()));
OS << ";\"";
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
OS << "label " << LD->getNameAsString();
} else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
OS << "\"static_assert(\n";
DumpSubTree(SAD->getAssertExpr());
OS << ",\n";
DumpSubTree(SAD->getMessage());
OS << ");\"";
} else {
llvm_unreachable("Unexpected decl");
}
}
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
DumpStmt(Node);
OS << "\n";
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
DI != DE; ++DI) {
Decl* D = *DI;
++IndentLevel;
Indent();
OS << (void*) D << " ";
DumpDeclarator(D);
2009-03-30 00:04:50 +08:00
if (DI+1 != DE)
OS << "\n";
--IndentLevel;
}
}
void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
DumpStmt(Node);
OS << " '" << Node->getName() << "'";
}
void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
DumpStmt(Node);
OS << " '" << Node->getLabel()->getName()
<< "':" << (void*)Node->getLabel();
}
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
void StmtDumper::VisitExpr(Expr *Node) {
DumpExpr(Node);
}
static void DumpBasePath(raw_ostream &OS, CastExpr *Node) {
if (Node->path_empty())
return;
OS << " (";
bool First = true;
for (CastExpr::path_iterator
I = Node->path_begin(), E = Node->path_end(); I != E; ++I) {
const CXXBaseSpecifier *Base = *I;
if (!First)
OS << " -> ";
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (Base->isVirtual())
OS << "virtual ";
OS << RD->getName();
First = false;
}
OS << ')';
}
void StmtDumper::VisitCastExpr(CastExpr *Node) {
DumpExpr(Node);
OS << " <" << Node->getCastKindName();
DumpBasePath(OS, Node);
OS << ">";
}
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
OS << " ";
DumpDeclRef(Node->getDecl());
Add an optional field attached to a DeclRefExpr which points back to the Decl actually found via name lookup & overload resolution when that Decl is different from the ValueDecl which is actually referenced by the expression. This can be used by AST consumers to correctly attribute references to the spelling location of a using declaration, and otherwise gain insight into the name resolution performed by Clang. The public interface to DRE is kept as narrow as possible: we provide a getFoundDecl() which always returns a NamedDecl, either the ValueDecl referenced or the new, more precise NamedDecl if present. This way AST clients can code against getFoundDecl without know when exactly the AST has a split representation. For an example of the data this provides consider: % cat x.cc namespace N1 { struct S {}; void f(const S&); } void test(N1::S s) { f(s); using N1::f; f(s); } % ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc [...] void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1> (CallExpr 0x5b01df0 <line:6:3, col:6> 'void' (ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay> (DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)')) (ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp> (DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))) (DeclStmt 0x5b01ee0 <line:7:3, col:14> 0x5b01e40 "UsingN1::;") (CallExpr 0x5b01fc8 <line:8:3, col:6> 'void' (ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay> (DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f'))) (ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp> (DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))) Now we can tell that the second call is 'using' (no pun intended) the using declaration, and *which* using declaration it sees. Without this, we can mistake calls that go through using declarations for ADL calls, and have no way to attribute names looked up with using declarations to the appropriate UsingDecl. llvm-svn: 130670
2011-05-02 07:48:14 +08:00
if (Node->getDecl() != Node->getFoundDecl()) {
OS << " (";
DumpDeclRef(Node->getFoundDecl());
OS << ")";
}
}
void StmtDumper::DumpDeclRef(Decl *d) {
OS << d->getDeclKindName() << ' ' << (void*) d;
if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
OS << " '";
nd->getDeclName().printName(OS);
OS << "'";
}
if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
OS << ' '; DumpType(vd->getType());
}
}
void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
DumpExpr(Node);
OS << " (";
if (!Node->requiresADL()) OS << "no ";
OS << "ADL) = '" << Node->getName() << '\'';
UnresolvedLookupExpr::decls_iterator
I = Node->decls_begin(), E = Node->decls_end();
if (I == E) OS << " empty";
for (; I != E; ++I)
OS << " " << (void*) *I;
}
void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getDecl()->getDeclKindName()
<< "Decl='" << *Node->getDecl()
<< "' " << (void*)Node->getDecl();
if (Node->isFreeIvar())
OS << " isFreeIvar";
}
void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
DumpExpr(Node);
switch (Node->getIdentType()) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
}
void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
DumpExpr(Node);
OS << " " << Node->getValue();
}
void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
DumpExpr(Node);
bool isSigned = Node->getType()->isSignedIntegerType();
OS << " " << Node->getValue().toString(10, isSigned);
}
void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
DumpExpr(Node);
OS << " " << Node->getValueAsApproximateDouble();
}
void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
DumpExpr(Str);
// FIXME: this doesn't print wstrings right.
OS << " ";
switch (Str->getKind()) {
case StringLiteral::Ascii: break; // No prefix
case StringLiteral::Wide: OS << 'L'; break;
case StringLiteral::UTF8: OS << "u8"; break;
case StringLiteral::UTF16: OS << 'u'; break;
case StringLiteral::UTF32: OS << 'U'; break;
}
OS << '"';
OS.write_escaped(Str->getString());
OS << '"';
}
void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
DumpExpr(Node);
OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
<< " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
DumpExpr(Node);
switch(Node->getKind()) {
case UETT_SizeOf:
OS << " sizeof ";
break;
case UETT_AlignOf:
OS << " __alignof ";
break;
case UETT_VecStep:
OS << " vec_step ";
break;
}
if (Node->isArgumentType())
DumpType(Node->getArgumentType());
}
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
DumpExpr(Node);
OS << " " << (Node->isArrow() ? "->" : ".")
<< *Node->getMemberDecl() << ' '
<< (void*)Node->getMemberDecl();
}
void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getAccessor().getNameStart();
}
void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
DumpExpr(Node);
OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
DumpExpr(Node);
OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
<< "' ComputeLHSTy=";
DumpType(Node->getComputationLHSType());
OS << " ComputeResultTy=";
DumpType(Node->getComputationResultType());
}
void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
DumpExpr(Node);
IndentLevel++;
BlockDecl *block = Node->getBlockDecl();
if (block->capturesCXXThis()) {
OS << '\n'; Indent(); OS << "(capture this)";
}
for (BlockDecl::capture_iterator
i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
OS << '\n';
Indent();
OS << "(capture ";
if (i->isByRef()) OS << "byref ";
if (i->isNested()) OS << "nested ";
DumpDeclRef(i->getVariable());
if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
OS << ")";
}
IndentLevel--;
DumpSubTree(block->getBody());
}
void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
DumpExpr(Node);
if (Expr *Source = Node->getSourceExpr()) {
OS << '\n';
DumpSubTree(Source);
}
}
// GNU extensions.
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getLabel()->getName()
<< " " << (void*)Node->getLabel();
}
//===----------------------------------------------------------------------===//
// C++ Expressions
//===----------------------------------------------------------------------===//
void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getCastName()
<< "<" << Node->getTypeAsWritten().getAsString() << ">"
<< " <" << Node->getCastKindName();
DumpBasePath(OS, Node);
OS << ">";
}
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
DumpExpr(Node);
OS << " " << (Node->getValue() ? "true" : "false");
}
void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
DumpExpr(Node);
OS << " this";
}
void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
DumpExpr(Node);
OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
<< " <" << Node->getCastKindName() << ">";
}
void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
DumpExpr(Node);
CXXConstructorDecl *Ctor = Node->getConstructor();
DumpType(Ctor->getType());
if (Node->isElidable())
OS << " elidable";
if (Node->requiresZeroInitialization())
OS << " zeroing";
}
void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
DumpExpr(Node);
OS << " ";
DumpCXXTemporary(Node->getTemporary());
}
void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
++IndentLevel;
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
OS << "\n";
Indent();
OS << "(cleanup ";
DumpDeclRef(Node->getObject(i));
OS << ")";
}
--IndentLevel;
}
void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
OS << "(CXXTemporary " << (void *)Temporary << ")";
}
//===----------------------------------------------------------------------===//
// Obj-C Expressions
//===----------------------------------------------------------------------===//
void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
DumpExpr(Node);
OS << " selector=" << Node->getSelector().getAsString();
Overhaul the AST representation of Objective-C message send expressions, to improve source-location information, clarify the actual receiver of the message, and pave the way for proper C++ support. The ObjCMessageExpr node represents four different kinds of message sends in a single AST node: 1) Send to a object instance described by an expression (e.g., [x method:5]) 2) Send to a class described by the class name (e.g., [NSString method:5]) 3) Send to a superclass class (e.g, [super method:5] in class method) 4) Send to a superclass instance (e.g., [super method:5] in instance method) Previously these four cases where tangled together. Now, they have more distinct representations. Specific changes: 1) Unchanged; the object instance is represented by an Expr*. 2) Previously stored the ObjCInterfaceDecl* referring to the class receiving the message. Now stores a TypeSourceInfo* so that we know how the class was spelled. This both maintains typedef information and opens the door for more complicated C++ types (e.g., dependent types). There was an alternative, unused representation of these sends by naming the class via an IdentifierInfo *. In practice, we either had an ObjCInterfaceDecl *, from which we would get the IdentifierInfo *, or we fell into the case below... 3) Previously represented by a class message whose IdentifierInfo * referred to "super". Sema and CodeGen would use isStr("super") to determine if they had a send to super. Now represented as a "class super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). 4) Previously represented by an instance message whose receiver is a an ObjCSuperExpr, which Sema and CodeGen would check for via isa<ObjCSuperExpr>(). Now represented as an "instance super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). Note that ObjCSuperExpr only has one remaining use in the AST, which is for "super.prop" references. The new representation of ObjCMessageExpr is 2 pointers smaller than the old one, since it combines more storage. It also eliminates a leak when we loaded message-send expressions from a precompiled header. The representation also feels much cleaner to me; comments welcome! This patch attempts to maintain the same semantics we previously had with Objective-C message sends. In several places, there are massive changes that boil down to simply replacing a nested-if structure such as: if (message has a receiver expression) { // instance message if (isa<ObjCSuperExpr>(...)) { // send to super } else { // send to an object } } else { // class message if (name->isStr("super")) { // class send to super } else { // send to class } } with a switch switch (E->getReceiverKind()) { case ObjCMessageExpr::SuperInstance: ... case ObjCMessageExpr::Instance: ... case ObjCMessageExpr::SuperClass: ... case ObjCMessageExpr::Class:... } There are quite a few places (particularly in the checkers) where send-to-super is effectively ignored. I've placed FIXMEs in most of them, and attempted to address send-to-super in a reasonable way. This could use some review. llvm-svn: 101972
2010-04-21 08:45:42 +08:00
switch (Node->getReceiverKind()) {
case ObjCMessageExpr::Instance:
break;
case ObjCMessageExpr::Class:
OS << " class=";
DumpType(Node->getClassReceiver());
break;
case ObjCMessageExpr::SuperInstance:
OS << " super (instance)";
break;
case ObjCMessageExpr::SuperClass:
OS << " super (class)";
break;
}
}
void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
DumpStmt(Node);
if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
OS << " catch parm = ";
DumpDeclarator(CatchParam);
} else {
OS << " catch all";
}
}
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
DumpExpr(Node);
OS << " ";
DumpType(Node->getEncodedType());
}
void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getSelector().getAsString();
}
void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
DumpExpr(Node);
OS << ' ' <<* Node->getProtocol();
}
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
if (Node->isImplicitProperty()) {
OS << " Kind=MethodRef Getter=\"";
if (Node->getImplicitPropertyGetter())
OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
else
OS << "(null)";
OS << "\" Setter=\"";
if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
OS << Setter->getSelector().getAsString();
else
OS << "(null)";
OS << "\"";
} else {
OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
}
if (Node->isSuperReceiver())
OS << " super";
}
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
/// dump - This does a local dump of the specified AST fragment. It dumps the
/// specified node and a few nodes underneath it, but not the whole subtree.
/// This is useful in a debugger.
void Stmt::dump(SourceManager &SM) const {
dump(llvm::errs(), SM);
}
void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
StmtDumper P(&SM, OS, 4);
P.DumpSubTree(const_cast<Stmt*>(this));
OS << "\n";
}
/// dump - This does a local dump of the specified AST fragment. It dumps the
/// specified node and a few nodes underneath it, but not the whole subtree.
/// This is useful in a debugger.
void Stmt::dump() const {
StmtDumper P(0, llvm::errs(), 4);
P.DumpSubTree(const_cast<Stmt*>(this));
llvm::errs() << "\n";
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll(SourceManager &SM) const {
StmtDumper P(&SM, llvm::errs(), ~0U);
P.DumpSubTree(const_cast<Stmt*>(this));
llvm::errs() << "\n";
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll() const {
StmtDumper P(0, llvm::errs(), ~0U);
P.DumpSubTree(const_cast<Stmt*>(this));
llvm::errs() << "\n";
}