diff options
| author | Aaron Ballman <aaron@aaronballman.com> | 2014-04-01 21:43:23 +0000 |
|---|---|---|
| committer | Aaron Ballman <aaron@aaronballman.com> | 2014-04-01 21:43:23 +0000 |
| commit | e044904301f39b33c6f460884afd36cff495d7c2 (patch) | |
| tree | 33290cc3f6565870f87c492e56ad2266afb2aeba /clang/lib/Analysis/ThreadSafety.cpp | |
| parent | 6b444c5c8edb6ec280cd6cdd5275ae27e31e4fc7 (diff) | |
| download | bcm5719-llvm-e044904301f39b33c6f460884afd36cff495d7c2.tar.gz bcm5719-llvm-e044904301f39b33c6f460884afd36cff495d7c2.zip | |
Updating the capability attribute diagnostics to be more capability-neutral. Instead of using terminology such as "lock", "unlock" and "locked", the new terminology is "acquire", "release" and "held". Additionally, the capability attribute's name argument is now reported as part of the diagnostic, instead of hard coding as "mutex."
llvm-svn: 205359
Diffstat (limited to 'clang/lib/Analysis/ThreadSafety.cpp')
| -rw-r--r-- | clang/lib/Analysis/ThreadSafety.cpp | 280 |
1 files changed, 176 insertions, 104 deletions
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 5f7ce2d5928..fd804eba992 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -564,15 +564,15 @@ public: /// Issue a warning about an invalid lock expression static void warnInvalidLock(ThreadSafetyHandler &Handler, - const Expr *MutexExp, - const Expr *DeclExp, const NamedDecl* D) { + const Expr *MutexExp, const Expr *DeclExp, + const NamedDecl *D, StringRef Kind) { 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); + Handler.handleInvalidLockExp(Kind, Loc); } bool operator==(const SExpr &other) const { @@ -1428,9 +1428,10 @@ class ThreadSafetyAnalyzer { public: ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {} - void addLock(FactSet &FSet, const SExpr &Mutex, const LockData &LDat); - void removeLock(FactSet &FSet, const SExpr &Mutex, - SourceLocation UnlockLoc, bool FullyRemove, LockKind Kind); + void addLock(FactSet &FSet, const SExpr &Mutex, const LockData &LDat, + StringRef DiagKind); + void removeLock(FactSet &FSet, const SExpr &Mutex, SourceLocation UnlockLoc, + bool FullyRemove, LockKind Kind, StringRef DiagKind); template <typename AttrType> void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp, @@ -1463,12 +1464,89 @@ public: void runAnalysis(AnalysisDeclContext &AC); }; +/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs. +static const ValueDecl *getValueDecl(const Expr *Exp) { + if (const auto *CE = dyn_cast<ImplicitCastExpr>(Exp)) + return getValueDecl(CE->getSubExpr()); + + if (const auto *DR = dyn_cast<DeclRefExpr>(Exp)) + return DR->getDecl(); + + if (const auto *ME = dyn_cast<MemberExpr>(Exp)) + return ME->getMemberDecl(); + + return nullptr; +} + +template <typename Ty> +class has_arg_iterator { + typedef char yes[1]; + typedef char no[2]; + + template <typename Inner> + static yes& test(Inner *I, decltype(I->args_begin()) * = nullptr); + + template <typename> + static no& test(...); + +public: + static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes); +}; + +static StringRef ClassifyDiagnostic(const CapabilityAttr *A) { + return A->getName(); +} + +static StringRef ClassifyDiagnostic(QualType VDT) { + // We need to look at the declaration of the type of the value to determine + // which it is. The type should either be a record or a typedef, or a pointer + // or reference thereof. + if (const auto *RT = VDT->getAs<RecordType>()) { + if (const auto *RD = RT->getDecl()) + if (const auto *CA = RD->getAttr<CapabilityAttr>()) + return ClassifyDiagnostic(CA); + } else if (const auto *TT = VDT->getAs<TypedefType>()) { + if (const auto *TD = TT->getDecl()) + if (const auto *CA = TD->getAttr<CapabilityAttr>()) + return ClassifyDiagnostic(CA); + } else if (VDT->isPointerType() || VDT->isReferenceType()) + return ClassifyDiagnostic(VDT->getPointeeType()); + + return "mutex"; +} + +static StringRef ClassifyDiagnostic(const ValueDecl *VD) { + assert(VD && "No ValueDecl passed"); + + // The ValueDecl is the declaration of a mutex or role (hopefully). + return ClassifyDiagnostic(VD->getType()); +} + +template <typename AttrTy> +static typename std::enable_if<!has_arg_iterator<AttrTy>::value, + StringRef>::type +ClassifyDiagnostic(const AttrTy *A) { + if (const ValueDecl *VD = getValueDecl(A->getArg())) + return ClassifyDiagnostic(VD); + return "mutex"; +} + +template <typename AttrTy> +static typename std::enable_if<has_arg_iterator<AttrTy>::value, + StringRef>::type +ClassifyDiagnostic(const AttrTy *A) { + for (auto I = A->args_begin(), E = A->args_end(); I != E; ++I) { + if (const ValueDecl *VD = getValueDecl(*I)) + return ClassifyDiagnostic(VD); + } + return "mutex"; +} /// \brief Add a new lock to the lockset, warning if the lock is already there. /// \param Mutex -- the Mutex expression for the lock /// \param LDat -- the LockData for the lock void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex, - const LockData &LDat) { + const LockData &LDat, StringRef DiagKind) { // FIXME: deal with acquired before/after annotations. // FIXME: Don't always warn when we have support for reentrant locks. if (Mutex.shouldIgnore()) @@ -1476,7 +1554,7 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex, if (FSet.findLock(FactMan, Mutex)) { if (!LDat.Asserted) - Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc); + Handler.handleDoubleLock(DiagKind, Mutex.toString(), LDat.AcquireLoc); } else { FSet.addLock(FactMan, Mutex, LDat); } @@ -1488,20 +1566,21 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex, /// \param UnlockLoc The source location of the unlock (only used in error msg) void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const SExpr &Mutex, SourceLocation UnlockLoc, - bool FullyRemove, LockKind ReceivedKind) { + bool FullyRemove, LockKind ReceivedKind, + StringRef DiagKind) { if (Mutex.shouldIgnore()) return; const LockData *LDat = FSet.findLock(FactMan, Mutex); if (!LDat) { - Handler.handleUnmatchedUnlock(Mutex.toString(), UnlockLoc); + Handler.handleUnmatchedUnlock(DiagKind, Mutex.toString(), UnlockLoc); return; } // Generic lock removal doesn't care about lock kind mismatches, but // otherwise diagnose when the lock kinds are mismatched. if (ReceivedKind != LK_Generic && LDat->LKind != ReceivedKind) { - Handler.handleIncorrectUnlockKind(Mutex.toString(), LDat->LKind, + Handler.handleIncorrectUnlockKind(DiagKind, Mutex.toString(), LDat->LKind, ReceivedKind, UnlockLoc); return; } @@ -1517,8 +1596,8 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const SExpr &Mutex, // We're releasing the underlying mutex, but not destroying the // managing object. Warn on dual release. if (!FSet.findLock(FactMan, LDat->UnderlyingMutex)) { - Handler.handleUnmatchedUnlock(LDat->UnderlyingMutex.toString(), - UnlockLoc); + Handler.handleUnmatchedUnlock( + DiagKind, LDat->UnderlyingMutex.toString(), UnlockLoc); } FSet.removeLock(FactMan, LDat->UnderlyingMutex); return; @@ -1540,7 +1619,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, // The mutex held is the "this" object. SExpr Mu(0, Exp, D, SelfDecl); if (!Mu.isValid()) - SExpr::warnInvalidLock(Handler, 0, Exp, D); + SExpr::warnInvalidLock(Handler, 0, Exp, D, ClassifyDiagnostic(Attr)); else Mtxs.push_back_nodup(Mu); return; @@ -1549,7 +1628,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) { SExpr Mu(*I, Exp, D, SelfDecl); if (!Mu.isValid()) - SExpr::warnInvalidLock(Handler, *I, Exp, D); + SExpr::warnInvalidLock(Handler, *I, Exp, D, ClassifyDiagnostic(Attr)); else Mtxs.push_back_nodup(Mu); } @@ -1682,6 +1761,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, bool Negate = false; const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->getBlockID()]; const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext; + StringRef CapDiagKind = "mutex"; CallExpr *Exp = const_cast<CallExpr*>(getTrylockCallExpr(Cond, LVarCtx, Negate)); @@ -1705,6 +1785,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, cast<ExclusiveTrylockFunctionAttr>(Attr); getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, A->getSuccessValue(), Negate); + CapDiagKind = ClassifyDiagnostic(A); break; } case attr::SharedTrylockFunction: { @@ -1712,6 +1793,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, cast<SharedTrylockFunctionAttr>(Attr); getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, A->getSuccessValue(), Negate); + CapDiagKind = ClassifyDiagnostic(A); break; } default: @@ -1721,17 +1803,13 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, // Add and remove locks. SourceLocation Loc = Exp->getExprLoc(); - for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) { - addLock(Result, ExclusiveLocksToAdd[i], - LockData(Loc, LK_Exclusive)); - } - for (unsigned i=0,n=SharedLocksToAdd.size(); i<n; ++i) { - addLock(Result, SharedLocksToAdd[i], - LockData(Loc, LK_Shared)); - } + for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd) + addLock(Result, ExclusiveLockToAdd, LockData(Loc, LK_Exclusive), + CapDiagKind); + for (const auto &SharedLockToAdd : SharedLocksToAdd) + addLock(Result, SharedLockToAdd, LockData(Loc, LK_Shared), CapDiagKind); } - /// \brief We use this class to visit different types of expressions in /// CFGBlocks, and build up the lockset. /// An expression may cause us to add or remove locks from the lockset, or else @@ -1746,11 +1824,12 @@ class BuildLockset : public StmtVisitor<BuildLockset> { unsigned CtxIndex; // Helper functions - const ValueDecl *getValueDecl(const Expr *Exp); void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK, - Expr *MutexExp, ProtectedOperationKind POK); - void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp); + Expr *MutexExp, ProtectedOperationKind POK, + StringRef DiagKind); + void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp, + StringRef DiagKind); void checkAccess(const Expr *Exp, AccessKind AK); void checkPtAccess(const Expr *Exp, AccessKind AK); @@ -1774,31 +1853,17 @@ public: void VisitDeclStmt(DeclStmt *S); }; - -/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs -const ValueDecl *BuildLockset::getValueDecl(const Expr *Exp) { - if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Exp)) - return getValueDecl(CE->getSubExpr()); - - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp)) - return DR->getDecl(); - - if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) - return ME->getMemberDecl(); - - return 0; -} - /// \brief Warn if the LSet does not contain a lock sufficient to protect access /// of at least the passed in AccessKind. void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK, Expr *MutexExp, - ProtectedOperationKind POK) { + ProtectedOperationKind POK, + StringRef DiagKind) { LockKind LK = getLockKindFromAccessKind(AK); SExpr Mutex(MutexExp, Exp, D); if (!Mutex.isValid()) { - SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D); + SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D, DiagKind); return; } else if (Mutex.shouldIgnore()) { return; @@ -1814,40 +1879,38 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, LDat = &FEntry->LDat; std::string PartMatchStr = FEntry->MutID.toString(); StringRef PartMatchName(PartMatchStr); - Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK, - Exp->getExprLoc(), &PartMatchName); + Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(), + LK, Exp->getExprLoc(), + &PartMatchName); } else { // Warn that there's no match at all. - Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK, - Exp->getExprLoc()); + Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(), + LK, Exp->getExprLoc()); } NoError = false; } // Make sure the mutex we found is the right kind. if (NoError && LDat && !LDat->isAtLeast(LK)) - Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK, + Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(), LK, Exp->getExprLoc()); } /// \brief Warn if the LSet contains the given lock. -void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr* Exp, - Expr *MutexExp) { +void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, + Expr *MutexExp, + StringRef DiagKind) { SExpr Mutex(MutexExp, Exp, D); if (!Mutex.isValid()) { - SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D); + SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D, DiagKind); return; } LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex); - if (LDat) { - std::string DeclName = D->getNameAsString(); - StringRef DeclNameSR (DeclName); - Analyzer->Handler.handleFunExcludesLock(DeclNameSR, Mutex.toString(), - Exp->getExprLoc()); - } + if (LDat) + Analyzer->Handler.handleFunExcludesLock( + DiagKind, D->getNameAsString(), Mutex.toString(), Exp->getExprLoc()); } - /// \brief Checks guarded_by and pt_guarded_by attributes. /// Whenever we identify an access (read or write) to a DeclRefExpr that is /// marked with guarded_by, we must ensure the appropriate mutexes are held. @@ -1880,11 +1943,12 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) { return; if (D->hasAttr<GuardedVarAttr>() && FSet.isEmpty()) - Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK, + Analyzer->Handler.handleNoMutexHeld("mutex", D, POK_VarAccess, AK, Exp->getExprLoc()); for (const auto *I : D->specific_attrs<GuardedByAttr>()) - warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarAccess); + warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarAccess, + ClassifyDiagnostic(I)); } /// \brief Checks pt_guarded_by and pt_guarded_var attributes. @@ -1912,14 +1976,14 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) { return; if (D->hasAttr<PtGuardedVarAttr>() && FSet.isEmpty()) - Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK, + Analyzer->Handler.handleNoMutexHeld("mutex", D, POK_VarDereference, AK, Exp->getExprLoc()); for (auto const *I : D->specific_attrs<PtGuardedByAttr>()) - warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarDereference); + warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarDereference, + ClassifyDiagnostic(I)); } - /// \brief Process a function call, method call, constructor call, /// or destructor call. This involves looking at the attributes on the /// corresponding function/method/constructor/destructor, issuing warnings, @@ -1935,6 +1999,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { const AttrVec &ArgAttrs = D->getAttrs(); MutexIDList ExclusiveLocksToAdd, SharedLocksToAdd; MutexIDList ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove; + StringRef CapDiagKind = "mutex"; for(unsigned i = 0; i < ArgAttrs.size(); ++i) { Attr *At = const_cast<Attr*>(ArgAttrs[i]); @@ -1946,6 +2011,8 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, Exp, D, VD); + + CapDiagKind = ClassifyDiagnostic(A); break; } @@ -1957,10 +2024,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { MutexIDList AssertLocks; Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD); - for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) { - Analyzer->addLock(FSet, AssertLocks[i], - LockData(Loc, LK_Exclusive, false, true)); - } + for (const auto &AssertLock : AssertLocks) + Analyzer->addLock(FSet, AssertLock, + LockData(Loc, LK_Exclusive, false, true), + ClassifyDiagnostic(A)); break; } case attr::AssertSharedLock: { @@ -1968,10 +2035,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { MutexIDList AssertLocks; Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD); - for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) { - Analyzer->addLock(FSet, AssertLocks[i], - LockData(Loc, LK_Shared, false, true)); - } + for (const auto &AssertLock : AssertLocks) + Analyzer->addLock(FSet, AssertLock, + LockData(Loc, LK_Shared, false, true), + ClassifyDiagnostic(A)); break; } @@ -1985,6 +2052,8 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD); else Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD); + + CapDiagKind = ClassifyDiagnostic(A); break; } @@ -1994,7 +2063,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { for (RequiresCapabilityAttr::args_iterator I = A->args_begin(), E = A->args_end(); I != E; ++I) warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, *I, - POK_FunctionCall); + POK_FunctionCall, ClassifyDiagnostic(A)); break; } @@ -2003,7 +2072,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { for (LocksExcludedAttr::args_iterator I = A->args_begin(), E = A->args_end(); I != E; ++I) { - warnIfMutexHeld(D, Exp, *I); + warnIfMutexHeld(D, Exp, *I, ClassifyDiagnostic(A)); } break; } @@ -2026,9 +2095,11 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { // Add locks. for (const auto &M : ExclusiveLocksToAdd) - Analyzer->addLock(FSet, M, LockData(Loc, LK_Exclusive, isScopedVar)); + Analyzer->addLock(FSet, M, LockData(Loc, LK_Exclusive, isScopedVar), + CapDiagKind); for (const auto &M : SharedLocksToAdd) - Analyzer->addLock(FSet, M, LockData(Loc, LK_Shared, isScopedVar)); + Analyzer->addLock(FSet, M, LockData(Loc, LK_Shared, isScopedVar), + CapDiagKind); // Add the managing object as a dummy mutex, mapped to the underlying mutex. // FIXME -- this doesn't work if we acquire multiple locks. @@ -2038,20 +2109,22 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { SExpr SMutex(&DRE, 0, 0); for (const auto &M : ExclusiveLocksToAdd) - Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Exclusive, M)); + Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Exclusive, M), + CapDiagKind); for (const auto &M : SharedLocksToAdd) - Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Shared, M)); + Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Shared, M), + CapDiagKind); } // Remove locks. // FIXME -- should only fully remove if the attribute refers to 'this'. bool Dtor = isa<CXXDestructorDecl>(D); for (const auto &M : ExclusiveLocksToRemove) - Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Exclusive); + Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Exclusive, CapDiagKind); for (const auto &M : SharedLocksToRemove) - Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Shared); + Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Shared, CapDiagKind); for (const auto &M : GenericLocksToRemove) - Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Generic); + Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Generic, CapDiagKind); } @@ -2212,9 +2285,8 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, if (I1 != FSet1.end()) { const LockData* LDat1 = &FactMan[*I1].LDat; if (LDat1->LKind != LDat2.LKind) { - Handler.handleExclusiveAndShared(FSet2Mutex.toString(), - LDat2.AcquireLoc, - LDat1->AcquireLoc); + Handler.handleExclusiveAndShared("mutex", FSet2Mutex.toString(), + LDat2.AcquireLoc, LDat1->AcquireLoc); if (Modify && LDat1->LKind != LK_Exclusive) { // Take the exclusive lock, which is the one in FSet2. *I1 = *I; @@ -2230,15 +2302,14 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, // If this is a scoped lock that manages another mutex, and if the // underlying mutex is still held, then warn about the underlying // mutex. - Handler.handleMutexHeldEndOfScope(LDat2.UnderlyingMutex.toString(), - LDat2.AcquireLoc, - JoinLoc, LEK1); + Handler.handleMutexHeldEndOfScope("mutex", + LDat2.UnderlyingMutex.toString(), + LDat2.AcquireLoc, JoinLoc, LEK1); } } else if (!LDat2.Managed && !FSet2Mutex.isUniversal() && !LDat2.Asserted) - Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(), - LDat2.AcquireLoc, - JoinLoc, LEK1); + Handler.handleMutexHeldEndOfScope("mutex", FSet2Mutex.toString(), + LDat2.AcquireLoc, JoinLoc, LEK1); } } @@ -2254,15 +2325,14 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, // If this is a scoped lock that manages another mutex, and if the // underlying mutex is still held, then warn about the underlying // mutex. - Handler.handleMutexHeldEndOfScope(LDat1.UnderlyingMutex.toString(), - LDat1.AcquireLoc, - JoinLoc, LEK1); + Handler.handleMutexHeldEndOfScope("mutex", + LDat1.UnderlyingMutex.toString(), + LDat1.AcquireLoc, JoinLoc, LEK1); } } else if (!LDat1.Managed && !FSet1Mutex.isUniversal() && !LDat1.Asserted) - Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(), - LDat1.AcquireLoc, - JoinLoc, LEK2); + Handler.handleMutexHeldEndOfScope("mutex", FSet1Mutex.toString(), + LDat1.AcquireLoc, JoinLoc, LEK2); if (Modify) FSet1.removeLock(FactMan, FSet1Mutex); } @@ -2343,6 +2413,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { MutexIDList ExclusiveLocksToAdd; MutexIDList SharedLocksToAdd; + StringRef CapDiagKind = "mutex"; SourceLocation Loc = D->getLocation(); for (unsigned i = 0; i < ArgAttrs.size(); ++i) { @@ -2351,6 +2422,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (RequiresCapabilityAttr *A = dyn_cast<RequiresCapabilityAttr>(Attr)) { getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, 0, D); + CapDiagKind = ClassifyDiagnostic(A); } else if (auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) { // UNLOCK_FUNCTION() is used to hide the underlying lock implementation. // We must ignore such methods. @@ -2359,12 +2431,14 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // FIXME -- deal with exclusive vs. shared unlock functions? getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D); getMutexIDs(LocksReleased, A, (Expr*) 0, D); + CapDiagKind = ClassifyDiagnostic(A); } else if (auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) { if (A->args_size() == 0) return; getMutexIDs(A->isShared() ? SharedLocksAcquired : ExclusiveLocksAcquired, A, nullptr, D); + CapDiagKind = ClassifyDiagnostic(A); } else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) { // Don't try to check trylock functions for now return; @@ -2375,14 +2449,12 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } // FIXME -- Loc can be wrong here. - for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) { - addLock(InitialLockset, ExclusiveLocksToAdd[i], - LockData(Loc, LK_Exclusive)); - } - for (unsigned i=0,n=SharedLocksToAdd.size(); i<n; ++i) { - addLock(InitialLockset, SharedLocksToAdd[i], - LockData(Loc, LK_Shared)); - } + for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd) + addLock(InitialLockset, ExclusiveLockToAdd, LockData(Loc, LK_Exclusive), + CapDiagKind); + for (const auto &SharedLockToAdd : SharedLocksToAdd) + addLock(InitialLockset, SharedLockToAdd, LockData(Loc, LK_Shared), + CapDiagKind); } for (PostOrderCFGView::iterator I = SortedGraph->begin(), |

