Thread safety analysis:  implement lock_returned attribute.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159152 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 075324d..2668de1 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -84,12 +84,33 @@
 class MutexID {
   SmallVector<NamedDecl*, 2> DeclSeq;
 
+  /// \brief Encapsulates the lexical context of a function call.  The lexical
+  /// context includes the arguments to the call, including the implicit object
+  /// argument.  When an attribute containing a mutex expression is attached to
+  /// a method, the expression may refer to formal parameters of the method.
+  /// Actual arguments must be substituted for formal parameters to derive
+  /// the appropriate mutex expression in the lexical context where the function
+  /// is called.  PrevCtx holds the context in which the arguments themselves
+  /// should be evaluated; multiple calling contexts can be chained together
+  /// by the lock_returned attribute.
+  struct CallingContext {
+    const NamedDecl* AttrDecl;  // The decl to which the attribute is attached.
+    Expr*            SelfArg;   // Implicit object argument -- e.g. 'this'
+    unsigned         NumArgs;   // Number of funArgs
+    Expr**           FunArgs;   // Function arguments
+    CallingContext*  PrevCtx;   // The previous context; or 0 if none.
+
+    CallingContext(const NamedDecl* D = 0, Expr* S = 0,
+                   unsigned N = 0, Expr** A = 0, CallingContext* P = 0)
+      : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), PrevCtx(P)
+    { }
+  };
+
   /// Build a Decl sequence representing the lock from the given expression.
   /// Recursive function that terminates on DeclRefExpr.
   /// Note: this function merely creates a MutexID; it does not check to
   /// ensure that the original expression is a valid mutex expression.
-  void buildMutexID(Expr *Exp, const NamedDecl *D, Expr *Parent,
-                    unsigned NumArgs, Expr **FunArgs) {
+  void buildMutexID(Expr *Exp, CallingContext* CallCtx) {
     if (!Exp) {
       DeclSeq.clear();
       return;
@@ -103,10 +124,11 @@
           cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
         unsigned i = PV->getFunctionScopeIndex();
 
-        if (FunArgs && FD == D->getCanonicalDecl()) {
+        if (CallCtx && CallCtx->FunArgs &&
+            FD == CallCtx->AttrDecl->getCanonicalDecl()) {
           // Substitute call arguments for references to function parameters
-          assert(i < NumArgs);
-          buildMutexID(FunArgs[i], D, 0, 0, 0);
+          assert(i < CallCtx->NumArgs);
+          buildMutexID(CallCtx->FunArgs[i], CallCtx->PrevCtx);
           return;
         }
         // Map the param back to the param of the original function declaration.
@@ -115,54 +137,75 @@
       }
       // Not a function parameter -- just store the reference.
       DeclSeq.push_back(ND);
-    } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
-      NamedDecl *ND = ME->getMemberDecl();
-      DeclSeq.push_back(ND);
-      buildMutexID(ME->getBase(), D, Parent, NumArgs, FunArgs);
     } else if (isa<CXXThisExpr>(Exp)) {
-      if (Parent)
-        buildMutexID(Parent, D, 0, 0, 0);
+      // Substitute parent for 'this'
+      if (CallCtx && CallCtx->SelfArg)
+        buildMutexID(CallCtx->SelfArg, CallCtx->PrevCtx);
       else {
         DeclSeq.push_back(0);  // Use 0 to represent 'this'.
         return;  // mutexID is still valid in this case
       }
+    } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+      NamedDecl *ND = ME->getMemberDecl();
+      DeclSeq.push_back(ND);
+      buildMutexID(ME->getBase(), CallCtx);
     } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+      // When calling a function with a lock_returned attribute, replace
+      // the function call with the expression in lock_returned.
+      if (LockReturnedAttr* At =
+            CMCE->getMethodDecl()->getAttr<LockReturnedAttr>()) {
+        CallingContext LRCallCtx(CMCE->getMethodDecl());
+        LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
+        LRCallCtx.NumArgs = CMCE->getNumArgs();
+        LRCallCtx.FunArgs = CMCE->getArgs();
+        LRCallCtx.PrevCtx = CallCtx;
+        buildMutexID(At->getArg(), &LRCallCtx);
+        return;
+      }
       DeclSeq.push_back(CMCE->getMethodDecl()->getCanonicalDecl());
-      buildMutexID(CMCE->getImplicitObjectArgument(),
-                   D, Parent, NumArgs, FunArgs);
+      buildMutexID(CMCE->getImplicitObjectArgument(), CallCtx);
       unsigned NumCallArgs = CMCE->getNumArgs();
       Expr** CallArgs = CMCE->getArgs();
       for (unsigned i = 0; i < NumCallArgs; ++i) {
-        buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs);
+        buildMutexID(CallArgs[i], CallCtx);
       }
     } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
