]> granicus.if.org Git - clang/commitdiff
Switch over to BodyFarm implementation of OSAtomicCompareAndSwap and
authorTed Kremenek <kremenek@apple.com>
Thu, 11 Oct 2012 20:58:18 +0000 (20:58 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 11 Oct 2012 20:58:18 +0000 (20:58 +0000)
objc_atomicCompareAndSwap.

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

lib/Analysis/BodyFarm.cpp
lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp

index 3dcbfb927ef567f7732d0736b3eaab631e7fa1d2..9a04a826751fa10b3f1c971d22a05ae406dc4204 100644 (file)
@@ -16,6 +16,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/ExprObjC.h"
 #include "BodyFarm.h"
 
 using namespace clang;
@@ -49,6 +50,13 @@ public:
   /// Create a new BinaryOperator representing a simple assignment.
   BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
   
+  /// Create a new BinaryOperator representing a comparison.
+  BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
+                                 BinaryOperator::Opcode Op);
+  
+  /// Create a new compound stmt using the provided statements.
+  CompoundStmt *makeCompound(ArrayRef<Stmt*>);
+  
   /// Create a new DeclRefExpr for the referenced variable.
   DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
   
@@ -58,9 +66,18 @@ public:
   /// Create an implicit cast for an integer conversion.
   ImplicitCastExpr *makeIntegralCast(const Expr *Arg, QualType Ty);
   
+  /// Create an implicit cast to a builtin boolean type.
+  ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
+  
   // Create an implicit cast for lvalue-to-rvaluate conversions.
   ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
   
+  /// Create an Objective-C bool literal.
+  ObjCBoolLiteralExpr *makeObjCBool(bool Val);
+  
+  /// Create a Return statement.
+  ReturnStmt *makeReturn(const Expr *RetVal);
+  
 private:
   ASTContext &C;
 };
@@ -73,6 +90,24 @@ BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
                                OK_Ordinary, SourceLocation(), false);
 }
 
+BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
+                                         BinaryOperator::Opcode Op) {
+  assert(BinaryOperator::isLogicalOp(Op) ||
+         BinaryOperator::isComparisonOp(Op));
+  return new (C) BinaryOperator(const_cast<Expr*>(LHS),
+                                const_cast<Expr*>(RHS),
+                                Op,
+                                C.getLogicalOperationType(),
+                                VK_RValue,
+                                OK_Ordinary, SourceLocation(), false);
+}
+
+CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
+  return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
+                              Stmts.size(),
+                              SourceLocation(), SourceLocation());
+}
+
 DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
   DeclRefExpr *DR =
     DeclRefExpr::Create(/* Ctx = */ C,
@@ -101,6 +136,20 @@ ImplicitCastExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
                                   const_cast<Expr*>(Arg), 0, VK_RValue);
 }
 
+ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
+  return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
+                                  const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
+  QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
+  return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
+}
+
+ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
+  return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
+}
+
 //===----------------------------------------------------------------------===//
 // Creation functions for faux ASTs.
 //===----------------------------------------------------------------------===//
@@ -163,9 +212,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
   // (3) Create the compound statement.
   Stmt *Stmts[2];
   Stmts[0] = B;
-  Stmts[1] = CE;  
-  CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(),
-                                          SourceLocation());
+  Stmts[1] = CE;
+  CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
   
   // (4) Create the 'if' condition.
   ImplicitCastExpr *LValToRval =
@@ -213,6 +261,71 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
   return CE;
 }
 
+static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
+{
+  // There are exactly 3 arguments.
+  if (D->param_size() != 3)
+    return 0;
+  
+  // Body for:
+  //   if (oldValue == *theValue) {
+  //    *theValue = newValue;
+  //    return YES;
+  //   }
+  //   else return NO;
+  
+  const ParmVarDecl *OldValue = D->getParamDecl(0);
+  QualType OldValueTy = OldValue->getType();
+
+  const ParmVarDecl *NewValue = D->getParamDecl(1);
+  QualType NewValueTy = NewValue->getType();
+  
+  assert(OldValueTy == NewValueTy);
+  
+  const ParmVarDecl *TheValue = D->getParamDecl(2);
+  QualType TheValueTy = TheValue->getType();
+  const PointerType *PT = TheValueTy->getAs<PointerType>();
+  if (!PT)
+    return 0;
+  QualType PointeeTy = PT->getPointeeType();
+  
+  ASTMaker M(C);
+  // Construct the comparison.
+  Expr *Comparison =
+    M.makeComparison(
+      M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
+      M.makeLvalueToRvalue(
+        M.makeDereference(
+          M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+          PointeeTy),
+        PointeeTy),
+      BO_EQ);
+
+  // Construct the body of the IfStmt.
+  Stmt *Stmts[2];
+  Stmts[0] =
+    M.makeAssignment(
+      M.makeDereference(
+        M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+        PointeeTy),
+      M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
+      NewValueTy);
+  Stmts[1] =
+    M.makeReturn(M.makeIntegralCastToBoolean(M.makeObjCBool(true)));
+  CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+  
+  // Construct the else clause.
+  Stmt *Else =
+    M.makeReturn(M.makeIntegralCastToBoolean(M.makeObjCBool(false)));
+  
+  /// Construct the If.
+  Stmt *If =
+    new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
+                   SourceLocation(), Else);
+  
+  return If;  
+}
+
 Stmt *BodyFarm::getBody(const FunctionDecl *D) {
   D = D->getCanonicalDecl();
   
@@ -228,17 +341,21 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
   StringRef Name = D->getName();
   if (Name.empty())
     return 0;
-  
-  FunctionFarmer FF =
-    llvm::StringSwitch<FunctionFarmer>(Name)
-      .Case("dispatch_sync", create_dispatch_sync)
-      .Case("dispatch_once", create_dispatch_once)
-      .Default(NULL);
-  
-  if (FF) {
-    Val = FF(C, D);
+
+  FunctionFarmer FF;
+
+  if (Name.startswith("OSAtomicCompareAndSwap") ||
+      Name.startswith("objc_atomicCompareAndSwap")) {
+    FF = create_OSAtomicCompareAndSwap;
+  }
+  else {
+    FF = llvm::StringSwitch<FunctionFarmer>(Name)
+          .Case("dispatch_sync", create_dispatch_sync)
+          .Case("dispatch_once", create_dispatch_once)
+        .Default(NULL);
   }
   
+  if (FF) { Val = FF(C, D); }
   return Val.getValue();
 }
 
index 81e4f0dcf2aaa03bc2c9fef09715d1b1474268ce..6cdd9a5925c4512f01e480b147e3f0d0dd14a617 100644 (file)
@@ -212,5 +212,5 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
 }
 
 void ento::registerOSAtomicChecker(CheckerManager &mgr) {
-  mgr.registerChecker<OSAtomicChecker>();
+  //  mgr.registerChecker<OSAtomicChecker>();
 }