This patch performs two additional refactorings.  The first refactors
lockset removal into a separate function, to be consistent with
lockset addition.  The second refactors the handling of invalid lock
expressions into a separate routine, in preparation for better
handling of such messages in more complex cases, such as attributes on
destructors.  There is no major change in functionality.

  http://codereview.appspot.com/5293049/

  -DeLesley

-- 
DeLesley Hutchins | Software Engineer | [email protected] | 505-206-0315
From fc0555aa78b8df4b2977726a88b4e21f3ab1fe0a Mon Sep 17 00:00:00 2001
From: DeLesley Hutchins <[email protected]>
Date: Wed, 19 Oct 2011 15:41:04 -0700
Subject: [PATCH] Thread safety analysis refactoring: invalid lock expressions.

---
 include/clang/Basic/DiagnosticSemaKinds.td   |    2 +-
 lib/Analysis/ThreadSafety.cpp                |   95 +++++++++++++++++---------
 test/SemaCXX/warn-thread-safety-analysis.cpp |   17 ++---
 3 files changed, 72 insertions(+), 42 deletions(-)

diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9590deb..bfee1c6 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1527,7 +1527,7 @@ def warn_fun_excludes_mutex : Warning<
   "cannot call function '%0' while mutex '%1' is locked">,
   InGroup<ThreadSafety>, DefaultIgnore;
 def warn_cannot_resolve_lock : Warning<
-  "cannot resolve lock expression to a specific lockable object">,
+  "cannot resolve lock expression">,
   InGroup<ThreadSafety>, DefaultIgnore;
 
 
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 7cc71f7..b0cde9b 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -161,6 +161,11 @@ class MutexID {
   /// Recursive function that bottoms out when the final DeclRefExpr is reached.
   void buildMutexID(Expr *Exp, Expr *Parent, int NumArgs,
                     const NamedDecl **FunArgDecls, Expr **FunArgs) {
+    if (!Exp) {
+      DeclSeq.clear();
+      return;
+    }
+
     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
       if (FunArgDecls) {
         // Substitute call arguments for references to function parameters
@@ -202,11 +207,13 @@ class MutexID {
     Expr **FunArgs = 0;
     SmallVector<const NamedDecl*, 8> FunArgDecls;
 
+    // If we are processing a raw attribute expression...
     if (DeclExp == 0) {
       buildMutexID(MutexExp, 0, 0, 0, 0);
       return;
     }
 
+    // Get Parent and FunArgs from DeclExp
     if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
       Parent = ME->getBase();
     } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
@@ -250,6 +257,18 @@ public:
     return !DeclSeq.empty();
   }
 
+  /// Issue a warning about an invalid lock expression
+  static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
+                              Expr *DeclExp, const NamedDecl* D) {
+    SourceLocation Loc;
+    if (DeclExp)
+      Loc = DeclExp->getExprLoc();
+
+    // FIXME: add a note about the attribute location in MutexExp or D
+    if (Loc.isValid())
+      Handler.handleInvalidLockExp(Loc);
+  }
+
   bool operator==(const MutexID &other) const {
     return DeclSeq == other.DeclSeq;
   }
@@ -329,6 +348,8 @@ typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
 /// output error messages related to missing locks.
 /// FIXME: In future, we may be able to not inherit from a visitor.
 class BuildLockset : public StmtVisitor<BuildLockset> {
+  friend class ThreadSafetyAnalyzer;
+
   ThreadSafetyHandler &Handler;
   Lockset LSet;
   Lockset::Factory &LocksetFactory;
@@ -339,6 +360,8 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
 
   template <class AttrType>
   void addLocksToSet(LockKind LK, AttrType *Attr, Expr *Exp, NamedDecl *D);
+  void removeLocksFromSet(UnlockFunctionAttr *Attr,
+                          Expr *Exp, NamedDecl* FunDecl);
 
   const ValueDecl *getValueDecl(Expr *Exp);
   void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK,
@@ -401,9 +424,10 @@ void BuildLockset::addLock(SourceLocation LockLoc, MutexID &Mutex,
   LockData NewLock(LockLoc, LK);
 
   // FIXME: Don't always warn when we have support for reentrant locks.
-  if (locksetContains(Mutex))
+  if (locksetContains(Mutex) && LockLoc.isValid())
     Handler.handleDoubleLock(Mutex.getName(), LockLoc);
-  LSet = LocksetFactory.add(LSet, Mutex, NewLock);
+  else
+    LSet = LocksetFactory.add(LSet, Mutex, NewLock);
 }
 
 /// \brief Remove a lock from the lockset, warning if the lock is not there.
@@ -411,10 +435,10 @@ void BuildLockset::addLock(SourceLocation LockLoc, MutexID &Mutex,
 /// \param UnlockLoc The source location of the unlock (only used in error msg)
 void BuildLockset::removeLock(SourceLocation UnlockLoc, MutexID &Mutex) {
   Lockset NewLSet = LocksetFactory.remove(LSet, Mutex);
-  if(NewLSet == LSet)
+  if(NewLSet == LSet && UnlockLoc.isValid())
     Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
-
-  LSet = NewLSet;
+  else
+    LSet = NewLSet;
 }
 
 /// \brief This function, parameterized by an attribute type, is used to add a
@@ -428,10 +452,9 @@ void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr,
 
   if (Attr->args_size() == 0) {
     // The mutex held is the "this" object.
-
     MutexID Mutex(0, Exp, FunDecl);
     if (!Mutex.isValid())
-      Handler.handleInvalidLockExp(Exp->getExprLoc());
+      MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl);
     else
       addLock(ExpLocation, Mutex, LK);
     return;
@@ -440,12 +463,39 @@ void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr,
   for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
     MutexID Mutex(*I, Exp, FunDecl);
     if (!Mutex.isValid())
-      Handler.handleInvalidLockExp(Exp->getExprLoc());
+      MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl);
     else
       addLock(ExpLocation, Mutex, LK);
   }
 }
 
+/// \brief this function adds a set of locks specified as attribute arguments
+/// to the lockset.
+void BuildLockset::removeLocksFromSet(UnlockFunctionAttr *Attr,
+                                      Expr *Exp, NamedDecl* FunDecl) {
+  SourceLocation ExpLocation;
+  if (Exp) ExpLocation = Exp->getExprLoc();
+
+  if (Attr->args_size() == 0) {
+    // The mutex held is the "this" object.
+    MutexID Mu(0, Exp, FunDecl);
+    if (!Mu.isValid())
+      MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl);
+    else
+      removeLock(ExpLocation, Mu);
+    return;
+  }
+
+  for (UnlockFunctionAttr::args_iterator I = Attr->args_begin(),
+       E = Attr->args_end(); I != E; ++I) {
+    MutexID Mutex(*I, Exp, FunDecl);
+    if (!Mutex.isValid())
+      MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl);
+    else
+      removeLock(ExpLocation, Mutex);
+  }
+}
+
 /// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
 const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp))
@@ -466,7 +516,7 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
 
   MutexID Mutex(MutexExp, Exp, D);
   if (!Mutex.isValid())
-    Handler.handleInvalidLockExp(MutexExp->getExprLoc());
+    MutexID::warnInvalidLock(Handler, MutexExp, Exp, D);
   else if (!locksetContainsAtLeast(Mutex, LK))
     Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc());
 }
@@ -529,8 +579,6 @@ void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) {
 /// FIXME: Do not flag an error for member variables accessed in constructors/
 /// destructors
 void BuildLockset::handleCall(Expr *Exp, NamedDecl *D) {
-  SourceLocation ExpLocation = Exp->getExprLoc();
-
   AttrVec &ArgAttrs = D->getAttrs();
   for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
     Attr *Attr = ArgAttrs[i];
@@ -555,24 +603,7 @@ void BuildLockset::handleCall(Expr *Exp, NamedDecl *D) {
       // mutexes from the lockset, and flag a warning if they are not there.
       case attr::UnlockFunction: {
         UnlockFunctionAttr *UFAttr = cast<UnlockFunctionAttr>(Attr);
-
-        if (UFAttr->args_size() == 0) { // The lock held is the "this" object.
-          MutexID Mu(0, Exp, D);
-          if (!Mu.isValid())
-            Handler.handleInvalidLockExp(Exp->getExprLoc());
-          else
-            removeLock(ExpLocation, Mu);
-          break;
-        }
-
-        for (UnlockFunctionAttr::args_iterator I = UFAttr->args_begin(),
-             E = UFAttr->args_end(); I != E; ++I) {
-          MutexID Mutex(*I, Exp, D);
-          if (!Mutex.isValid())
-            Handler.handleInvalidLockExp(Exp->getExprLoc());
-          else
-            removeLock(ExpLocation, Mutex);
-        }
+        removeLocksFromSet(UFAttr, Exp, D);
         break;
       }
 
@@ -601,10 +632,10 @@ void BuildLockset::handleCall(Expr *Exp, NamedDecl *D) {
             E = LEAttr->args_end(); I != E; ++I) {
           MutexID Mutex(*I, Exp, D);
           if (!Mutex.isValid())
-            Handler.handleInvalidLockExp((*I)->getExprLoc());
+            MutexID::warnInvalidLock(Handler, *I, Exp, D);
           else if (locksetContains(Mutex))
             Handler.handleFunExcludesLock(D->getName(), Mutex.getName(),
-                                          ExpLocation);
+                                          Exp->getExprLoc());
         }
         break;
       }
@@ -737,7 +768,7 @@ Lockset ThreadSafetyAnalyzer::addLock(Lockset &LSet, Expr *MutexExp,
                                       LockKind LK, SourceLocation Loc) {
   MutexID Mutex(MutexExp, 0, D);
   if (!Mutex.isValid()) {
-    Handler.handleInvalidLockExp(MutexExp->getExprLoc());
+    MutexID::warnInvalidLock(Handler, MutexExp, 0, D);
     return LSet;
   }
   LockData NewLock(Loc, LK);
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index efa19fd..c30f002 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -749,23 +749,22 @@ Mutex UPmu;
 // FIXME: add support for lock expressions involving arrays.
 Mutex mua[5];
 
-int x __attribute__((guarded_by(UPmu = sls_mu))); // \
-  // expected-warning{{cannot resolve lock expression to a specific lockable object}}
-int y __attribute__((guarded_by(mua[0]))); // \
-  // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+int x __attribute__((guarded_by(UPmu = sls_mu)));
+int y __attribute__((guarded_by(mua[0])));
 
 
 void testUnparse() {
-  // no errors, since the lock expressions are not resolved
-  x = 5;
-  y = 5;
+  x = 5; // \
+    // expected-warning{{cannot resolve lock expression}}
+  y = 5; // \
+    // expected-warning{{cannot resolve lock expression}}
 }
 
 void testUnparse2() {
   mua[0].Lock(); // \
-    // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+    // expected-warning{{cannot resolve lock expression}}
   (&(mua[0]) + 4)->Lock(); // \
-    // expected-warning{{cannot resolve lock expression to a specific lockable object}}
+    // expected-warning{{cannot resolve lock expression}}
 }
 
 
-- 
1.7.3.1

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to