]> granicus.if.org Git - clang/commitdiff
Added boilerplate transfer function support for CallExprs.
authorTed Kremenek <kremenek@apple.com>
Tue, 19 Feb 2008 01:44:53 +0000 (01:44 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 19 Feb 2008 01:44:53 +0000 (01:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47298 91177308-0d34-0410-b5e6-96231b3b80d8

Analysis/GRExprEngine.cpp
Analysis/RValues.cpp
Analysis/ValueState.cpp
include/clang/Analysis/PathSensitive/GRExprEngine.h
include/clang/Analysis/PathSensitive/RValues.h

index 09ffcd47a5d8322b40e89121f602d6048c69c3c9..4ea78194974599bf01729c38907b1697161166ac 100644 (file)
@@ -259,7 +259,7 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
     do {      
       nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1));
       
-      NonLValue Res = EvalBinaryOp(ValMgr, BinaryOperator::EQ, CondV, CaseVal);
+      NonLValue Res = EvalBinaryOp(BinaryOperator::EQ, CondV, CaseVal);
       
       // Now "assume" that the case matches.
       bool isFeasible = false;
@@ -407,12 +407,51 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){
   Nodify(Dst, D, Pred, SetValue(St, D, GetValue(St, D)));
 }
 
+void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
+                             CallExpr::arg_iterator I, CallExpr::arg_iterator E,
+                             NodeSet& Dst) {
+  
+  if (I != E) {
+    NodeSet DstTmp;  
+    Visit(*I, Pred, DstTmp);
+    ++I;
+    
+    for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI)
+      VisitCall(CE, *DI, I, E, Dst);
+    
+    return;
+  }
+
+  // If we reach here we have processed all of the arguments.  Evaluate
+  // the callee expression.
+  NodeSet DstTmp;
+  Visit(CE->getCallee(), Pred, DstTmp);
+  
+  // Finally, evaluate the function call.
+  for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI) {
+    StateTy St = (*DI)->getState();    
+    LValue L = GetLValue(St, CE->getCallee());
+
+    // Check for uninitialized control-flow.
+    if (isa<UninitializedVal>(L)) {
+      NodeTy* N = Builder->generateNode(CE, St, *DI);
+      N->markAsSink();
+      UninitBranches.insert(N);
+      continue;
+    }
+    
+    // Note: EvalCall must handle the case where the callee is "UnknownVal."
+    Nodify(Dst, CE, *DI, EvalCall(CE, (*DI)->getState()));
+  }
+}
+
 void GRExprEngine::VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst) {
   
   QualType T = CastE->getType();
 
   // Check for redundant casts.
-  if (E->getType() == T) {
+  if (E->getType() == T || 
+      (T->isPointerType() && E->getType()->isFunctionType())) {
     Dst.Add(Pred);
     return;
   }
@@ -515,7 +554,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U,
       BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
                                                      : BinaryOperator::Sub;
       
-      RValue Result = EvalBinaryOp(ValMgr, Op, R1, GetRValueConstant(1U, U));
+      RValue Result = EvalBinaryOp(Op, R1, GetRValueConstant(1U, U));
       
       if (U->isPostfix())
         Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result));
@@ -553,14 +592,14 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U,
           const LValue& L1 = cast<LValue>(V1);
           lval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth());
           Nodify(Dst, U, N1,
-                 SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ,
+                 SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ,
                                               L1, V2)));
         }
         else {
           const NonLValue& R1 = cast<NonLValue>(V1);
           nonlval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth());
           Nodify(Dst, U, N1,
-                 SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ,
+                 SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ,
                                               R1, V2)));
         }
         
@@ -705,7 +744,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
           continue;
         }
         
-        Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(ValMgr, Op, V1, V2)));
+        Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(Op, V1, V2)));
         continue;
       
       }
