1294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//=-- ExprEngineObjC.cpp - ExprEngine support for Objective-C ---*- C++ -*-===//
2294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//
3294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//                     The LLVM Compiler Infrastructure
4294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//
5294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek// This file is distributed under the University of Illinois Open Source
6294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek// License. See LICENSE.TXT for details.
7294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//
8294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//===----------------------------------------------------------------------===//
9294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//
10294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//  This file defines ExprEngine's support for Objective-C expressions.
11294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//
12294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek//===----------------------------------------------------------------------===//
13294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
14c35fb7d67d515659ad2325b4f6ec97c9fe64fb63Benjamin Kramer#include "clang/AST/StmtObjC.h"
15294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek#include "clang/StaticAnalyzer/Core/CheckerManager.h"
16f540c54701e3eeb34cb619a3a4eb18f1ac70ef2dJordan Rose#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
18294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
19294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenekusing namespace clang;
20294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenekusing namespace ento;
21294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
22294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenekvoid ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
23294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                          ExplodedNode *Pred,
24294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                          ExplodedNodeSet &Dst) {
258bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = Pred->getState();
265eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek  const LocationContext *LCtx = Pred->getLocationContext();
275eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek  SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
28294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  SVal location = state->getLValue(Ex->getDecl(), baseVal);
29294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
30294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  ExplodedNodeSet dstIvar;
3166c486f275531df6362b3511fc3af6563561801bTed Kremenek  StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
325eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek  Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
33294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
34294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // Perform the post-condition check of the ObjCIvarRefExpr and store
35294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // the created nodes in 'Dst'.
36294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
37294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek}
38294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
39294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenekvoid ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
40294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                             ExplodedNode *Pred,
41294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                             ExplodedNodeSet &Dst) {
42294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
43294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek}
44294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
45294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenekvoid ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
46294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                            ExplodedNode *Pred,
47294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                            ExplodedNodeSet &Dst) {
48294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
49294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // ObjCForCollectionStmts are processed in two places.  This method
50294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // handles the case where an ObjCForCollectionStmt* occurs as one of the
51294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // statements within a basic block.  This transfer function does two things:
52294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //
53294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //  (1) binds the next container value to 'element'.  This creates a new
54294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //      node in the ExplodedGraph.
55294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //
56294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //  (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
57294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //      whether or not the container has any more elements.  This value
58294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //      will be tested in ProcessBranch.  We need to explicitly bind
59294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //      this value because a container can contain nil elements.
60294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //
61294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // FIXME: Eventually this logic should actually do dispatches to
62294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
63294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   This will require simulating a temporary NSFastEnumerationState, either
64294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   through an SVal or through the use of MemRegions.  This value can
65294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
66294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   terminates we reclaim the temporary (it goes out of scope) and we
67294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   we can test if the SVal is 0 or if the MemRegion is null (depending
68294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //   on what approach we take).
69294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //
70294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //  For now: simulate (1) by assigning either a symbol or nil if the
71294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //    container is empty.  Thus this transfer function will by default
72294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  //    result in state splitting.
73ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14Anna Zaks
74294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  const Stmt *elem = S->getElement();
758bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = Pred->getState();
76294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  SVal elementV;
77294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
78294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
79294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
80294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    assert(elemD->getInit() == 0);
81294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    elementV = state->getLValue(elemD, Pred->getLocationContext());
82294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  }
83294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  else {
845eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek    elementV = state->getSVal(elem, Pred->getLocationContext());
85294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  }
86294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
87294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  ExplodedNodeSet dstLocation;
88bd613137499b1d4c3b63dccd0aa21f6add243f4fTed Kremenek  evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
891895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose
901895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose  ExplodedNodeSet Tmp;
9166c486f275531df6362b3511fc3af6563561801bTed Kremenek  StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
921895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose
93294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
94294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek       NE = dstLocation.end(); NI!=NE; ++NI) {
95294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    Pred = *NI;
968bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek    ProgramStateRef state = Pred->getState();
975eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek    const LocationContext *LCtx = Pred->getLocationContext();
98294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
99294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    // Handle the case where the container still has elements.
100294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    SVal TrueV = svalBuilder.makeTruthVal(1);
1018bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek    ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
102294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
103294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    // Handle the case where the container has no elements.
104294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    SVal FalseV = svalBuilder.makeTruthVal(0);
1058bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek    ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
106294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
107294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
108294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek      if (const TypedValueRegion *R =
109294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek          dyn_cast<TypedValueRegion>(MV->getRegion())) {
110294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        // FIXME: The proper thing to do is to really iterate over the
111294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        //  container.  We will do this with dispatch logic to the store.
112294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        //  For now, just 'conjure' up a symbolic value.
113294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        QualType T = R->getValueType();
114294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        assert(Loc::isLocType(T));
11566c486f275531df6362b3511fc3af6563561801bTed Kremenek        SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
11666c486f275531df6362b3511fc3af6563561801bTed Kremenek                                             currBldrCtx->blockCount());
117294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        SVal V = svalBuilder.makeLoc(Sym);
118294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        hasElems = hasElems->bindLoc(elementV, V);
119294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
120294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        // Bind the location to 'nil' on the false branch.
121294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        SVal nilV = svalBuilder.makeIntVal(0, T);
122294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        noElems = noElems->bindLoc(elementV, nilV);
123294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek      }
124294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
125294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    // Create the new nodes.
126ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14Anna Zaks    Bldr.generateNode(S, Pred, hasElems);
127ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14Anna Zaks    Bldr.generateNode(S, Pred, noElems);
128294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  }
1291895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose
1301895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose  // Finally, run any custom checkers.
1311895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose  // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
1321895a0a6936001374f66adbdfcf8abe5edf912eaJordan Rose  getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
133294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek}
134294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
1356c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rosestatic bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
1366c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose  if (!Class)
1376c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose    return false;
1386c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose  if (Class->getIdentifier() == II)
1396c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose    return true;
1406c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose  return isSubclass(Class->getSuperClass(), II);
1416c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose}
1426c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose
143d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rosevoid ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
144294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                  ExplodedNode *Pred,
145294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek                                  ExplodedNodeSet &Dst) {
146d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose  CallEventManager &CEMgr = getStateManager().getCallEventManager();
147d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose  CallEventRef<ObjCMethodCall> Msg =
148d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose    CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
149d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose
150294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // Handle the previsits checks.
151294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  ExplodedNodeSet dstPrevisit;
15296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
153d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose                                                   *Msg, *this);
15496479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  ExplodedNodeSet dstGenericPrevisit;
15596479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
156d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose                                            *Msg, *this);
15796479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose
158294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // Proceed with evaluate the message expression.
159294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  ExplodedNodeSet dstEval;
16066c486f275531df6362b3511fc3af6563561801bTed Kremenek  StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
161ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14Anna Zaks
16296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
16396479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose       DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
164294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    ExplodedNode *Pred = *DI;
165d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose    ProgramStateRef State = Pred->getState();
166d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose    CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
167294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
168d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose    if (UpdatedMsg->isInstanceMessage()) {
169d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose      SVal recVal = UpdatedMsg->getReceiverSVal();
170294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek      if (!recVal.isUndef()) {
171294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        // Bifurcate the state into nil and non-nil ones.
172294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
173294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
1748bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek        ProgramStateRef notNilState, nilState;
175d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose        llvm::tie(notNilState, nilState) = State->assume(receiverVal);
176294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
177294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        // There are three cases: can be nil or non-nil, must be nil, must be
178294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        // non-nil. We ignore must be nil, and merge the rest two into non-nil.
179cde8cdbd6a662c636164465ad309b5f17ff01064Jordan Rose        // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
180cde8cdbd6a662c636164465ad309b5f17ff01064Jordan Rose        // Revisit once we have lazier constraints.
181294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        if (nilState && !notNilState) {
182294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek          continue;
183294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        }
184294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
185294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        // Check if the "raise" message was sent.
186294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        assert(notNilState);
187d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose        if (Msg->getSelector() == RaiseSel) {
188e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks          // If we raise an exception, for now treat it as a sink.
189e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks          // Eventually we will want to handle exceptions properly.
19066c486f275531df6362b3511fc3af6563561801bTed Kremenek          Bldr.generateSink(currStmt, Pred, State);
191e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks          continue;
192e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks        }
193294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
194e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks        // Generate a transition to non-Nil state.
19582f2ad456a82da1b9cb7ddfc994c8f5fa44b59e6Jordan Rose        if (notNilState != State) {
19666c486f275531df6362b3511fc3af6563561801bTed Kremenek          Pred = Bldr.generateNode(currStmt, Pred, notNilState);
19782f2ad456a82da1b9cb7ddfc994c8f5fa44b59e6Jordan Rose          assert(Pred && "Should have cached out already!");
19882f2ad456a82da1b9cb7ddfc994c8f5fa44b59e6Jordan Rose        }
199294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek      }
200cde8cdbd6a662c636164465ad309b5f17ff01064Jordan Rose    } else {
2016c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose      // Check for special class methods.
202d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose      if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
2036c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose        if (!NSExceptionII) {
204294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek          ASTContext &Ctx = getContext();
2056c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose          NSExceptionII = &Ctx.Idents.get("NSException");
206294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek        }
207294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
2086c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose        if (isSubclass(Iface, NSExceptionII)) {
2096c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose          enum { NUM_RAISE_SELECTORS = 2 };
2106c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose
2116c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose          // Lazily create a cache of the selectors.
2126c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose          if (!NSExceptionInstanceRaiseSelectors) {
2136c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            ASTContext &Ctx = getContext();
2146c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            NSExceptionInstanceRaiseSelectors =
2156c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose              new Selector[NUM_RAISE_SELECTORS];
2166c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
2176c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            unsigned idx = 0;
2186c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose
2196c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            // raise:format:
2206c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            II.push_back(&Ctx.Idents.get("raise"));
2216c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            II.push_back(&Ctx.Idents.get("format"));
2226c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            NSExceptionInstanceRaiseSelectors[idx++] =
2236c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose              Ctx.Selectors.getSelector(II.size(), &II[0]);
2246c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose
2256c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            // raise:format:arguments:
2266c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            II.push_back(&Ctx.Idents.get("arguments"));
2276c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            NSExceptionInstanceRaiseSelectors[idx++] =
2286c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose              Ctx.Selectors.getSelector(II.size(), &II[0]);
2296c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose          }
2306c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose
231d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose          Selector S = Msg->getSelector();
232e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks          bool RaisesException = false;
2336c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose          for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
2346c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            if (S == NSExceptionInstanceRaiseSelectors[i]) {
2356c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose              RaisesException = true;
2366c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose              break;
2376c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose            }
238294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek          }
239e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks          if (RaisesException) {
240e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks            // If we raise an exception, for now treat it as a sink.
241e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks            // Eventually we will want to handle exceptions properly.
24266c486f275531df6362b3511fc3af6563561801bTed Kremenek            Bldr.generateSink(currStmt, Pred, Pred->getState());
243e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks            continue;
244e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks          }
245e81ce256b62717dd846bd19aecc4115a0dcd4995Anna Zaks
2466c234b1fd1da64a14a77433cb805cb1aa798512aJordan Rose        }
247294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek      }
248294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek    }
2499dc5167e4017ef4c8b327abb6f72225eec2e0f19Anna Zaks
25082f2ad456a82da1b9cb7ddfc994c8f5fa44b59e6Jordan Rose    defaultEvalCall(Bldr, Pred, *UpdatedMsg);
251294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  }
252294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek
25396479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  ExplodedNodeSet dstPostvisit;
254d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose  getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
255d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose                                             *Msg, *this);
25696479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose
257294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // Finally, perform the post-condition check of the ObjCMessageExpr and store
258294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek  // the created nodes in 'Dst'.
25996479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose  getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
260d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose                                                    *Msg, *this);
261294fd0a62b95f512637910bf85c7efa6c2354b50Ted Kremenek}
262