]> granicus.if.org Git - clang/commitdiff
Handle member initializer in C++ ctor.
authorZhongxing Xu <xuzhongxing@gmail.com>
Tue, 16 Nov 2010 07:52:17 +0000 (07:52 +0000)
committerZhongxing Xu <xuzhongxing@gmail.com>
Tue, 16 Nov 2010 07:52:17 +0000 (07:52 +0000)
 - 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

include/clang/AST/Expr.h
include/clang/Analysis/ProgramPoint.h
include/clang/Checker/PathSensitive/GRCoreEngine.h
include/clang/Checker/PathSensitive/GRExprEngine.h
lib/Checker/GRCXXExprEngine.cpp
lib/Checker/GRCoreEngine.cpp
lib/Checker/GRExprEngine.cpp
test/Analysis/initializer.cpp [new file with mode: 0644]

index eae3e6947641f930f32ca5cee0dd660af881d044..89295e4c7e7b75dd482f0ffbcc9eeb1674d5a8f2 100644 (file)
@@ -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) {}
 
index c29fd02c0a2555a91b73c91bbfbba43d316a097d..a77ca39b1590292613cd6a8610a6734f1c055b8b 100644 (file)
@@ -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.
index 411f29d80238ad17bd43e3fba4ae2407c22f1a47..58c148f66d22fa05a0e18dd4539d038c0cdfedac 100644 (file)
@@ -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);
index ab6a74dc34a40f5f6857f96f43ff5fb8e6fc4936..80c53107b5fb01dd866e20e496a88e9247fcb85a 100644 (file)
@@ -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.
index 890387632fd6fccb160c85bf861f8222454f7c3a..072c21e721873c6a48d8c4d99eb98967dd57a82c 100644 (file)
@@ -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) {
index 01d254c8f476476a9ec3796c83bc32dff23f1b5d..c77a0228e46c943a3cd1406ac0c5889031c81d45 100644 (file)
@@ -233,9 +233,9 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
         break;
 
       default:
-        assert(isa<PostStmt>(Node->getLocation()));
-        HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
-                       WU.getIndex(), Node);
+        assert(isa<PostStmt>(Node->getLocation()) || 
+               isa<PostInitializer>(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<PostInitializer>(N->getLocation())) {
+    Eng.WList->Enqueue(N, &B, Idx+1);
+    return;
+  }
+
   PostStmt Loc(getStmt(), N->getLocationContext());
 
   if (Loc == N->getLocation()) {
index 017a6959cc902c652fa244ebcbb49505e8d111a8..acb67d63dc97b30a60c130b3eb4a5a6bbb0d95e8 100644 (file)
@@ -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<CXXRecordDecl>(RD),
+                           cast<StackFrameContext>(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<CXXConstructExpr>(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 (file)
index 0000000..2fa3a9e
--- /dev/null
@@ -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
+  }
+}