@@ -742,14 +781,14 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
           
           if (B->getType()->isPointerType()) { // Perform pointer arithmetic.
             const NonLValue& R2 = cast<NonLValue>(V2);
-            Result = EvalBinaryOp(ValMgr, Op, L1, R2);
+            Result = EvalBinaryOp(Op, L1, R2);
           }
           else if (isa<LValue>(V2)) {
             const LValue& L2 = cast<LValue>(V2);
             
             if (B->getRHS()->getType()->isPointerType()) {
               // LValue comparison.
-              Result = EvalBinaryOp(ValMgr, Op, L1, L2);
+              Result = EvalBinaryOp(Op, L1, L2);
             }
             else {
               QualType T1 = B->getLHS()->getType();
@@ -757,7 +796,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
               
               // An operation between two variables of a non-lvalue type.
               Result =
-                EvalBinaryOp(ValMgr, Op,
+                EvalBinaryOp(Op,
                             cast<NonLValue>(GetValue(N1->getState(), L1, &T1)),
                             cast<NonLValue>(GetValue(N2->getState(), L2, &T2)));
             }
@@ -767,7 +806,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
             const NonLValue& R1 = cast<NonLValue>(GetValue(N1->getState(),
                                                            L1, &T));
             const NonLValue& R2 = cast<NonLValue>(V2);
-            Result = EvalBinaryOp(ValMgr, Op, R1, R2);
+            Result = EvalBinaryOp(Op, R1, R2);
           }
           
           Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
@@ -821,6 +860,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
       VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
       break;
     }
+      
+    case Stmt::CallExprClass: {
+      CallExpr* C = cast<CallExpr>(S);
+      VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+      break;      
+    }
 
     case Stmt::CastExprClass: {
       CastExpr* C = cast<CastExpr>(S);
index c8a4dfa8d9a04c55ae0e0ccf87c24d7f2a2bebee..0fc03dda588360acb6f37f7eef24aa5e95bcbe3a 100644 (file)
@@ -342,7 +342,12 @@ void LValue::print(std::ostream& Out) const {
 
     case lval::DeclValKind:
       Out << '&' 
-      << cast<lval::DeclVal>(this)->getDecl()->getIdentifier()->getName();
+          << cast<lval::DeclVal>(this)->getDecl()->getIdentifier()->getName();
+      break;
+      
+    case lval::FuncValKind:
+      Out << "function " 
+          << cast<lval::FuncVal>(this)->getDecl()->getIdentifier()->getName();
       break;
       
     default:
index 32be0c6d7135c94baf62a3ad41794294519975cf..0f29def4a064b4874642bc558c46389491e3510e 100644 (file)
@@ -220,6 +220,8 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
           // a better way, since APInts are fairly lightweight.
           return nonlval::ConcreteInt(ValMgr.getValue(ED->getInitVal()));
         }
+        else if (FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
+          return lval::FuncVal(FD);
         
         assert (false &&
                 "ValueDecl support for this ValueDecl not implemented.");
@@ -248,7 +250,10 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
         
       case Stmt::ImplicitCastExprClass: {
         ImplicitCastExpr* C = cast<ImplicitCastExpr>(E);
-        if (C->getType() == C->getSubExpr()->getType()) {
+        QualType CT = C->getType();
+        QualType ST = C->getSubExpr()->getType();
+        
+        if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
           E = C->getSubExpr();
           continue;
         }
@@ -257,7 +262,10 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
         
       case Stmt::CastExprClass: {
         CastExpr* C = cast<CastExpr>(E);
-        if (C->getType() == C->getSubExpr()->getType()) {
+        QualType CT = C->getType();
+        QualType ST = C->getSubExpr()->getType();
+        
+        if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
           E = C->getSubExpr();
           continue;
         }
@@ -297,8 +305,14 @@ LValue ValueStateManager::GetLValue(ValueState St, Expr* E) {
   while (ParenExpr* P = dyn_cast<ParenExpr>(E))
     E = P->getSubExpr();
   
-  if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
-    return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
+  if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
+    ValueDecl* VD = DR->getDecl();
+    
+    if (FunctionDecl* FD = dyn_cast<FunctionDecl>(VD))
+      return lval::FuncVal(FD);
+    else
+      return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
+  }
   
   if (UnaryOperator* U = dyn_cast<UnaryOperator>(E))
     if (U->getOpcode() == UnaryOperator::Deref)
index 1bdbb2afda96003dae29727589b385128900fcc7..4f9456d4e367a275611bd332027ba3c9fb398187 100644 (file)
@@ -296,6 +296,11 @@ public:
   
   void VisitAssignmentLHS(Expr* E, NodeTy* Pred, NodeSet& Dst);
   
+  /// VisitCall - Transfer function for function calls.
+  void VisitCall(CallExpr* CE, NodeTy* Pred,
+                 CallExpr::arg_iterator I, CallExpr::arg_iterator E,
+                 NodeSet& Dst);
+  
   /// VisitCast - Transfer function logic for all casts (implicit and explicit).
   void VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst);  
   
@@ -342,7 +347,7 @@ public:
     return TF->EvalComplement(ValMgr, X);
   }
   
-  inline NonLValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
+  inline NonLValue EvalBinaryOp(BinaryOperator::Opcode Op,
                                 NonLValue LHS, NonLValue RHS) {
     
     if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
@@ -354,7 +359,7 @@ public:
     return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
   }    
   
-  inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
+  inline RValue EvalBinaryOp(BinaryOperator::Opcode Op,
                              LValue LHS, LValue RHS) {
     
     if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
@@ -366,7 +371,7 @@ public:
     return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
   }
   
-  inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
+  inline RValue EvalBinaryOp(BinaryOperator::Opcode Op,
                              LValue LHS, NonLValue RHS) {
     
     if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
@@ -378,7 +383,7 @@ public:
     return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
   }
   
-  inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
+  inline RValue EvalBinaryOp(BinaryOperator::Opcode Op,
                              RValue LHS, RValue RHS) {
     
     if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
@@ -389,5 +394,9 @@ public:
     
     return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
   }
+  
+  StateTy EvalCall(CallExpr* CE, StateTy St) {
+    return St;     
+  }
 };
 } // end clang namespace
