]> granicus.if.org Git - clang/commitdiff
[analyzer] Add a CXXDestructorCall CallEvent.
authorJordan Rose <jordan_rose@apple.com>
Tue, 10 Jul 2012 22:07:47 +0000 (22:07 +0000)
committerJordan Rose <jordan_rose@apple.com>
Tue, 10 Jul 2012 22:07:47 +0000 (22:07 +0000)
While this work is still fairly tentative (destructors are still left out of
the CFG by default), we now handle destructors in the same way as any other
calls, instead of just automatically trying to inline them.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160020 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
lib/StaticAnalyzer/Core/Calls.cpp
lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

index 0d830c3ce9a112ef7593352cf5fd6f6221dfdb59..e1d30e42c2578fffcac2a424a2125f53629106fa 100644 (file)
@@ -37,6 +37,7 @@ enum CallEventKind {
   CE_BEG_SIMPLE_CALLS = CE_Function,
   CE_END_SIMPLE_CALLS = CE_Block,
   CE_CXXConstructor,
+  CE_CXXDestructor,
   CE_CXXAllocator,
   CE_BEG_FUNCTION_CALLS = CE_Function,
   CE_END_FUNCTION_CALLS = CE_CXXAllocator,
@@ -159,7 +160,7 @@ public:
   }
 
   /// \brief Returns an appropriate ProgramPoint for this call.
-  ProgramPoint getProgramPoint(bool IsPreVisit,
+  ProgramPoint getProgramPoint(bool IsPreVisit = false,
                                const ProgramPointTag *Tag = 0) const;
 
   /// \brief Returns a new state with all argument regions invalidated.
@@ -391,6 +392,36 @@ public:
   }
 };
 
+/// \brief Represents an implicit call to a C++ destructor.
+///
+/// This can occur at the end of a scope (for automatic objects), at the end
+/// of a full-expression (for temporaries), or as part of a delete.
+class CXXDestructorCall : public AnyFunctionCall {
+  const CXXDestructorDecl *DD;
+  const MemRegion *Target;
+  SourceLocation Loc;
+
+protected:
+  void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+  CXXDestructorCall(const CXXDestructorDecl *dd, const Stmt *Trigger,
+                    const MemRegion *target, ProgramStateRef St,
+                    const LocationContext *LCtx)
+    : AnyFunctionCall(St, LCtx, CE_CXXDestructor), DD(dd), Target(target),
+      Loc(Trigger->getLocEnd()) {}
+
+  const Expr *getOriginExpr() const { return 0; }
+  SourceRange getSourceRange() const { return Loc; }
+
+  const CXXDestructorDecl *getDecl() const { return DD; }
+  unsigned getNumArgs() const { return 0; }
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() == CE_CXXDestructor;
+  }
+};
+
 /// \brief Represents the memory allocation call in a C++ new-expression.
 ///
 /// This is a call to "operator new".
index 32f7706bd94aa108b272d1f0359c73126a64ccd0..541a8b7c15760ac082ae2f4ba1a15d6e125844e7 100644 (file)
@@ -948,6 +948,7 @@ RetainSummaryManager::getSummary(const CallEvent &Call,
   case CE_CXXMemberOperator:
   case CE_Block:
   case CE_CXXConstructor:
+  case CE_CXXDestructor:
   case CE_CXXAllocator:
     // FIXME: These calls are currently unsupported.
     return getPersistentStopSummary();
index 7b86d442765b58678abd91b31d44e940a1f95b1d..8ea1336bb7b1ab1b2fc4c1ebab5887ad8d71b869 100644 (file)
@@ -372,6 +372,12 @@ void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
 }
 
 
+void CXXDestructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+  if (Target)
+    Regions.push_back(Target);
+}
+
+
 CallEvent::param_iterator ObjCMethodCall::param_begin() const {
   const ObjCMethodDecl *D = getDecl();
   if (!D)
index bac5b70f699422abf97c64173854d3a249584f01..3fa052817c2751548af50e167e89469070a3aab6 100644 (file)
@@ -75,21 +75,21 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
                                       const Stmt *S,
                                       ExplodedNode *Pred, 
                                       ExplodedNodeSet &Dst) {
-  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
-  if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
-    return;
+  CXXDestructorCall Call(DD, S, Dest, Pred->getState(),
+                         Pred->getLocationContext());
 
-  // Create the context for 'this' region.
-  const StackFrameContext *SFC =
-    AnalysisDeclContexts.getContext(DD)->
-      getStackFrame(Pred->getLocationContext(), S,
-      currentBuilderContext->getBlock(), currentStmtIdx);
+  ExplodedNodeSet DstPreCall;
+  getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
+                                            Call, *this);
 
-  CallEnter PP(S, SFC, Pred->getLocationContext());
-  ProgramStateRef state = Pred->getState();
-  state = state->bindLoc(svalBuilder.getCXXThis(DD->getParent(), SFC),
-                         loc::MemRegionVal(Dest));
-  Bldr.generateNode(PP, Pred, state);
+  ExplodedNodeSet DstInvalidated;
+  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+       I != E; ++I)
+    defaultEvalCall(DstInvalidated, *I, Call);
+
+  ExplodedNodeSet DstPostCall;
+  getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
+                                             Call, *this);
 }
 
 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
index bf55ceb5fd49a433ad77f119d7c984c03c4bc542..cce55ea023b7000b03fdbb586e1d18da99a46826 100644 (file)
@@ -292,7 +292,8 @@ bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
     // enterStackFrame as well.
     return false;
   case CE_CXXConstructor:
-    // Do not inline constructors until we can model destructors.
+  case CE_CXXDestructor:
+    // Do not inline constructors until we can really model destructors.
     // This is unfortunate, but basically necessary for smart pointers and such.
     return false;
   case CE_CXXAllocator:
@@ -430,7 +431,7 @@ void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
     return;
 
   // If we can't inline it, handle the return value and invalidate the regions.
-  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+  NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
 
   // Invalidate any regions touched by the call.
   unsigned Count = currentBuilderContext->getCurrentBlockCount();
@@ -439,16 +440,17 @@ void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
   state = Call.invalidateRegions(Count, state);
 
   // Conjure a symbol value to use as the result.
-  assert(Call.getOriginExpr() && "Must have an expression to bind the result");
-  QualType ResultTy = Call.getResultType();
-  SValBuilder &SVB = getSValBuilder();
-  const LocationContext *LCtx = Pred->getLocationContext();
-  SVal RetVal = SVB.getConjuredSymbolVal(0, Call.getOriginExpr(), LCtx,
-                                         ResultTy, Count);
+  if (E) {
+    QualType ResultTy = Call.getResultType();
+    SValBuilder &SVB = getSValBuilder();
+    const LocationContext *LCtx = Pred->getLocationContext();
+    SVal RetVal = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+
+    state = state->BindExpr(E, LCtx, RetVal);
+  }
 
   // And make the result node.
-  state = state->BindExpr(Call.getOriginExpr(), LCtx, RetVal);
-  Bldr.generateNode(Call.getOriginExpr(), Pred, state);
+  Bldr.generateNode(Call.getProgramPoint(), state, Pred);
 }
 
 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,