35 #include "llvm/ADT/ImmutableMap.h"
36 #include "llvm/ADT/PostOrderIterator.h"
37 #include "llvm/ADT/SmallVector.h"
38 #include "llvm/ADT/StringRef.h"
39 #include "llvm/Support/raw_ostream.h"
45 using namespace clang;
46 using namespace threadSafety;
59 const Expr *DeclExp, StringRef
Kind) {
71 class CapExprSet :
public SmallVector<CapabilityExpr, 4> {
75 iterator It = std::find_if(begin(), end(),
104 bool Asrt,
bool Declrd =
false)
108 virtual ~FactEntry() {}
112 bool asserted()
const {
return Asserted; }
113 bool declared()
const {
return Declared; }
115 void setDeclared(
bool D) { Declared = D; }
118 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
121 virtual void handleUnlock(FactSet &FSet, FactManager &FactMan,
124 StringRef DiagKind)
const = 0;
133 typedef unsigned short FactID;
139 std::vector<std::unique_ptr<FactEntry>> Facts;
142 FactID newFact(std::unique_ptr<FactEntry> Entry) {
143 Facts.push_back(std::move(Entry));
144 return static_cast<unsigned short>(Facts.size() - 1);
147 const FactEntry &operator[](FactID F)
const {
return *Facts[F]; }
148 FactEntry &operator[](FactID F) {
return *Facts[F]; }
166 typedef FactVec::iterator iterator;
167 typedef FactVec::const_iterator const_iterator;
169 iterator begin() {
return FactIDs.begin(); }
170 const_iterator begin()
const {
return FactIDs.begin(); }
172 iterator end() {
return FactIDs.end(); }
173 const_iterator end()
const {
return FactIDs.end(); }
175 bool isEmpty()
const {
return FactIDs.size() == 0; }
178 bool isEmpty(FactManager &FactMan)
const {
179 for (FactID FID : *
this) {
180 if (!FactMan[FID].negative())
186 void addLockByID(FactID
ID) { FactIDs.push_back(ID); }
188 FactID addLock(FactManager &FM, std::unique_ptr<FactEntry> Entry) {
189 FactID F = FM.newFact(std::move(Entry));
190 FactIDs.push_back(F);
195 unsigned n = FactIDs.size();
199 for (
unsigned i = 0; i < n-1; ++i) {
200 if (FM[FactIDs[i]].
matches(CapE)) {
201 FactIDs[i] = FactIDs[n-1];
206 if (FM[FactIDs[n-1]].
matches(CapE)) {
213 iterator findLockIter(FactManager &FM,
const CapabilityExpr &CapE) {
214 return std::find_if(begin(), end(), [&](FactID ID) {
215 return FM[
ID].matches(CapE);
219 FactEntry *findLock(FactManager &FM,
const CapabilityExpr &CapE)
const {
220 auto I = std::find_if(begin(), end(), [&](FactID ID) {
221 return FM[
ID].matches(CapE);
223 return I != end() ? &FM[*
I] :
nullptr;
226 FactEntry *findLockUniv(FactManager &FM,
const CapabilityExpr &CapE)
const {
227 auto I = std::find_if(begin(), end(), [&](FactID ID) ->
bool {
228 return FM[
ID].matchesUniv(CapE);
230 return I != end() ? &FM[*
I] :
nullptr;
233 FactEntry *findPartialMatch(FactManager &FM,
235 auto I = std::find_if(begin(), end(), [&](FactID ID) ->
bool {
236 return FM[
ID].partiallyMatches(CapE);
238 return I != end() ? &FM[*
I] :
nullptr;
241 bool containsMutexDecl(FactManager &FM,
const ValueDecl* Vd)
const {
242 auto I = std::find_if(begin(), end(), [&](FactID ID) ->
bool {
243 return FM[
ID].valueDecl() == Vd;
249 class ThreadSafetyAnalyzer;
253 namespace threadSafety {
259 BeforeInfo() : Visited(0) {}
260 BeforeInfo(BeforeInfo &&) =
default;
266 typedef llvm::DenseMap<const ValueDecl *, std::unique_ptr<BeforeInfo>>
268 typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap;
273 BeforeInfo* insertAttrExprs(
const ValueDecl* Vd,
274 ThreadSafetyAnalyzer& Analyzer);
276 BeforeInfo *getBeforeInfoForDecl(
const ValueDecl *Vd,
277 ThreadSafetyAnalyzer &Analyzer);
279 void checkBeforeAfter(
const ValueDecl* Vd,
281 ThreadSafetyAnalyzer& Analyzer,
293 class LocalVariableMap;
301 struct CFGBlockInfo {
304 LocalVarContext EntryContext;
305 LocalVarContext ExitContext;
312 return Side == CBS_Entry ? EntrySet : ExitSet;
315 return Side == CBS_Entry ? EntryLoc : ExitLoc;
319 CFGBlockInfo(LocalVarContext EmptyCtx)
320 : EntryContext(EmptyCtx), ExitContext(EmptyCtx), Reachable(
false)
324 static CFGBlockInfo getEmptyBlockInfo(LocalVariableMap &M);
342 class LocalVariableMap {
344 typedef LocalVarContext
Context;
350 struct VarDefinition {
352 friend class LocalVariableMap;
359 bool isReference() {
return !Exp; }
364 : Dec(D), Exp(E), Ref(0), Ctx(C)
369 : Dec(D), Exp(nullptr), Ref(R), Ctx(C)
374 Context::Factory ContextFactory;
375 std::vector<VarDefinition> VarDefinitions;
376 std::vector<unsigned> CtxIndices;
377 std::vector<std::pair<Stmt*, Context> > SavedContexts;
382 VarDefinitions.push_back(VarDefinition(
nullptr, 0u, getEmptyContext()));
387 const unsigned *i = Ctx.lookup(D);
390 assert(*i < VarDefinitions.size());
391 return &VarDefinitions[*i];
398 const unsigned *
P = Ctx.lookup(D);
404 if (VarDefinitions[i].Exp) {
405 Ctx = VarDefinitions[i].Ctx;
406 return VarDefinitions[i].Exp;
408 i = VarDefinitions[i].Ref;
413 Context getEmptyContext() {
return ContextFactory.getEmptyMap(); }
419 if (SavedContexts[CtxIndex+1].first == S) {
427 void dumpVarDefinitionName(
unsigned i) {
429 llvm::errs() <<
"Undefined";
432 const NamedDecl *Dec = VarDefinitions[i].Dec;
434 llvm::errs() <<
"<<NULL>>";
438 llvm::errs() <<
"." << i <<
" " << ((
const void*) Dec);
443 for (
unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) {
444 const Expr *Exp = VarDefinitions[i].Exp;
445 unsigned Ref = VarDefinitions[i].Ref;
447 dumpVarDefinitionName(i);
448 llvm::errs() <<
" = ";
449 if (Exp) Exp->
dump();
451 dumpVarDefinitionName(Ref);
452 llvm::errs() <<
"\n";
459 for (Context::iterator
I = C.begin(),
E = C.end();
I !=
E; ++
I) {
462 const unsigned *i = C.lookup(D);
463 llvm::errs() <<
" -> ";
464 dumpVarDefinitionName(*i);
465 llvm::errs() <<
"\n";
471 std::vector<CFGBlockInfo> &BlockInfo);
475 unsigned getContextIndex() {
return SavedContexts.size()-1; }
479 SavedContexts.push_back(std::make_pair(S,C));
485 assert(!Ctx.contains(D));
486 unsigned newID = VarDefinitions.size();
487 Context NewCtx = ContextFactory.add(Ctx, D, newID);
488 VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
494 unsigned newID = VarDefinitions.size();
495 Context NewCtx = ContextFactory.add(Ctx, D, newID);
496 VarDefinitions.push_back(VarDefinition(D, i, Ctx));
503 if (Ctx.contains(D)) {
504 unsigned newID = VarDefinitions.size();
505 Context NewCtx = ContextFactory.remove(Ctx, D);
506 NewCtx = ContextFactory.add(NewCtx, D, newID);
507 VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
517 if (NewCtx.contains(D)) {
518 NewCtx = ContextFactory.remove(NewCtx, D);
519 NewCtx = ContextFactory.add(NewCtx, D, 0);
527 if (NewCtx.contains(D)) {
528 NewCtx = ContextFactory.remove(NewCtx, D);
537 friend class VarMapBuilder;
542 CFGBlockInfo CFGBlockInfo::getEmptyBlockInfo(LocalVariableMap &M) {
543 return CFGBlockInfo(M.getEmptyContext());
548 class VarMapBuilder :
public StmtVisitor<VarMapBuilder> {
550 LocalVariableMap* VMap;
551 LocalVariableMap::Context Ctx;
553 VarMapBuilder(LocalVariableMap *VM, LocalVariableMap::Context C)
554 : VMap(VM), Ctx(C) {}
562 void VarMapBuilder::VisitDeclStmt(
DeclStmt *S) {
563 bool modifiedCtx =
false;
565 for (
const auto *D : DGrp) {
566 if (
const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
567 const Expr *
E = VD->getInit();
572 Ctx = VMap->addDefinition(VD, E, Ctx);
578 VMap->saveContext(S, Ctx);
589 if (
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHSExp)) {
591 if (Ctx.lookup(VDec)) {
593 Ctx = VMap->updateDefinition(VDec, BO->
getRHS(), Ctx);
596 Ctx = VMap->clearDefinition(VDec, Ctx);
597 VMap->saveContext(BO, Ctx);
606 LocalVariableMap::Context
609 for (
const auto &P : C1) {
611 const unsigned *i2 = C2.lookup(Dec);
613 Result = removeDefinition(Dec, Result);
614 else if (*i2 != P.second)
615 Result = clearDefinition(Dec, Result);
623 LocalVariableMap::Context LocalVariableMap::createReferenceContext(
Context C) {
624 Context Result = getEmptyContext();
625 for (
const auto &P : C)
626 Result = addReference(P.first, P.second, Result);
633 void LocalVariableMap::intersectBackEdge(
Context C1,
Context C2) {
634 for (
const auto &P : C1) {
635 unsigned i1 = P.second;
636 VarDefinition *VDef = &VarDefinitions[i1];
637 assert(VDef->isReference());
639 const unsigned *i2 = C2.lookup(P.first);
640 if (!i2 || (*i2 != i1))
684 void LocalVariableMap::traverseCFG(
CFG *CFGraph,
686 std::vector<CFGBlockInfo> &BlockInfo) {
691 for (
const auto *CurrBlock : *SortedGraph) {
692 int CurrBlockID = CurrBlock->getBlockID();
693 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
695 VisitedBlocks.insert(CurrBlock);
698 bool HasBackEdges =
false;
701 PE = CurrBlock->pred_end(); PI != PE; ++PI) {
703 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI)) {
708 int PrevBlockID = (*PI)->getBlockID();
709 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
712 CurrBlockInfo->EntryContext = PrevBlockInfo->ExitContext;
716 CurrBlockInfo->EntryContext =
717 intersectContexts(CurrBlockInfo->EntryContext,
718 PrevBlockInfo->ExitContext);
725 CurrBlockInfo->EntryContext =
726 createReferenceContext(CurrBlockInfo->EntryContext);
729 saveContext(
nullptr, CurrBlockInfo->EntryContext);
730 CurrBlockInfo->EntryIndex = getContextIndex();
733 VarMapBuilder VMapBuilder(
this, CurrBlockInfo->EntryContext);
735 BE = CurrBlock->end(); BI != BE; ++BI) {
736 switch (BI->getKind()) {
739 VMapBuilder.Visit(const_cast<Stmt*>(CS.
getStmt()));
746 CurrBlockInfo->ExitContext = VMapBuilder.Ctx;
750 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
752 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
757 Context LoopEnd = CurrBlockInfo->ExitContext;
758 intersectBackEdge(LoopBegin, LoopEnd);
764 saveContext(
nullptr, BlockInfo[exitID].ExitContext);
769 static void findBlockLocations(
CFG *CFGraph,
771 std::vector<CFGBlockInfo> &BlockInfo) {
772 for (
const auto *CurrBlock : *SortedGraph) {
773 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
777 if (
const Stmt *S = CurrBlock->getTerminator()) {
778 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->
getLocStart();
781 BE = CurrBlock->rend(); BI != BE; ++BI) {
784 CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart();
790 if (CurrBlockInfo->ExitLoc.isValid()) {
794 BE = CurrBlock->end(); BI != BE; ++BI) {
797 CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart();
801 }
else if (CurrBlock->pred_size() == 1 && *CurrBlock->pred_begin() &&
802 CurrBlock != &CFGraph->
getExit()) {
805 CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc =
806 BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc;
811 class LockableFactEntry :
public FactEntry {
817 bool Mng =
false,
bool Asrt =
false)
818 : FactEntry(CE, LK, Loc, Asrt), Managed(Mng) {}
821 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
824 if (!Managed && !asserted() && !negative() && !isUniversal()) {
830 void handleUnlock(FactSet &FSet, FactManager &FactMan,
833 StringRef DiagKind)
const override {
834 FSet.removeLock(FactMan, Cp);
836 FSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
842 class ScopedLockableFactEntry :
public FactEntry {
848 const CapExprSet &Excl,
const CapExprSet &Shrd)
850 for (
const auto &M : Excl)
851 UnderlyingMutexes.push_back(M.sexpr());
852 for (
const auto &M : Shrd)
853 UnderlyingMutexes.push_back(M.sexpr());
857 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
860 for (
const til::SExpr *UnderlyingMutex : UnderlyingMutexes) {
861 if (FSet.findLock(FactMan,
CapabilityExpr(UnderlyingMutex,
false))) {
865 "mutex",
sx::toString(UnderlyingMutex), loc(), JoinLoc, LEK);
870 void handleUnlock(FactSet &FSet, FactManager &FactMan,
873 StringRef DiagKind)
const override {
874 assert(!Cp.
negative() &&
"Managing object cannot be negative.");
875 for (
const til::SExpr *UnderlyingMutex : UnderlyingMutexes) {
877 auto UnderEntry = llvm::make_unique<LockableFactEntry>(
883 if (FSet.findLock(FactMan, UnderCp)) {
884 FSet.removeLock(FactMan, UnderCp);
885 FSet.addLock(FactMan, std::move(UnderEntry));
890 if (!FSet.findLock(FactMan, UnderCp)) {
894 FSet.removeLock(FactMan, UnderCp);
895 FSet.addLock(FactMan, std::move(UnderEntry));
899 FSet.removeLock(FactMan, Cp);
904 class ThreadSafetyAnalyzer {
905 friend class BuildLockset;
908 llvm::BumpPtrAllocator Bpa;
914 LocalVariableMap LocalVarMap;
916 std::vector<CFGBlockInfo> BlockInfo;
922 : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
926 void addLock(FactSet &FSet, std::unique_ptr<FactEntry> Entry,
927 StringRef DiagKind,
bool ReqAttr =
false);
932 template <
typename AttrType>
933 void getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
Expr *Exp,
936 template <
class AttrType>
937 void getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
Expr *Exp,
940 Expr *BrE,
bool Neg);
942 const CallExpr* getTrylockCallExpr(
const Stmt *Cond, LocalVarContext C,
945 void getEdgeLockset(FactSet &Result,
const FactSet &ExitSet,
949 void intersectAndWarn(FactSet &FSet1,
const FactSet &FSet2,
954 void intersectAndWarn(FactSet &FSet1,
const FactSet &FSet2,
957 intersectAndWarn(FSet1, FSet2, JoinLoc, LEK1, LEK1, Modify);
966 ThreadSafetyAnalyzer& Analyzer) {
968 BeforeInfo *Info =
nullptr;
972 std::unique_ptr<BeforeInfo> &InfoPtr = BMap[Vd];
974 InfoPtr.reset(
new BeforeInfo());
975 Info = InfoPtr.get();
979 switch (At->getKind()) {
980 case attr::AcquiredBefore: {
981 auto *A = cast<AcquiredBeforeAttr>(At);
984 for (
const auto *Arg : A->args()) {
986 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
988 Info->Vect.push_back(Cpvd);
989 auto It = BMap.find(Cpvd);
990 if (It == BMap.end())
996 case attr::AcquiredAfter: {
997 auto *A = cast<AcquiredAfterAttr>(At);
1000 for (
const auto *Arg : A->args()) {
1002 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
1006 ArgInfo->Vect.push_back(Vd);
1019 BeforeSet::BeforeInfo *
1021 ThreadSafetyAnalyzer &Analyzer) {
1022 auto It = BMap.find(Vd);
1023 BeforeInfo *Info =
nullptr;
1024 if (It == BMap.end())
1027 Info = It->second.get();
1028 assert(Info &&
"BMap contained nullptr?");
1034 const FactSet& FSet,
1035 ThreadSafetyAnalyzer& Analyzer,
1041 std::function<bool (const ValueDecl*)> traverse = [&](
const ValueDecl* Vd) {
1047 if (Info->Visited == 1)
1050 if (Info->Visited == 2)
1053 if (Info->Vect.empty())
1056 InfoVect.push_back(Info);
1058 for (
auto *Vdb : Info->Vect) {
1060 if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
1061 StringRef L1 = StartVd->
getName();
1062 StringRef L2 = Vdb->getName();
1063 Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc);
1066 if (traverse(Vdb)) {
1067 if (CycMap.find(Vd) == CycMap.end()) {
1068 CycMap.insert(std::make_pair(Vd,
true));
1070 Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->
getLocation());
1080 for (
auto* Info : InfoVect)
1088 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
1091 if (
const auto *DR = dyn_cast<DeclRefExpr>(Exp))
1092 return DR->getDecl();
1094 if (
const auto *ME = dyn_cast<MemberExpr>(Exp))
1095 return ME->getMemberDecl();
1101 template <
typename Ty>
1102 class has_arg_iterator_range {
1103 typedef char yes[1];
1106 template <
typename Inner>
1107 static yes& test(Inner *
I, decltype(I->args()) * =
nullptr);
1110 static no& test(...);
1113 static const bool value =
sizeof(test<Ty>(
nullptr)) ==
sizeof(yes);
1118 return A->getName();
1126 if (
const auto *RD = RT->getDecl())
1127 if (
const auto *CA = RD->getAttr<CapabilityAttr>())
1130 if (
const auto *TD = TT->getDecl())
1131 if (
const auto *CA = TD->getAttr<CapabilityAttr>())
1140 assert(VD &&
"No ValueDecl passed");
1146 template <
typename AttrTy>
1147 static typename std::enable_if<!has_arg_iterator_range<AttrTy>::value,
1155 template <
typename AttrTy>
1156 static typename std::enable_if<has_arg_iterator_range<AttrTy>::value,
1159 for (
const auto *Arg : A->args()) {
1167 inline bool ThreadSafetyAnalyzer::inCurrentScope(
const CapabilityExpr &CapE) {
1170 if (
auto *P = dyn_cast_or_null<til::Project>(CapE.
sexpr())) {
1171 auto *VD = P->clangDecl();
1173 return VD->getDeclContext() == CurrentMethod->getDeclContext();
1181 void ThreadSafetyAnalyzer::addLock(FactSet &FSet,
1182 std::unique_ptr<FactEntry> Entry,
1183 StringRef DiagKind,
bool ReqAttr) {
1184 if (Entry->shouldIgnore())
1187 if (!ReqAttr && !Entry->negative()) {
1190 FactEntry *Nen = FSet.findLock(FactMan, NegC);
1192 FSet.removeLock(FactMan, NegC);
1195 if (inCurrentScope(*Entry) && !Entry->asserted())
1203 !Entry->asserted() && !Entry->declared()) {
1204 GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *
this,
1205 Entry->loc(), DiagKind);
1209 if (FSet.findLock(FactMan, *Entry)) {
1210 if (!Entry->asserted())
1213 FSet.addLock(FactMan, std::move(Entry));
1220 void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const CapabilityExpr &Cp,
1222 bool FullyRemove,
LockKind ReceivedKind,
1223 StringRef DiagKind) {
1227 const FactEntry *LDat = FSet.findLock(FactMan, Cp);
1235 if (ReceivedKind !=
LK_Generic && LDat->kind() != ReceivedKind) {
1237 LDat->kind(), ReceivedKind, UnlockLoc);
1240 LDat->handleUnlock(FSet, FactMan, Cp, UnlockLoc, FullyRemove, Handler,
1247 template <
typename AttrType>
1248 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
1251 if (Attr->args_size() == 0) {
1253 CapabilityExpr Cp = SxBuilder.translateAttrExpr(
nullptr, D, Exp, SelfDecl);
1260 Mtxs.push_back_nodup(Cp);
1264 for (
const auto *Arg : Attr->args()) {
1265 CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, SelfDecl);
1272 Mtxs.push_back_nodup(Cp);
1280 template <
class AttrType>
1281 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
1285 Expr *BrE,
bool Neg) {
1287 bool branch =
false;
1289 branch = BLE->getValue();
1290 else if (
IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE))
1291 branch = ILE->getValue().getBoolValue();
1293 int branchnum = branch ? 0 : 1;
1295 branchnum = !branchnum;
1300 SE = PredBlock->
succ_end(); SI != SE && i < 2; ++SI, ++i) {
1301 if (*SI == CurrBlock && i == branchnum)
1302 getMutexIDs(Mtxs, Attr, Exp, D);
1307 if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) {
1311 TCond = BLE->getValue();
1314 TCond = ILE->getValue().getBoolValue();
1326 const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(
const Stmt *Cond,
1332 if (
const CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
1335 else if (
const ParenExpr *PE = dyn_cast<ParenExpr>(Cond)) {
1336 return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
1339 return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
1342 return getTrylockCallExpr(EWC->getSubExpr(), C, Negate);
1344 else if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
1345 const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
1346 return getTrylockCallExpr(E, C, Negate);
1348 else if (
const UnaryOperator *UOP = dyn_cast<UnaryOperator>(Cond)) {
1349 if (UOP->getOpcode() == UO_LNot) {
1351 return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
1355 else if (
const BinaryOperator *BOP = dyn_cast<BinaryOperator>(Cond)) {
1356 if (BOP->getOpcode() == BO_EQ || BOP->getOpcode() == BO_NE) {
1357 if (BOP->getOpcode() == BO_NE)
1362 if (!TCond) Negate = !Negate;
1363 return getTrylockCallExpr(BOP->getLHS(), C, Negate);
1367 if (!TCond) Negate = !Negate;
1368 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1372 if (BOP->getOpcode() == BO_LAnd) {
1374 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1376 if (BOP->getOpcode() == BO_LOr) {
1377 return getTrylockCallExpr(BOP->getRHS(), C, Negate);
1388 void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
1389 const FactSet &ExitSet,
1398 bool Negate =
false;
1399 const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->
getBlockID()];
1400 const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext;
1401 StringRef CapDiagKind =
"mutex";
1404 const_cast<CallExpr*
>(getTrylockCallExpr(Cond, LVarCtx, Negate));
1409 if(!FunDecl || !FunDecl->
hasAttrs())
1412 CapExprSet ExclusiveLocksToAdd;
1413 CapExprSet SharedLocksToAdd;
1416 for (
auto *Attr : FunDecl->
attrs()) {
1417 switch (Attr->getKind()) {
1418 case attr::ExclusiveTrylockFunction: {
1419 ExclusiveTrylockFunctionAttr *A =
1420 cast<ExclusiveTrylockFunctionAttr>(Attr);
1421 getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
1422 PredBlock, CurrBlock, A->getSuccessValue(), Negate);
1426 case attr::SharedTrylockFunction: {
1427 SharedTrylockFunctionAttr *A =
1428 cast<SharedTrylockFunctionAttr>(Attr);
1429 getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
1430 PredBlock, CurrBlock, A->getSuccessValue(), Negate);
1441 for (
const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
1442 addLock(Result, llvm::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
1445 for (
const auto &SharedLockToAdd : SharedLocksToAdd)
1446 addLock(Result, llvm::make_unique<LockableFactEntry>(SharedLockToAdd,
1457 class BuildLockset :
public StmtVisitor<BuildLockset> {
1458 friend class ThreadSafetyAnalyzer;
1460 ThreadSafetyAnalyzer *Analyzer;
1462 LocalVariableMap::Context LVarCtx;
1470 StringRef DiagKind);
1480 BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
1483 FSet(Info.EntrySet),
1484 LVarCtx(Info.EntryContext),
1485 CtxIndex(Info.EntryIndex)
1499 void BuildLockset::warnIfMutexNotHeld(
const NamedDecl *D,
const Expr *Exp,
1505 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1507 warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
1515 FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
1517 Analyzer->Handler.handleFunExcludesLock(
1524 if (!Analyzer->inCurrentScope(Cp))
1528 LDat = FSet.findLock(Analyzer->FactMan, Cp);
1530 Analyzer->Handler.handleMutexNotHeld(
"", D, POK, Cp.
toString(),
1536 FactEntry* LDat = FSet.findLockUniv(Analyzer->FactMan, Cp);
1537 bool NoError =
true;
1540 LDat = FSet.findPartialMatch(Analyzer->FactMan, Cp);
1543 std::string PartMatchStr = LDat->toString();
1544 StringRef PartMatchName(PartMatchStr);
1545 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1546 LK, Loc, &PartMatchName);
1549 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1555 if (NoError && LDat && !LDat->isAtLeast(LK)) {
1556 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1562 void BuildLockset::warnIfMutexHeld(
const NamedDecl *D,
const Expr *Exp,
1563 Expr *MutexExp, StringRef DiagKind) {
1564 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1566 warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
1572 FactEntry* LDat = FSet.findLock(Analyzer->FactMan, Cp);
1574 Analyzer->Handler.handleFunExcludesLock(
1592 while (
const auto *DRE = dyn_cast<DeclRefExpr>(Exp)) {
1593 const auto *VD = dyn_cast<
VarDecl>(DRE->getDecl()->getCanonicalDecl());
1594 if (VD && VD->isLocalVarDecl() && VD->getType()->isReferenceType()) {
1595 if (
const auto *E = VD->getInit()) {
1603 if (
const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) {
1605 if (UO->getOpcode() == clang::UO_Deref)
1606 checkPtAccess(UO->getSubExpr(), AK, POK);
1611 checkPtAccess(AE->getLHS(), AK, POK);
1615 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
1617 checkPtAccess(ME->getBase(), AK, POK);
1619 checkAccess(ME->getBase(), AK, POK);
1626 if (D->
hasAttr<GuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan)) {
1627 Analyzer->Handler.handleNoMutexHeld(
"mutex", D, POK, AK, Loc);
1631 warnIfMutexNotHeld(D, Exp, AK,
I->getArg(), POK,
1641 if (
const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
1642 Exp = PE->getSubExpr();
1645 if (
const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
1646 if (CE->getCastKind() == CK_ArrayToPointerDecay) {
1649 checkAccess(CE->getSubExpr(), AK, POK);
1652 Exp = CE->getSubExpr();
1666 if (D->
hasAttr<PtGuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan))
1667 Analyzer->Handler.handleNoMutexHeld(
"mutex", D, PtPOK, AK,
1671 warnIfMutexNotHeld(D, Exp, AK,
I->getArg(), PtPOK,
1687 CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
1688 CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
1689 CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
1690 StringRef CapDiagKind =
"mutex";
1693 bool isScopedVar =
false;
1697 if (PD && PD->
hasAttr<ScopedLockableAttr>())
1702 for(Attr *Atconst : D->
attrs()) {
1703 Attr* At =
const_cast<Attr*
>(Atconst);
1707 case attr::AcquireCapability: {
1708 auto *A = cast<AcquireCapabilityAttr>(At);
1709 Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd
1710 : ExclusiveLocksToAdd,
1720 case attr::AssertExclusiveLock: {
1721 AssertExclusiveLockAttr *A = cast<AssertExclusiveLockAttr>(At);
1723 CapExprSet AssertLocks;
1724 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1725 for (
const auto &AssertLock : AssertLocks)
1726 Analyzer->addLock(FSet,
1727 llvm::make_unique<LockableFactEntry>(
1728 AssertLock, LK_Exclusive, Loc,
false,
true),
1732 case attr::AssertSharedLock: {
1733 AssertSharedLockAttr *A = cast<AssertSharedLockAttr>(At);
1735 CapExprSet AssertLocks;
1736 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1737 for (
const auto &AssertLock : AssertLocks)
1738 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1739 AssertLock,
LK_Shared, Loc,
false,
true),
1746 case attr::ReleaseCapability: {
1747 auto *A = cast<ReleaseCapabilityAttr>(At);
1749 Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, VD);
1750 else if (A->isShared())
1751 Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD);
1753 Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD);
1759 case attr::RequiresCapability: {
1760 RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
1761 for (
auto *Arg : A->args()) {
1767 Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs
1768 : ScopedExclusiveReqs,
1775 case attr::LocksExcluded: {
1776 LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
1777 for (
auto *Arg : A->args())
1789 for (
const auto &M : ExclusiveLocksToAdd)
1790 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1791 M, LK_Exclusive, Loc, isScopedVar),
1793 for (
const auto &M : SharedLocksToAdd)
1794 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1803 CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE,
nullptr);
1805 std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(),
1806 std::back_inserter(ExclusiveLocksToAdd));
1807 std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(),
1808 std::back_inserter(SharedLocksToAdd));
1809 Analyzer->addLock(FSet,
1810 llvm::make_unique<ScopedLockableFactEntry>(
1811 Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),
1817 bool Dtor = isa<CXXDestructorDecl>(D);
1818 for (
const auto &M : ExclusiveLocksToRemove)
1819 Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Exclusive, CapDiagKind);
1820 for (
const auto &M : SharedLocksToRemove)
1821 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Shared, CapDiagKind);
1822 for (
const auto &M : GenericLocksToRemove)
1823 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Generic, CapDiagKind);
1832 case clang::UO_PostDec:
1833 case clang::UO_PostInc:
1834 case clang::UO_PreDec:
1835 case clang::UO_PreInc: {
1852 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
1861 void BuildLockset::VisitCastExpr(
CastExpr *CE) {
1868 void BuildLockset::VisitCallExpr(
CallExpr *Exp) {
1869 bool ExamineArgs =
true;
1870 bool OperatorFun =
false;
1879 if (MD->isConst()) {
1880 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1882 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1886 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1888 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1894 auto OEop = OE->getOperator();
1897 ExamineArgs =
false;
1898 const Expr *Target = OE->getArg(0);
1899 const Expr *Source = OE->getArg(1);
1906 case OO_Subscript: {
1907 const Expr *Obj = OE->getArg(0);
1909 if (!(OEop == OO_Star && OE->getNumArgs() > 1)) {
1917 const Expr *Obj = OE->getArg(0);
1933 if (!FD->hasAttr<NoThreadSafetyAnalysisAttr>()) {
1934 unsigned Fn = FD->getNumParams();
1940 if (isa<CXXMethodDecl>(FD)) {
1951 unsigned n = (Fn < Cn) ? Fn : Cn;
1953 for (; i < n; ++i) {
1979 void BuildLockset::VisitDeclStmt(
DeclStmt *S) {
1981 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
1984 if (
VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
1988 E = EWC->getSubExpr();
1991 NamedDecl *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
1994 handleCall(CE, CtorD, VD);
2016 void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
2017 const FactSet &FSet2,
2022 FactSet FSet1Orig = FSet1;
2025 for (
const auto &Fact : FSet2) {
2026 const FactEntry *LDat1 =
nullptr;
2027 const FactEntry *LDat2 = &FactMan[Fact];
2028 FactSet::iterator Iter1 = FSet1.findLockIter(FactMan, *LDat2);
2029 if (Iter1 != FSet1.end()) LDat1 = &FactMan[*Iter1];
2032 if (LDat1->kind() != LDat2->kind()) {
2034 LDat2->loc(), LDat1->loc());
2040 else if (Modify && LDat1->asserted() && !LDat2->asserted()) {
2045 LDat2->handleRemovalFromIntersection(FSet2, FactMan, JoinLoc, LEK1,
2051 for (
const auto &Fact : FSet1Orig) {
2052 const FactEntry *LDat1 = &FactMan[Fact];
2053 const FactEntry *LDat2 = FSet2.findLock(FactMan, *LDat1);
2056 LDat1->handleRemovalFromIntersection(FSet1Orig, FactMan, JoinLoc, LEK2,
2059 FSet1.removeLock(FactMan, *LDat1);
2074 if (isa<CXXThrowExpr>(S->getStmt()))
2090 if (!walker.
init(AC))
2101 if (D->
hasAttr<NoThreadSafetyAnalysisAttr>())
2108 if (isa<CXXConstructorDecl>(D))
2110 if (isa<CXXDestructorDecl>(D))
2116 CFGBlockInfo::getEmptyBlockInfo(LocalVarMap));
2128 LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
2131 findBlockLocations(CFGraph, SortedGraph, BlockInfo);
2133 CapExprSet ExclusiveLocksAcquired;
2134 CapExprSet SharedLocksAcquired;
2135 CapExprSet LocksReleased;
2142 FactSet &InitialLockset = BlockInfo[FirstBlock->
getBlockID()].EntrySet;
2144 CapExprSet ExclusiveLocksToAdd;
2145 CapExprSet SharedLocksToAdd;
2146 StringRef CapDiagKind =
"mutex";
2149 for (
const auto *Attr : D->
attrs()) {
2150 Loc = Attr->getLocation();
2151 if (
const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
2152 getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
2155 }
else if (
const auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
2158 if (A->args_size() == 0)
2161 getMutexIDs(ExclusiveLocksToAdd, A,
nullptr, D);
2162 getMutexIDs(LocksReleased, A,
nullptr, D);
2164 }
else if (
const auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
2165 if (A->args_size() == 0)
2167 getMutexIDs(A->isShared() ? SharedLocksAcquired
2168 : ExclusiveLocksAcquired,
2171 }
else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) {
2174 }
else if (isa<SharedTrylockFunctionAttr>(Attr)) {
2181 for (
const auto &Mu : ExclusiveLocksToAdd) {
2182 auto Entry = llvm::make_unique<LockableFactEntry>(Mu,
LK_Exclusive, Loc);
2183 Entry->setDeclared(
true);
2184 addLock(InitialLockset, std::move(Entry), CapDiagKind,
true);
2186 for (
const auto &Mu : SharedLocksToAdd) {
2187 auto Entry = llvm::make_unique<LockableFactEntry>(Mu,
LK_Shared, Loc);
2188 Entry->setDeclared(
true);
2189 addLock(InitialLockset, std::move(Entry), CapDiagKind,
true);
2193 for (
const auto *CurrBlock : *SortedGraph) {
2195 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
2198 VisitedBlocks.insert(CurrBlock);
2213 bool LocksetInitialized =
false;
2216 PE = CurrBlock->
pred_end(); PI != PE; ++PI) {
2219 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI))
2222 int PrevBlockID = (*PI)->getBlockID();
2223 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2230 CurrBlockInfo->Reachable =
true;
2236 if (
const Stmt *Terminator = (*PI)->getTerminator()) {
2237 if (isa<ContinueStmt>(Terminator) || isa<BreakStmt>(Terminator)) {
2238 SpecialBlocks.push_back(*PI);
2243 FactSet PrevLockset;
2244 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
2246 if (!LocksetInitialized) {
2247 CurrBlockInfo->EntrySet = PrevLockset;
2248 LocksetInitialized =
true;
2250 intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset,
2251 CurrBlockInfo->EntryLoc,
2257 if (!CurrBlockInfo->Reachable)
2262 for (
const auto *PrevBlock : SpecialBlocks) {
2263 int PrevBlockID = PrevBlock->getBlockID();
2264 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2266 if (!LocksetInitialized) {
2267 CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet;
2268 LocksetInitialized =
true;
2275 const Stmt *Terminator = PrevBlock->getTerminator();
2276 bool IsLoop = Terminator && isa<ContinueStmt>(Terminator);
2278 FactSet PrevLockset;
2279 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet,
2280 PrevBlock, CurrBlock);
2283 intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset,
2284 PrevBlockInfo->ExitLoc,
2291 BuildLockset LocksetBuilder(
this, *CurrBlockInfo);
2295 BE = CurrBlock->
end(); BI != BE; ++BI) {
2296 switch (BI->getKind()) {
2299 LocksetBuilder.Visit(const_cast<Stmt*>(CS.
getStmt()));
2307 if (!DD->hasAttrs())
2314 LocksetBuilder.handleCall(&DRE, DD);
2321 CurrBlockInfo->ExitSet = LocksetBuilder.FSet;
2328 SE = CurrBlock->
succ_end(); SI != SE; ++SI) {
2331 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
2335 CFGBlockInfo *PreLoop = &BlockInfo[FirstLoopBlock->
getBlockID()];
2336 CFGBlockInfo *LoopEnd = &BlockInfo[CurrBlockID];
2337 intersectAndWarn(LoopEnd->ExitSet, PreLoop->EntrySet,
2348 if (!Final->Reachable)
2352 FactSet ExpectedExitSet = Initial->EntrySet;
2358 for (
const auto &Lock : ExclusiveLocksAcquired)
2359 ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
2361 for (
const auto &Lock : SharedLocksAcquired)
2362 ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
2364 for (
const auto &Lock : LocksReleased)
2365 ExpectedExitSet.removeLock(FactMan, Lock);
2368 intersectAndWarn(ExpectedExitSet, Final->ExitSet,
2388 ThreadSafetyAnalyzer Analyzer(Handler, *BSet);
2389 Analyzer.runAnalysis(AC);
2403 llvm_unreachable(
"Unknown AccessKind");
A call to an overloaded operator written using operator syntax.
CastKind getCastKind() const
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Passing a guarded variable by reference.
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
ASTContext & getASTContext() const
const DeclGroupRef getDeclGroup() const
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
succ_iterator succ_begin()
Stmt - This represents one statement.
virtual void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc)
Warn about unlock function calls that do not have a prior matching lock expression.
static StringRef ClassifyDiagnostic(const CapabilityAttr *A)
Defines the SourceManager interface.
ParenExpr - This represents a parethesized expression, e.g.
TypePropertyCache< Private > Cache
bool isCopyConstructor(unsigned &TypeQuals) const
Whether this constructor is a copy constructor (C++ [class.copy]p2, which can be used to copy the cla...
const Expr * getInit() const
Represents a call to a C++ constructor.
LockKind getLockKindFromAccessKind(AccessKind AK)
Helper function that returns a LockKind required for the given level of access.
Represents a C++ constructor within a class.
Exclusive/writer lock of a mutex.
ProtectedOperationKind
This enum distinguishes between different kinds of operations that may need to be protected by locks...
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Expr * IgnoreImplicit() LLVM_READONLY
IgnoreImplicit - Skip past any implicit AST nodes which might surround this expression.
bool equals(const CapabilityExpr &other) const
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
static bool isAssignmentOp(Opcode Opc)
ParmVarDecl - Represents a parameter to a function.
Defines the clang::Expr interface and subclasses for C++ expressions.
const ValueDecl * valueDecl() const
void threadSafetyCleanup(BeforeSet *Cache)
static const ValueDecl * getValueDecl(const Expr *Exp)
Gets the value decl pointer from DeclRefExprs or MemberExprs.
LockKind
This enum distinguishes between different kinds of lock actions.
CFGBlockSide
A side (entry or exit) of a CFG node.
bool isReferenceType() const
AnalysisDeclContext contains the context data for the function or method under analysis.
CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated for automatic object or t...
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
static bool neverReturns(const CFGBlock *B)
virtual void enterFunction(const FunctionDecl *FD)
Called by the analysis when starting analysis of a function.
virtual void handleInvalidLockExp(StringRef Kind, SourceLocation Loc)
Warn about lock expressions which fail to resolve to lockable objects.
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
virtual void printName(raw_ostream &os) const
const VarDecl * getVarDecl() const
Implements a set of CFGBlocks using a BitVector.
ElementList::const_iterator const_iterator
A builtin binary operation expression such as "x + y" or "x <= y".
bool shouldIgnore() const
const NamedDecl * getDecl() const
std::string getNameAsString() const
getNameAsString - Get a human-readable name for the declaration, even if it is one of the special kin...
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
bool isTrivialType(const ASTContext &Context) const
Return true if this is a trivial type per (C++0x [basic.types]p9)
virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, SourceLocation Loc)
Warn when acquiring a lock that the negative capability is not held.
detail::InMemoryDirectory::const_iterator I
const Stmt * getTriggerStmt() const
Shared/reader lock of a mutex.
virtual ~ThreadSafetyHandler()
Passing a pt-guarded variable by reference.
bool init(AnalysisDeclContext &AC)
Handler class for thread safety warnings.
SourceLocation getLocEnd() const LLVM_READONLY
CFGBlock - Represents a single basic block in a source-level CFG.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Dereferencing a variable (e.g. p in *p = 5;)
ValueDecl - Represent the declaration of a variable (in which case it is an lvalue) a function (in wh...
Expr - This represents one expression.
Stmt * getTerminatorCondition(bool StripParens=true)
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
Represents a C++ destructor within a class.
Defines an enumeration for C++ overloaded operators.
void checkBeforeAfter(const ValueDecl *Vd, const FactSet &FSet, ThreadSafetyAnalyzer &Analyzer, SourceLocation Loc, StringRef CapKind)
Return true if any mutexes in FSet are in the acquired_before set of Vd.
AdjacentBlocks::const_iterator const_pred_iterator
void dump() const
Dumps the specified AST fragment and all subtrees to llvm::errs().
Expr * getSubExpr() const
virtual void handleIncorrectUnlockKind(StringRef Kind, Name LockName, LockKind Expected, LockKind Received, SourceLocation Loc)
Warn about an unlock function call that attempts to unlock a lock with the incorrect lock kind...
DeclContext * getParent()
getParent - Returns the containing DeclContext.
unsigned getBlockID() const
AccessKind
This enum distinguishes between different ways to access (read or write) a variable.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
Making a function call (e.g. fool())
std::string toString() const
const PostOrderCFGView * getSortedGraph() const
const til::SExpr * sexpr() const
bool hasNoReturnElement() const
Reading or writing a variable (e.g. x in x = 5;)
BeforeInfo * insertAttrExprs(const ValueDecl *Vd, ThreadSafetyAnalyzer &Analyzer)
Process acquired_before and acquired_after attributes on Vd.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
Represents a call to a member function that may be written either with member call syntax (e...
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Represents a static or instance method of a struct/union/class.
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
const Stmt * getStmt() const
const CFG * getGraph() const
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
static bool getStaticBooleanValue(Expr *E, bool &TCond)
AdjacentBlocks::const_iterator const_succ_iterator
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
attr::Kind getKind() const
pred_iterator pred_begin()
SourceLocation getLocStart() const LLVM_READONLY
BeforeInfo * getBeforeInfoForDecl(const ValueDecl *Vd, ThreadSafetyAnalyzer &Analyzer)
void runThreadSafetyAnalysis(AnalysisDeclContext &AC, ThreadSafetyHandler &Handler, BeforeSet **Bset)
Check a function's CFG for thread-safety violations.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
detail::InMemoryDirectory::const_iterator E
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
std::string toString(const til::SExpr *E)
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
const T * getAs() const
Member-template getAs<specific type>'.
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
virtual void handleExclusiveAndShared(StringRef Kind, Name LockName, SourceLocation Loc1, SourceLocation Loc2)
Warn when a mutex is held exclusively and shared at the same point.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
virtual void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc)
Warn about lock function calls for locks which are already held.
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ struct/union/class.
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
CFGElement - Represents a top-level expression in a basic block.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
virtual void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, SourceLocation LocLocked, SourceLocation LocEndOfScope, LockErrorKind LEK)
Warn about situations where a mutex is sometimes held and sometimes not.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A reference to a declared variable, function, enum, etc.
Base class for AST nodes in the typed intermediate language.
const FunctionDecl * CurrentFunction
virtual void leaveFunction(const FunctionDecl *FD)
Called by the analysis when finishing analysis of a function.
bool matches(const til::SExpr *E1, const til::SExpr *E2)
An l-value expression is a reference to an object with independent storage.
SourceLocation getLocation() const
NamedDecl - This represents a decl with a name.
A boolean literal, per ([C++ lex.bool] Boolean literals).
unsigned getNumBlockIDs() const
getNumBlockIDs - Returns the total number of BlockIDs allocated (which start at 0).
Optional< T > getAs() const
Convert to the specified CFGElement type, returning None if this CFGElement is not of the desired typ...
Attr - This represents one attribute.
bool isPointerType() const
Can be either Shared or Exclusive.