\ No newline at end of file
index 202c2306bf2e6cbb8942e875736e6309ed88a64b..d4a2766ce66dcafda84cd4e5aa72e1ea5cbe98f2 100644 (file)
@@ -147,9 +147,9 @@ public:
 
 namespace nonlval {
   
-  enum Kind { SymbolValKind,
+  enum Kind { ConcreteIntKind,
+              SymbolValKind,
               SymIntConstraintValKind,
-              ConcreteIntKind,
               NumKind };
 
   class SymbolVal : public NonLValue {
@@ -218,6 +218,7 @@ namespace lval {
   enum Kind { SymbolValKind,
               GotoLabelKind,
               DeclValKind,
+              FuncValKind,
               ConcreteIntKind,
               NumKind };
   
@@ -282,6 +283,32 @@ namespace lval {
       return V->getSubKind() == DeclValKind;
     }
   };
+  
+  class FuncVal : public LValue {
+  public:
+    FuncVal(const FunctionDecl* fd) : LValue(FuncValKind, fd) {}
+    
+    FunctionDecl* getDecl() const {
+      return static_cast<FunctionDecl*>(Data);
+    }
+    
+    inline bool operator==(const FuncVal& R) const {
+      return getDecl() == R.getDecl();
+    }
+    
+    inline bool operator!=(const FuncVal& R) const {
+      return getDecl() != R.getDecl();
+    }
+    
+    // Implement isa<T> support.
+    static inline bool classof(const RValue* V) {
+      return isa<LValue>(V) && V->getSubKind() == FuncValKind;
+    }
+    
+    static inline bool classof(const LValue* V) {
+      return V->getSubKind() == FuncValKind;
+    }
+  };
 
   class ConcreteInt : public LValue {
   public: