summaryrefslogtreecommitdiffstats
path: root/clang/lib/Checker
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-04-21 00:45:42 +0000
committerDouglas Gregor <dgregor@apple.com>2010-04-21 00:45:42 +0000
commit9a1291942127751d4621f930d048fe22496e9681 (patch)
tree8144f1d1e9757feb6a4993ba298ac25b1d2fec86 /clang/lib/Checker
parent2034d9f2da93cd830f4f1ed568f71c1a232e3ed7 (diff)
downloadbcm5719-llvm-9a1291942127751d4621f930d048fe22496e9681.tar.gz
bcm5719-llvm-9a1291942127751d4621f930d048fe22496e9681.zip
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
Diffstat (limited to 'clang/lib/Checker')
-rw-r--r--clang/lib/Checker/BasicObjCFoundationChecks.cpp41
-rw-r--r--clang/lib/Checker/BugReporterVisitors.cpp10
-rw-r--r--clang/lib/Checker/CFRefCount.cpp113
-rw-r--r--clang/lib/Checker/CallAndMessageChecker.cpp12
-rw-r--r--clang/lib/Checker/CheckObjCDealloc.cpp20
-rw-r--r--clang/lib/Checker/GRExprEngine.cpp8
-rw-r--r--clang/lib/Checker/NSAutoreleasePoolChecker.cpp2
7 files changed, 132 insertions, 74 deletions
diff --git a/clang/lib/Checker/BasicObjCFoundationChecks.cpp b/clang/lib/Checker/BasicObjCFoundationChecks.cpp
index 810d0fbb997..e7275ca551c 100644
--- a/clang/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -31,13 +31,22 @@
using namespace clang;
static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- const Expr* Receiver = ME->getReceiver();
-
- if (!Receiver)
- return NULL;
+ QualType T;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ T = ME->getInstanceReceiver()->getType();
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ T = ME->getSuperType();
+ break;
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ return 0;
+ }
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
+ if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
return PT->getInterfaceType();
return NULL;
@@ -509,11 +518,21 @@ public:
void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
-
- const IdentifierInfo *ClsName = ME->getClassName();
- if (!ClsName)
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
return;
-
+ }
+
Selector S = ME->getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
os << "The '" << S.getAsString() << "' message should be sent to instances "
- "of class '" << ClsName->getName()
+ "of class '" << Class->getName()
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
diff --git a/clang/lib/Checker/BugReporterVisitors.cpp b/clang/lib/Checker/BugReporterVisitors.cpp
index 544129bbf28..776e12bd2ae 100644
--- a/clang/lib/Checker/BugReporterVisitors.cpp
+++ b/clang/lib/Checker/BugReporterVisitors.cpp
@@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
}
const Stmt*
-clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
- if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
- return ME->getReceiver();
- return NULL;
-}
-
-const Stmt*
clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
@@ -402,7 +394,7 @@ public:
const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
if (!ME)
return 0;
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
if (!Receiver)
return 0;
const GRState *state = N->getState();
diff --git a/clang/lib/Checker/CFRefCount.cpp b/clang/lib/Checker/CFRefCount.cpp
index a0b46661600..d26ee1db565 100644
--- a/clang/lib/Checker/CFRefCount.cpp
+++ b/clang/lib/Checker/CFRefCount.cpp
@@ -603,12 +603,33 @@ public:
Selector S = ME->getSelector();
- if (Expr* Receiver = ME->getReceiver()) {
- const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
- return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+ const ObjCInterfaceDecl* OD = 0;
+ bool IsInstanceMessage = false;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ OD = getReceiverDecl(ME->getInstanceReceiver());
+ IsInstanceMessage = true;
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ IsInstanceMessage = true;
+ OD = ME->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
+
+ case ObjCMessageExpr::Class:
+ OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
}
- return M[ObjCSummaryKey(ME->getClassName(), S)];
+ if (IsInstanceMessage)
+ return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+
+ return M[ObjCSummaryKey(OD->getIdentifier(), S)];
}
RetainSummary*& operator[](ObjCSummaryKey K) {
@@ -836,7 +857,7 @@ public:
RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
- return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
+ return getInstanceMethodSummary(ME->getSelector(), 0,
ID, ME->getMethodDecl(), ME->getType());
}
@@ -851,8 +872,21 @@ public:
QualType RetTy);
RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
- return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
- ME->getClassInfo().Decl,
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getReceiverInterface();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
+ break;
+ }
+
+ return getClassMethodSummary(ME->getSelector(),
+ Class? Class->getIdentifier() : 0,
+ Class,
ME->getMethodDecl(), ME->getType());
}
@@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
// we just use the 'ID' from the message expression.
- SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+ SVal receiverV;
+
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ receiverV = state->getSValAsScalarOrLoc(Receiver);
- // FIXME: Eventually replace the use of state->get<RefBindings> with
- // a generic API for reasoning about the Objective-C types of symbolic
- // objects.
- if (SymbolRef Sym = receiverV.getAsLocSymbol())
- if (const RefVal *T = state->get<RefBindings>(Sym))
- if (const ObjCObjectPointerType* PT =
+ // FIXME: Eventually replace the use of state->get<RefBindings> with
+ // a generic API for reasoning about the Objective-C types of symbolic
+ // objects.
+ if (SymbolRef Sym = receiverV.getAsLocSymbol())
+ if (const RefVal *T = state->get<RefBindings>(Sym))
+ if (const ObjCObjectPointerType* PT =
T->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ ID = PT->getInterfaceDecl();
- // FIXME: this is a hack. This may or may not be the actual method
- // that is called.
- if (!ID) {
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+ }
+ } else {
+ // FIXME: Hack for 'super'.
+ ID = ME->getReceiverInterface();
}
-
+
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
- if (isa<ObjCMethodDecl>(LC->getDecl())) {
+ if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
// Get the region associated with 'self'.
if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
@@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
- if (const Expr *receiver = ME->getReceiver())
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
@@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
// id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
// is a call to a class method whose type we can resolve. In such
// cases, promote the return type to XXX* (where XXX is the class).
- const ObjCInterfaceDecl *D = ME->getClassInfo().Decl;
+ const ObjCInterfaceDecl *D = ME->getReceiverInterface();
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
}
@@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- assert(Receiver);
- SVal V = state->getSValAsScalarOrLoc(Receiver);
bool found = false;
- if (SymbolRef Sym = V.getAsLocSymbol())
- if (state->get<RefBindings>(Sym)) {
- found = true;
- RE = Summaries.getObjAllocRetEffect();
- }
-
+ if (Receiver) {
+ SVal V = state->getSValAsScalarOrLoc(Receiver);
+ if (SymbolRef Sym = V.getAsLocSymbol())
+ if (state->get<RefBindings>(Sym)) {
+ found = true;
+ RE = Summaries.getObjAllocRetEffect();
+ }
+ } // FIXME: Otherwise, this is a send-to-super instance message.
if (!found)
RE = RetEffect::MakeNoRet();
}
@@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
ExplodedNode* Pred,
const GRState *state) {
RetainSummary *Summ =
- ME->getReceiver()
+ ME->isInstanceMessage()
? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+ EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
ME->arg_begin(), ME->arg_end(), Pred, state);
}
diff --git a/clang/lib/Checker/CallAndMessageChecker.cpp b/clang/lib/Checker/CallAndMessageChecker.cpp
index ce9f26ec69e..9d0dc333952 100644
--- a/clang/lib/Checker/CallAndMessageChecker.cpp
+++ b/clang/lib/Checker/CallAndMessageChecker.cpp
@@ -218,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const GRState *state = C.getState();
- if (const Expr *receiver = ME->getReceiver())
+ // FIXME: Handle 'super'?
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (state->getSVal(receiver).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_msg_undef)
@@ -265,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
<< ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
- const Expr *receiver = ME->getReceiver();
- report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
+ if (const Expr *receiver = ME->getInstanceReceiver()) {
+ report->addRange(receiver->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ }
C.EmitReport(report);
}
diff --git a/clang/lib/Checker/CheckObjCDealloc.cpp b/clang/lib/Checker/CheckObjCDealloc.cpp
index f510de573e2..c23be873f48 100644
--- a/clang/lib/Checker/CheckObjCDealloc.cpp
+++ b/clang/lib/Checker/CheckObjCDealloc.cpp
@@ -27,10 +27,14 @@ using namespace clang;
static bool scan_dealloc(Stmt* S, Selector Dealloc) {
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Dealloc)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
- return isa<ObjCSuperExpr>(Receiver);
+ if (ME->getSelector() == Dealloc) {
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: return false;
+ case ObjCMessageExpr::SuperInstance: return true;
+ case ObjCMessageExpr::Class: break;
+ case ObjCMessageExpr::SuperClass: break;
+ }
+ }
// Recurse to children.
@@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// [mMyIvar release]
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
return true;
// [self setMyIvar:nil];
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
diff --git a/clang/lib/Checker/GRExprEngine.cpp b/clang/lib/Checker/GRExprEngine.cpp
index b5f8fee5a22..a39e7f57b1c 100644
--- a/clang/lib/Checker/GRExprEngine.cpp
+++ b/clang/lib/Checker/GRExprEngine.cpp
@@ -2124,7 +2124,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// But first evaluate the receiver (if any).
ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
- if (Expr *Receiver = ME->getReceiver()) {
+ if (Expr *Receiver = ME->getInstanceReceiver()) {
ExplodedNodeSet Tmp;
Visit(Receiver, Pred, Tmp);
@@ -2176,7 +2176,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
- if (const Expr *Receiver = ME->getReceiver()) {
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
const GRState *state = GetState(Pred);
// Bifurcate the state into nil and non-nil ones.
@@ -2206,8 +2206,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// Dispatch to plug-in transfer function.
EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
- else {
- IdentifierInfo* ClsName = ME->getClassName();
+ else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
+ IdentifierInfo* ClsName = Iface->getIdentifier();
Selector S = ME->getSelector();
// Check for special instance methods.
diff --git a/clang/lib/Checker/NSAutoreleasePoolChecker.cpp b/clang/lib/Checker/NSAutoreleasePoolChecker.cpp
index 29bac9c384c..48f03a369ed 100644
--- a/clang/lib/Checker/NSAutoreleasePoolChecker.cpp
+++ b/clang/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -56,7 +56,7 @@ void
NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
- const Expr *receiver = ME->getReceiver();
+ const Expr *receiver = ME->getInstanceReceiver();
if (!receiver)
return;
OpenPOWER on IntegriCloud