From: Zhongxing Xu Date: Tue, 16 Nov 2010 07:52:17 +0000 (+0000) Subject: Handle member initializer in C++ ctor. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9dc84c9455df2a77195147d0210c915dc1775a88;p=clang Handle member initializer in C++ ctor. - Add a new Kind of ProgramPoint: PostInitializer. - Still use GRStmtNodeBuilder. But special handling PostInitializer in GRStmtNodeBuilder::GenerateAutoTransition(). - Someday we should clean up the interface of GRStmtNodeBuilder. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119335 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index eae3e69476..89295e4c7e 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -3468,7 +3468,7 @@ public: BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef, bool constAdded = false, Stmt *copyConstructorVal = 0) - : Expr(BlockDeclRefExprClass, t, (!t.isNull() && t->isDependentType()),false), + : Expr(BlockDeclRefExprClass, t, (!t.isNull() && t->isDependentType()),false), D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal) {} diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index c29fd02c0a..a77ca39b15 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -44,6 +44,7 @@ public: PostPurgeDeadSymbolsKind, PostStmtCustomKind, PostLValueKind, + PostInitializerKind, CallEnterKind, CallExitKind, MinPostStmtKind = PostStmtKind, @@ -304,6 +305,17 @@ public: } }; +class PostInitializer : public ProgramPoint { +public: + PostInitializer(const CXXBaseOrMemberInitializer *I, + const LocationContext *L) + : ProgramPoint(I, PostInitializerKind, L) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == PostInitializerKind; + } +}; + class CallEnter : public StmtPoint { public: // L is caller's location context. AC is callee's AnalysisContext. diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h index 411f29d802..58c148f66d 100644 --- a/include/clang/Checker/PathSensitive/GRCoreEngine.h +++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h @@ -72,8 +72,7 @@ private: void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred); void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred); void HandleBlockExit(const CFGBlock* B, ExplodedNode* Pred); - void HandlePostStmt(const PostStmt& S, const CFGBlock* B, - unsigned StmtIdx, ExplodedNode *Pred); + void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred); void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B, ExplodedNode* Pred); diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index ab6a74dc34..80c53107b5 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -438,7 +438,7 @@ public: ExplodedNodeSet &Dst); /// Synthesize CXXThisRegion. - const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD, + const CXXThisRegion *getCXXThisRegion(const CXXRecordDecl *RD, const StackFrameContext *SFC); /// Evaluate arguments with a work list algorithm. diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp index 890387632f..072c21e721 100644 --- a/lib/Checker/GRCXXExprEngine.cpp +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -64,10 +64,10 @@ void GRExprEngine::EvalArguments(ConstExprIterator AI, ConstExprIterator AE, } } -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXRecordDecl *D, const StackFrameContext *SFC) { - Type *T = D->getParent()->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T,0)); + Type *T = D->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T, 0)); return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); } @@ -121,7 +121,8 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, Pred->getLocationContext(), E, Builder->getBlock(), Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); + const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(), + SFC); CallEnter Loc(E, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), @@ -182,7 +183,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, MCE, Builder->getBlock(), Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + const CXXThisRegion *ThisR = getCXXThisRegion(MD->getParent(), SFC); CallEnter Loc(MCE, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(), E = PreVisitChecks.end(); I != E; ++I) { diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index 01d254c8f4..c77a0228e4 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -233,9 +233,9 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, break; default: - assert(isa(Node->getLocation())); - HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), - WU.getIndex(), Node); + assert(isa(Node->getLocation()) || + isa(Node->getLocation())); + HandlePostStmt(WU.getBlock(), WU.getIndex(), Node); break; } } @@ -413,9 +413,8 @@ void GRCoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term, ProcessBranch(Cond, Term, Builder); } -void GRCoreEngine::HandlePostStmt(const PostStmt& L, const CFGBlock* B, - unsigned StmtIdx, ExplodedNode* Pred) { - +void GRCoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, + ExplodedNode* Pred) { assert (!B->empty()); if (StmtIdx == B->size()) @@ -473,6 +472,12 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { return; } + // Do not create extra nodes. Move to the next CFG element. + if (isa(N->getLocation())) { + Eng.WList->Enqueue(N, &B, Idx+1); + return; + } + PostStmt Loc(getStmt(), N->getLocationContext()); if (Loc == N->getLocation()) { diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 017a6959cc..acb67d63dc 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -327,7 +327,7 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) SymMgr(StateMgr.getSymbolManager()), ValMgr(StateMgr.getValueManager()), SVator(ValMgr.getSValuator()), - CurrentStmt(NULL), + EntryNode(NULL), CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", getContext())), BR(mgr, *this), TF(tf) { @@ -679,8 +679,41 @@ void GRExprEngine::ProcessStmt(const CFGStmt S, GRStmtNodeBuilder& builder) { Builder = NULL; } -void GRExprEngine::ProcessInitializer(const CFGInitializer I, +void GRExprEngine::ProcessInitializer(const CFGInitializer Init, GRStmtNodeBuilder &builder) { + // We don't set EntryNode and CurrentStmt. And we don't clean up state. + const CXXBaseOrMemberInitializer *BMI = Init.getInitializer(); + + ExplodedNode *Pred = builder.getBasePredecessor(); + const LocationContext *LC = Pred->getLocationContext(); + + if (BMI->isMemberInitializer()) { + ExplodedNodeSet Dst; + + // Evaluate the initializer. + Visit(BMI->getInit(), Pred, Dst); + + for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){ + ExplodedNode *Pred = *I; + const GRState *state = Pred->getState(); + + const FieldDecl *FD = BMI->getMember(); + const RecordDecl *RD = FD->getParent(); + const CXXThisRegion *ThisR = getCXXThisRegion(cast(RD), + cast(LC)); + + SVal ThisV = state->getSVal(ThisR); + SVal FieldLoc = state->getLValue(FD, ThisV); + SVal InitVal = state->getSVal(BMI->getInit()); + state = state->bindLoc(FieldLoc, InitVal); + + // Use a custom node building process. + PostInitializer PP(BMI, LC); + // Builder automatically add the generated node to the deferred set, + // which are processed in the builder's dtor. + builder.generateNode(PP, state, Pred); + } + } } void GRExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, @@ -1566,7 +1599,8 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { // Bind the constructed object value to CXXConstructExpr. if (const CXXConstructExpr *CCE = dyn_cast(CE)) { - const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx); + const CXXThisRegion *ThisR = + getCXXThisRegion(CCE->getConstructor()->getParent(), LocCtx); // We might not have 'this' region in the binding if we didn't inline // the ctor call. SVal ThisV = state->getSVal(ThisR); diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp new file mode 100644 index 0000000000..2fa3a9eb86 --- /dev/null +++ b/test/Analysis/initializer.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -cfg-add-initializers -verify %s + +class A { + int x; +public: + A(); +}; + +A::A() : x(0) { + if (x != 0) { + int *p = 0; + *p = 0; // no-warning + } +}