From: Zhongxing Xu Date: Thu, 1 Apr 2010 07:58:50 +0000 (+0000) Subject: Initial support for visiting CXXMemberCallExpr. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=950db87e5efe2ff0c7234116929f8637aaf7ae7a;p=clang Initial support for visiting CXXMemberCallExpr. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100098 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index 97f6d70f57..161cb28df0 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -348,6 +348,10 @@ public: void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -356,7 +360,7 @@ public: ExplodedNodeSet &Dst); /// Synthesize CXXThisRegion. - const CXXThisRegion *getCXXThisRegion(const CXXConstructExpr *E, + const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD, const StackFrameContext *SFC); /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 2e40a93470..bab8922a8c 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -584,7 +584,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXMemberCallExprClass: case Stmt::CXXNamedCastExprClass: case Stmt::CXXStaticCastExprClass: case Stmt::CXXDynamicCastExprClass: @@ -673,6 +672,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXMemberCallExprClass: { + CXXMemberCallExpr *MCE = cast(S); + VisitCXXMemberCallExpr(MCE, Pred, Dst); + break; + } + // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. @@ -1342,7 +1347,7 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { // Bind the constructed object value to CXXConstructExpr. if (const CXXConstructExpr *CCE = dyn_cast(CE)) { - const CXXThisRegion *ThisR = getCXXThisRegion(CCE, LocCtx); + const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx); // We might not have 'this' region in the binding if we didn't inline // the ctor call. SVal ThisV = state->getSVal(ThisR); @@ -3222,7 +3227,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, Pred->getLocationContext(), E, Builder->getBlock(), Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(E, SFC); + const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); CallEnter Loc(E, CD, Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), @@ -3236,12 +3241,90 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, } } -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXConstructExpr *E, +void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the method type. + const FunctionProtoType *FnType = + MCE->getCallee()->getType()->getAs(); + assert(FnType && "Method type not available"); + + // Evaluate explicit arguments with a worklist. + CallExpr::arg_iterator AB = const_cast(MCE)->arg_begin(), + AE = const_cast(MCE)->arg_end(); + llvm::SmallVector WorkList; + WorkList.reserve(AE - AB); + WorkList.push_back(CallExprWLItem(AB, Pred)); + ExplodedNodeSet ArgsEvaluated; + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AB; + bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType(); + + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } + // Evaluate the implicit object argument. + ExplodedNodeSet AllArgsEvaluated; + const MemberExpr *ME = dyn_cast(MCE->getCallee()->IgnoreParens()); + if (!ME) + return; + Expr *ObjArgExpr = ME->getBase(); + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + if (ME->isArrow()) + Visit(ObjArgExpr, *I, AllArgsEvaluated); + else + VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); + } + + const CXXMethodDecl *MD = cast(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + + if (!MD->isThisDeclarationADefinition()) + // FIXME: conservative method call evaluation. + return; + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, MD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), + E = AllArgsEvaluated.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); + ExplodedNode *N = Builder->generateNode(Loc, state, *I); + if (N) + Dst.Add(N); + } +} + +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, const StackFrameContext *SFC) { - Type *T = E->getConstructor()->getParent()->getTypeForDecl(); + Type *T = D->getParent()->getTypeForDecl(); QualType PT = getContext().getPointerType(QualType(T,0)); return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); } + //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===//