-      buildMutexID(CE->getCallee(), D, Parent, NumArgs, FunArgs);
+      if (LockReturnedAttr* At =
+            CE->getDirectCallee()->getAttr<LockReturnedAttr>()) {
+        CallingContext LRCallCtx(CE->getDirectCallee());
+        LRCallCtx.NumArgs = CE->getNumArgs();
+        LRCallCtx.FunArgs = CE->getArgs();
+        LRCallCtx.PrevCtx = CallCtx;
+        buildMutexID(At->getArg(), &LRCallCtx);
+        return;
+      }
+      buildMutexID(CE->getCallee(), CallCtx);
       unsigned NumCallArgs = CE->getNumArgs();
       Expr** CallArgs = CE->getArgs();
       for (unsigned i = 0; i < NumCallArgs; ++i) {
-        buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs);
+        buildMutexID(CallArgs[i], CallCtx);
       }
     } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
-      buildMutexID(BOE->getLHS(), D, Parent, NumArgs, FunArgs);
-      buildMutexID(BOE->getRHS(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(BOE->getLHS(), CallCtx);
+      buildMutexID(BOE->getRHS(), CallCtx);
     } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
-      buildMutexID(UOE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(UOE->getSubExpr(), CallCtx);
     } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) {
-      buildMutexID(ASE->getBase(), D, Parent, NumArgs, FunArgs);
-      buildMutexID(ASE->getIdx(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(ASE->getBase(), CallCtx);
+      buildMutexID(ASE->getIdx(), CallCtx);
     } else if (AbstractConditionalOperator *CE =
                  dyn_cast<AbstractConditionalOperator>(Exp)) {
-      buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs);
-      buildMutexID(CE->getTrueExpr(), D, Parent, NumArgs, FunArgs);
-      buildMutexID(CE->getFalseExpr(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(CE->getCond(), CallCtx);
+      buildMutexID(CE->getTrueExpr(), CallCtx);
+      buildMutexID(CE->getFalseExpr(), CallCtx);
     } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
-      buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs);
-      buildMutexID(CE->getLHS(), D, Parent, NumArgs, FunArgs);
-      buildMutexID(CE->getRHS(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(CE->getCond(), CallCtx);
+      buildMutexID(CE->getLHS(), CallCtx);
+      buildMutexID(CE->getRHS(), CallCtx);
     } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
-      buildMutexID(CE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(CE->getSubExpr(), CallCtx);
     } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
-      buildMutexID(PE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+      buildMutexID(PE->getSubExpr(), CallCtx);
     } else if (isa<CharacterLiteral>(Exp) ||
              isa<CXXNullPtrLiteralExpr>(Exp) ||
              isa<GNUNullExpr>(Exp) ||
@@ -184,43 +227,42 @@
   ///        occurs.
   /// \param D  The declaration to which the lock/unlock attribute is attached.
   void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
-    Expr *Parent = 0;
-    unsigned NumArgs = 0;
-    Expr **FunArgs = 0;
+    CallingContext CallCtx(D);
 
     // If we are processing a raw attribute expression, with no substitutions.
     if (DeclExp == 0) {
-      buildMutexID(MutexExp, D, 0, 0, 0);
+      buildMutexID(MutexExp, 0);
       return;
     }
 
-    // Examine DeclExp to find Parent and FunArgs, which are used to substitute
+    // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
     // for formal parameters when we call buildMutexID later.
     if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
-      Parent = ME->getBase();
+      CallCtx.SelfArg = ME->getBase();
     } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
-      Parent = CE->getImplicitObjectArgument();
-      NumArgs = CE->getNumArgs();
-      FunArgs = CE->getArgs();
+      CallCtx.SelfArg = CE->getImplicitObjectArgument();
+      CallCtx.NumArgs = CE->getNumArgs();
+      CallCtx.FunArgs = CE->getArgs();
     } else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
-      NumArgs = CE->getNumArgs();
-      FunArgs = CE->getArgs();
+      CallCtx.NumArgs = CE->getNumArgs();
+      CallCtx.FunArgs = CE->getArgs();
     } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
-      Parent = 0;  // FIXME -- get the parent from DeclStmt
-      NumArgs = CE->getNumArgs();
-      FunArgs = CE->getArgs();
+      CallCtx.SelfArg = 0;  // FIXME -- get the parent from DeclStmt
+      CallCtx.NumArgs = CE->getNumArgs();
+      CallCtx.FunArgs = CE->getArgs();
     } else if (D && isa<CXXDestructorDecl>(D)) {
       // There's no such thing as a "destructor call" in the AST.
-      Parent = DeclExp;
+      CallCtx.SelfArg = DeclExp;
     }
 
     // If the attribute has no arguments, then assume the argument is "this".
     if (MutexExp == 0) {
-      buildMutexID(Parent, D, 0, 0, 0);
+      buildMutexID(CallCtx.SelfArg, 0);
       return;
     }
 
-    buildMutexID(MutexExp, D, Parent, NumArgs, FunArgs);
+    // For most attributes.
+    buildMutexID(MutexExp, &CallCtx);
   }
 
 public: