35 #include "llvm/ADT/BitVector.h"
36 #include "llvm/ADT/FoldingSet.h"
37 #include "llvm/ADT/ImmutableMap.h"
38 #include "llvm/ADT/PostOrderIterator.h"
39 #include "llvm/ADT/SmallVector.h"
40 #include "llvm/ADT/StringRef.h"
41 #include "llvm/Support/raw_ostream.h"
47 using namespace clang;
48 using namespace threadSafety;
61 const Expr *DeclExp, StringRef
Kind) {
73 class CapExprSet :
public SmallVector<CapabilityExpr, 4> {
77 iterator It = std::find_if(begin(), end(),
106 bool Asrt,
bool Declrd =
false)
110 virtual ~FactEntry() {}
114 bool asserted()
const {
return Asserted; }
115 bool declared()
const {
return Declared; }
117 void setDeclared(
bool D) { Declared = D; }
120 handleRemovalFromIntersection(
const FactSet &FSet, FactManager &FactMan,
123 virtual void handleUnlock(FactSet &FSet, FactManager &FactMan,
126 StringRef DiagKind)
const = 0;
135 typedef unsigned short FactID;
141 std::vector<std::unique_ptr<FactEntry>> Facts;
144 FactID newFact(std::unique_ptr<FactEntry> Entry) {
145 Facts.push_back(std::move(Entry));
146 return static_cast<unsigned short>(Facts.size() - 1);
149 const FactEntry &operator[](FactID F)
const {
return *Facts[F]; }
150 FactEntry &operator[](FactID F) {
return *Facts[F]; }
168 typedef FactVec::iterator iterator;
169 typedef FactVec::const_iterator const_iterator;
171 iterator begin() {
return FactIDs.begin(); }
172 const_iterator begin()
const {
return FactIDs.begin(); }
174 iterator end() {
return FactIDs.end(); }
175 const_iterator end()
const {
return FactIDs.end(); }
177 bool isEmpty()
const {
return FactIDs.size() == 0; }
180 bool isEmpty(FactManager &FactMan)
const {
181 for (FactID FID : *
this) {
182 if (!FactMan[FID].negative())
188 void addLockByID(FactID
ID) { FactIDs.push_back(ID); }
190 FactID addLock(FactManager &FM, std::unique_ptr<FactEntry> Entry) {
191 FactID F = FM.newFact(std::move(Entry));
192 FactIDs.push_back(F);
197 unsigned n = FactIDs.size();
201 for (
unsigned i = 0; i < n-1; ++i) {
202 if (FM[FactIDs[i]].
matches(CapE)) {
203 FactIDs[i] = FactIDs[n-1];
208 if (FM[FactIDs[n-1]].
matches(CapE)) {
215 iterator findLockIter(FactManager &FM,
const CapabilityExpr &CapE) {
216 return std::find_if(begin(), end(), [&](FactID ID) {
217 return FM[
ID].matches(CapE);
221 FactEntry *findLock(FactManager &FM,
const CapabilityExpr &CapE)
const {
222 auto I = std::find_if(begin(), end(), [&](FactID ID) {
223 return FM[
ID].matches(CapE);
225 return I != end() ? &FM[*I] :
nullptr;
228 FactEntry *findLockUniv(FactManager &FM,
const CapabilityExpr &CapE)
const {
229 auto I = std::find_if(begin(), end(), [&](FactID ID) ->
bool {
230 return FM[
ID].matchesUniv(CapE);
232 return I != end() ? &FM[*I] :
nullptr;
235 FactEntry *findPartialMatch(FactManager &FM,
237 auto I = std::find_if(begin(), end(), [&](FactID ID) ->
bool {
238 return FM[
ID].partiallyMatches(CapE);
240 return I != end() ? &FM[*I] :
nullptr;
243 bool containsMutexDecl(FactManager &FM,
const ValueDecl* Vd)
const {
244 auto I = std::find_if(begin(), end(), [&](FactID ID) ->
bool {
245 return FM[
ID].valueDecl() == Vd;
251 class ThreadSafetyAnalyzer;
255 namespace threadSafety {
261 BeforeInfo() : Vect(
nullptr), Visited(
false) { }
262 BeforeInfo(BeforeInfo &&O)
263 : Vect(std::move(O.Vect)), Visited(O.Visited)
266 std::unique_ptr<BeforeVect> Vect;
270 typedef llvm::DenseMap<const ValueDecl*, BeforeInfo> BeforeMap;
271 typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap;
276 BeforeInfo* insertAttrExprs(
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.isInvalid()) {
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 auto& Entry = BMap.FindAndConstruct(Vd);
969 BeforeInfo* Info = &Entry.second;
973 switch (At->getKind()) {
974 case attr::AcquiredBefore: {
975 auto *A = cast<AcquiredBeforeAttr>(At);
980 Info->Vect.reset(Bv);
983 for (
const auto *Arg : A->args()) {
985 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
988 auto It = BMap.find(Cpvd);
989 if (It == BMap.end())
995 case attr::AcquiredAfter: {
996 auto *A = cast<AcquiredAfterAttr>(At);
999 for (
const auto *Arg : A->args()) {
1001 Analyzer.SxBuilder.translateAttrExpr(Arg,
nullptr);
1004 BeforeInfo* ArgInfo;
1005 auto It = BMap.find(ArgVd);
1006 if (It == BMap.end())
1009 ArgInfo = &It->second;
1015 ArgInfo->Vect.reset(ArgBv);
1017 ArgBv->push_back(Vd);
1033 const FactSet& FSet,
1034 ThreadSafetyAnalyzer& Analyzer,
1040 std::function<bool (const ValueDecl*)> traverse = [&](
const ValueDecl* Vd) {
1044 BeforeSet::BeforeInfo* Info;
1045 auto It = BMap.find(Vd);
1046 if (It == BMap.end())
1051 if (Info->Visited == 1)
1054 if (Info->Visited == 2)
1061 InfoVect.push_back(Info);
1063 for (
auto *Vdb : *Bv) {
1065 if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
1066 StringRef L1 = StartVd->
getName();
1067 StringRef L2 = Vdb->getName();
1068 Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc);
1071 if (traverse(Vdb)) {
1072 if (CycMap.find(Vd) == CycMap.end()) {
1073 CycMap.insert(std::make_pair(Vd,
true));
1075 Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->
getLocation());
1085 for (
auto* Info : InfoVect)
1093 if (
const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
1096 if (
const auto *DR = dyn_cast<DeclRefExpr>(Exp))
1097 return DR->getDecl();
1099 if (
const auto *ME = dyn_cast<MemberExpr>(Exp))
1100 return ME->getMemberDecl();
1106 template <
typename Ty>
1107 class has_arg_iterator_range {
1108 typedef char yes[1];
1111 template <
typename Inner>
1112 static yes& test(Inner *I, decltype(I->args()) * =
nullptr);
1115 static no& test(...);
1118 static const bool value =
sizeof(test<Ty>(
nullptr)) ==
sizeof(yes);
1123 return A->getName();
1131 if (
const auto *RD = RT->getDecl())
1132 if (
const auto *CA = RD->getAttr<CapabilityAttr>())
1135 if (
const auto *TD = TT->getDecl())
1136 if (
const auto *CA = TD->getAttr<CapabilityAttr>())
1145 assert(VD &&
"No ValueDecl passed");
1151 template <
typename AttrTy>
1152 static typename std::enable_if<!has_arg_iterator_range<AttrTy>::value,
1160 template <
typename AttrTy>
1161 static typename std::enable_if<has_arg_iterator_range<AttrTy>::value,
1164 for (
const auto *Arg : A->args()) {
1172 inline bool ThreadSafetyAnalyzer::inCurrentScope(
const CapabilityExpr &CapE) {
1175 if (
auto *P = dyn_cast_or_null<til::Project>(CapE.
sexpr())) {
1176 auto *VD = P->clangDecl();
1178 return VD->getDeclContext() == CurrentMethod->getDeclContext();
1186 void ThreadSafetyAnalyzer::addLock(FactSet &FSet,
1187 std::unique_ptr<FactEntry> Entry,
1188 StringRef DiagKind,
bool ReqAttr) {
1189 if (Entry->shouldIgnore())
1192 if (!ReqAttr && !Entry->negative()) {
1195 FactEntry *Nen = FSet.findLock(FactMan, NegC);
1197 FSet.removeLock(FactMan, NegC);
1200 if (inCurrentScope(*Entry) && !Entry->asserted())
1208 !Entry->asserted() && !Entry->declared()) {
1209 GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *
this,
1210 Entry->loc(), DiagKind);
1214 if (FSet.findLock(FactMan, *Entry)) {
1215 if (!Entry->asserted())
1218 FSet.addLock(FactMan, std::move(Entry));
1225 void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const CapabilityExpr &Cp,
1227 bool FullyRemove,
LockKind ReceivedKind,
1228 StringRef DiagKind) {
1232 const FactEntry *LDat = FSet.findLock(FactMan, Cp);
1240 if (ReceivedKind !=
LK_Generic && LDat->kind() != ReceivedKind) {
1242 LDat->kind(), ReceivedKind, UnlockLoc);
1245 LDat->handleUnlock(FSet, FactMan, Cp, UnlockLoc, FullyRemove, Handler,
1252 template <
typename AttrType>
1253 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *
Attr,
1256 if (Attr->args_size() == 0) {
1258 CapabilityExpr Cp = SxBuilder.translateAttrExpr(
nullptr, D, Exp, SelfDecl);
1265 Mtxs.push_back_nodup(Cp);
1269 for (
const auto *Arg : Attr->args()) {
1270 CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, SelfDecl);
1277 Mtxs.push_back_nodup(Cp);
1285 template <
class AttrType>
1286 void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
1290 Expr *BrE,
bool Neg) {
1292 bool branch =
false;
1294 branch = BLE->getValue();
1295 else if (
IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE))
1296 branch = ILE->getValue().getBoolValue();
1298 int branchnum = branch ? 0 : 1;
1300 branchnum = !branchnum;
1305 SE = PredBlock->
succ_end(); SI != SE && i < 2; ++SI, ++i) {
1306 if (*SI == CurrBlock && i == branchnum)
1307 getMutexIDs(Mtxs, Attr, Exp, D);
1312 if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) {
1316 TCond = BLE->getValue();
1319 TCond = ILE->getValue().getBoolValue();
1331 const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(
const Stmt *Cond,
1337 if (
const CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
1340 else if (
const ParenExpr *PE = dyn_cast<ParenExpr>(Cond)) {
1341 return getTrylockCallExpr(PE->getSubExpr(),
C, Negate);
1344 return getTrylockCallExpr(CE->getSubExpr(),
C, Negate);
1347 return getTrylockCallExpr(EWC->getSubExpr(),
C, Negate);
1349 else if (
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
1350 const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(),
C);
1351 return getTrylockCallExpr(E, C, Negate);
1353 else if (
const UnaryOperator *UOP = dyn_cast<UnaryOperator>(Cond)) {
1354 if (UOP->getOpcode() ==
UO_LNot) {
1356 return getTrylockCallExpr(UOP->getSubExpr(),
C, Negate);
1360 else if (
const BinaryOperator *BOP = dyn_cast<BinaryOperator>(Cond)) {
1361 if (BOP->getOpcode() ==
BO_EQ || BOP->getOpcode() ==
BO_NE) {
1362 if (BOP->getOpcode() ==
BO_NE)
1367 if (!TCond) Negate = !Negate;
1368 return getTrylockCallExpr(BOP->getLHS(),
C, Negate);
1372 if (!TCond) Negate = !Negate;
1373 return getTrylockCallExpr(BOP->getRHS(),
C, Negate);
1377 if (BOP->getOpcode() ==
BO_LAnd) {
1379 return getTrylockCallExpr(BOP->getRHS(),
C, Negate);
1381 if (BOP->getOpcode() ==
BO_LOr) {
1382 return getTrylockCallExpr(BOP->getRHS(),
C, Negate);
1393 void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
1394 const FactSet &ExitSet,
1403 bool Negate =
false;
1404 const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->
getBlockID()];
1405 const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext;
1406 StringRef CapDiagKind =
"mutex";
1409 const_cast<CallExpr*
>(getTrylockCallExpr(Cond, LVarCtx, Negate));
1414 if(!FunDecl || !FunDecl->
hasAttrs())
1417 CapExprSet ExclusiveLocksToAdd;
1418 CapExprSet SharedLocksToAdd;
1421 for (
auto *Attr : FunDecl->
attrs()) {
1422 switch (Attr->getKind()) {
1423 case attr::ExclusiveTrylockFunction: {
1424 ExclusiveTrylockFunctionAttr *A =
1425 cast<ExclusiveTrylockFunctionAttr>(Attr);
1426 getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
1427 PredBlock, CurrBlock, A->getSuccessValue(), Negate);
1431 case attr::SharedTrylockFunction: {
1432 SharedTrylockFunctionAttr *A =
1433 cast<SharedTrylockFunctionAttr>(Attr);
1434 getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
1435 PredBlock, CurrBlock, A->getSuccessValue(), Negate);
1446 for (
const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
1447 addLock(Result, llvm::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
1450 for (
const auto &SharedLockToAdd : SharedLocksToAdd)
1451 addLock(Result, llvm::make_unique<LockableFactEntry>(SharedLockToAdd,
1462 class BuildLockset :
public StmtVisitor<BuildLockset> {
1463 friend class ThreadSafetyAnalyzer;
1465 ThreadSafetyAnalyzer *Analyzer;
1467 LocalVariableMap::Context LVarCtx;
1475 StringRef DiagKind);
1485 BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
1488 FSet(Info.EntrySet),
1489 LVarCtx(Info.EntryContext),
1490 CtxIndex(Info.EntryIndex)
1504 void BuildLockset::warnIfMutexNotHeld(
const NamedDecl *D,
const Expr *Exp,
1510 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1512 warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
1520 FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
1522 Analyzer->Handler.handleFunExcludesLock(
1529 if (!Analyzer->inCurrentScope(Cp))
1533 LDat = FSet.findLock(Analyzer->FactMan, Cp);
1535 Analyzer->Handler.handleMutexNotHeld(
"", D, POK, Cp.
toString(),
1541 FactEntry* LDat = FSet.findLockUniv(Analyzer->FactMan, Cp);
1542 bool NoError =
true;
1545 LDat = FSet.findPartialMatch(Analyzer->FactMan, Cp);
1548 std::string PartMatchStr = LDat->toString();
1549 StringRef PartMatchName(PartMatchStr);
1550 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1551 LK, Loc, &PartMatchName);
1554 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1560 if (NoError && LDat && !LDat->isAtLeast(LK)) {
1561 Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Cp.
toString(),
1567 void BuildLockset::warnIfMutexHeld(
const NamedDecl *D,
const Expr *Exp,
1568 Expr *MutexExp, StringRef DiagKind) {
1569 CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
1571 warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, DiagKind);
1577 FactEntry* LDat = FSet.findLock(Analyzer->FactMan, Cp);
1579 Analyzer->Handler.handleFunExcludesLock(
1597 while (
const auto *DRE = dyn_cast<DeclRefExpr>(Exp)) {
1598 const auto *VD = dyn_cast<
VarDecl>(DRE->getDecl()->getCanonicalDecl());
1599 if (VD && VD->isLocalVarDecl() && VD->getType()->isReferenceType()) {
1600 if (
const auto *E = VD->getInit()) {
1608 if (
const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) {
1611 checkPtAccess(UO->getSubExpr(), AK, POK);
1616 checkPtAccess(AE->getLHS(), AK, POK);
1620 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
1622 checkPtAccess(ME->getBase(), AK, POK);
1624 checkAccess(ME->getBase(), AK, POK);
1631 if (D->
hasAttr<GuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan)) {
1632 Analyzer->Handler.handleNoMutexHeld(
"mutex", D, POK, AK, Loc);
1636 warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK,
1646 if (
const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
1647 Exp = PE->getSubExpr();
1650 if (
const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
1654 checkAccess(CE->getSubExpr(), AK, POK);
1657 Exp = CE->getSubExpr();
1671 if (D->
hasAttr<PtGuardedVarAttr>() && FSet.isEmpty(Analyzer->FactMan))
1672 Analyzer->Handler.handleNoMutexHeld(
"mutex", D, PtPOK, AK,
1676 warnIfMutexNotHeld(D, Exp, AK, I->getArg(), PtPOK,
1692 CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
1693 CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
1694 CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
1695 StringRef CapDiagKind =
"mutex";
1698 bool isScopedVar =
false;
1702 if (PD && PD->
hasAttr<ScopedLockableAttr>())
1707 for(Attr *Atconst : D->
attrs()) {
1708 Attr* At =
const_cast<Attr*
>(Atconst);
1712 case attr::AcquireCapability: {
1713 auto *A = cast<AcquireCapabilityAttr>(At);
1714 Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd
1715 : ExclusiveLocksToAdd,
1725 case attr::AssertExclusiveLock: {
1726 AssertExclusiveLockAttr *A = cast<AssertExclusiveLockAttr>(At);
1728 CapExprSet AssertLocks;
1729 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1730 for (
const auto &AssertLock : AssertLocks)
1731 Analyzer->addLock(FSet,
1732 llvm::make_unique<LockableFactEntry>(
1733 AssertLock, LK_Exclusive, Loc,
false,
true),
1737 case attr::AssertSharedLock: {
1738 AssertSharedLockAttr *A = cast<AssertSharedLockAttr>(At);
1740 CapExprSet AssertLocks;
1741 Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
1742 for (
const auto &AssertLock : AssertLocks)
1743 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1744 AssertLock,
LK_Shared, Loc,
false,
true),
1751 case attr::ReleaseCapability: {
1752 auto *A = cast<ReleaseCapabilityAttr>(At);
1754 Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, VD);
1755 else if (A->isShared())
1756 Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD);
1758 Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD);
1764 case attr::RequiresCapability: {
1765 RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
1766 for (
auto *Arg : A->args()) {
1772 Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs
1773 : ScopedExclusiveReqs,
1780 case attr::LocksExcluded: {
1781 LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
1782 for (
auto *Arg : A->args())
1794 for (
const auto &M : ExclusiveLocksToAdd)
1795 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1796 M, LK_Exclusive, Loc, isScopedVar),
1798 for (
const auto &M : SharedLocksToAdd)
1799 Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
1808 CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE,
nullptr);
1810 std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(),
1811 std::back_inserter(ExclusiveLocksToAdd));
1812 std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(),
1813 std::back_inserter(SharedLocksToAdd));
1814 Analyzer->addLock(FSet,
1815 llvm::make_unique<ScopedLockableFactEntry>(
1816 Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),
1822 bool Dtor = isa<CXXDestructorDecl>(D);
1823 for (
const auto &M : ExclusiveLocksToRemove)
1824 Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Exclusive, CapDiagKind);
1825 for (
const auto &M : SharedLocksToRemove)
1826 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Shared, CapDiagKind);
1827 for (
const auto &M : GenericLocksToRemove)
1828 Analyzer->removeLock(FSet, M, Loc, Dtor,
LK_Generic, CapDiagKind);
1857 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
1866 void BuildLockset::VisitCastExpr(
CastExpr *CE) {
1873 void BuildLockset::VisitCallExpr(
CallExpr *Exp) {
1874 bool ExamineArgs =
true;
1875 bool OperatorFun =
false;
1884 if (MD->isConst()) {
1885 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1887 checkPtAccess(CE->getImplicitObjectArgument(),
AK_Read);
1891 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1893 checkAccess(CE->getImplicitObjectArgument(),
AK_Read);
1899 auto OEop = OE->getOperator();
1902 ExamineArgs =
false;
1903 const Expr *Target = OE->getArg(0);
1904 const Expr *Source = OE->getArg(1);
1911 case OO_Subscript: {
1912 const Expr *Obj = OE->getArg(0);
1914 if (!(OEop == OO_Star && OE->getNumArgs() > 1)) {
1922 const Expr *Obj = OE->getArg(0);
1932 unsigned Fn = FD->getNumParams();
1938 if (isa<CXXMethodDecl>(FD)) {
1949 unsigned n = (Fn < Cn) ? Fn : Cn;
1951 for (; i < n; ++i) {
1976 void BuildLockset::VisitDeclStmt(
DeclStmt *S) {
1978 LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
1981 if (
VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
1985 E = EWC->getSubExpr();
1988 NamedDecl *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
1991 handleCall(CE, CtorD, VD);
2013 void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
2014 const FactSet &FSet2,
2019 FactSet FSet1Orig = FSet1;
2022 for (
const auto &Fact : FSet2) {
2023 const FactEntry *LDat1 =
nullptr;
2024 const FactEntry *LDat2 = &FactMan[Fact];
2025 FactSet::iterator Iter1 = FSet1.findLockIter(FactMan, *LDat2);
2026 if (Iter1 != FSet1.end()) LDat1 = &FactMan[*Iter1];
2029 if (LDat1->kind() != LDat2->kind()) {
2031 LDat2->loc(), LDat1->loc());
2037 else if (Modify && LDat1->asserted() && !LDat2->asserted()) {
2042 LDat2->handleRemovalFromIntersection(FSet2, FactMan, JoinLoc, LEK1,
2048 for (
const auto &Fact : FSet1Orig) {
2049 const FactEntry *LDat1 = &FactMan[Fact];
2050 const FactEntry *LDat2 = FSet2.findLock(FactMan, *LDat1);
2053 LDat1->handleRemovalFromIntersection(FSet1Orig, FactMan, JoinLoc, LEK2,
2056 FSet1.removeLock(FactMan, *LDat1);
2071 if (isa<CXXThrowExpr>(S->getStmt()))
2087 if (!walker.
init(AC))
2098 if (D->
hasAttr<NoThreadSafetyAnalysisAttr>())
2105 if (isa<CXXConstructorDecl>(D))
2107 if (isa<CXXDestructorDecl>(D))
2113 CFGBlockInfo::getEmptyBlockInfo(LocalVarMap));
2125 LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
2128 findBlockLocations(CFGraph, SortedGraph, BlockInfo);
2130 CapExprSet ExclusiveLocksAcquired;
2131 CapExprSet SharedLocksAcquired;
2132 CapExprSet LocksReleased;
2139 FactSet &InitialLockset = BlockInfo[FirstBlock->
getBlockID()].EntrySet;
2141 CapExprSet ExclusiveLocksToAdd;
2142 CapExprSet SharedLocksToAdd;
2143 StringRef CapDiagKind =
"mutex";
2146 for (
const auto *Attr : D->
attrs()) {
2147 Loc = Attr->getLocation();
2148 if (
const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
2149 getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
2152 }
else if (
const auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
2155 if (A->args_size() == 0)
2158 getMutexIDs(ExclusiveLocksToAdd, A,
nullptr, D);
2159 getMutexIDs(LocksReleased, A,
nullptr, D);
2161 }
else if (
const auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
2162 if (A->args_size() == 0)
2164 getMutexIDs(A->isShared() ? SharedLocksAcquired
2165 : ExclusiveLocksAcquired,
2168 }
else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) {
2171 }
else if (isa<SharedTrylockFunctionAttr>(Attr)) {
2178 for (
const auto &Mu : ExclusiveLocksToAdd) {
2179 auto Entry = llvm::make_unique<LockableFactEntry>(Mu,
LK_Exclusive, Loc);
2180 Entry->setDeclared(
true);
2181 addLock(InitialLockset, std::move(Entry), CapDiagKind,
true);
2183 for (
const auto &Mu : SharedLocksToAdd) {
2184 auto Entry = llvm::make_unique<LockableFactEntry>(Mu,
LK_Shared, Loc);
2185 Entry->setDeclared(
true);
2186 addLock(InitialLockset, std::move(Entry), CapDiagKind,
true);
2190 for (
const auto *CurrBlock : *SortedGraph) {
2192 CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
2195 VisitedBlocks.insert(CurrBlock);
2210 bool LocksetInitialized =
false;
2213 PE = CurrBlock->
pred_end(); PI != PE; ++PI) {
2216 if (*PI ==
nullptr || !VisitedBlocks.alreadySet(*PI))
2219 int PrevBlockID = (*PI)->getBlockID();
2220 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2227 CurrBlockInfo->Reachable =
true;
2233 if (
const Stmt *Terminator = (*PI)->getTerminator()) {
2234 if (isa<ContinueStmt>(Terminator) || isa<BreakStmt>(Terminator)) {
2235 SpecialBlocks.push_back(*PI);
2240 FactSet PrevLockset;
2241 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
2243 if (!LocksetInitialized) {
2244 CurrBlockInfo->EntrySet = PrevLockset;
2245 LocksetInitialized =
true;
2247 intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset,
2248 CurrBlockInfo->EntryLoc,
2254 if (!CurrBlockInfo->Reachable)
2259 for (
const auto *PrevBlock : SpecialBlocks) {
2260 int PrevBlockID = PrevBlock->getBlockID();
2261 CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
2263 if (!LocksetInitialized) {
2264 CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet;
2265 LocksetInitialized =
true;
2272 const Stmt *Terminator = PrevBlock->getTerminator();
2273 bool IsLoop = Terminator && isa<ContinueStmt>(Terminator);
2275 FactSet PrevLockset;
2276 getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet,
2277 PrevBlock, CurrBlock);
2280 intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset,
2281 PrevBlockInfo->ExitLoc,
2288 BuildLockset LocksetBuilder(
this, *CurrBlockInfo);
2292 BE = CurrBlock->
end(); BI != BE; ++BI) {
2293 switch (BI->getKind()) {
2296 LocksetBuilder.Visit(const_cast<Stmt*>(CS.
getStmt()));
2304 if (!DD->hasAttrs())
2311 LocksetBuilder.handleCall(&DRE, DD);
2318 CurrBlockInfo->ExitSet = LocksetBuilder.FSet;
2325 SE = CurrBlock->
succ_end(); SI != SE; ++SI) {
2328 if (*SI ==
nullptr || !VisitedBlocks.alreadySet(*SI))
2332 CFGBlockInfo *PreLoop = &BlockInfo[FirstLoopBlock->
getBlockID()];
2333 CFGBlockInfo *LoopEnd = &BlockInfo[CurrBlockID];
2334 intersectAndWarn(LoopEnd->ExitSet, PreLoop->EntrySet,
2345 if (!Final->Reachable)
2349 FactSet ExpectedExitSet = Initial->EntrySet;
2355 for (
const auto &Lock : ExclusiveLocksAcquired)
2356 ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
2358 for (
const auto &Lock : SharedLocksAcquired)
2359 ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
2361 for (
const auto &Lock : LocksReleased)
2362 ExpectedExitSet.removeLock(FactMan, Lock);
2365 intersectAndWarn(ExpectedExitSet, Final->ExitSet,
2385 ThreadSafetyAnalyzer Analyzer(Handler, *BSet);
2386 Analyzer.runAnalysis(AC);
2400 llvm_unreachable(
"Unknown AccessKind");
A call to an overloaded operator written using operator syntax.
CastKind getCastKind() const
Passing a guarded variable by reference.
StringRef getName() const
ASTContext & getASTContext() const
const DeclGroupRef getDeclGroup() const
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
succ_iterator succ_begin()
virtual void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc)
static StringRef ClassifyDiagnostic(const CapabilityAttr *A)
Defines the SourceManager interface.
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.
bool isTrivialType(ASTContext &Context) const
bool equals(const CapabilityExpr &other) const
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.
CFGBlockSide
A side (entry or exit) of a CFG node.
bool isReferenceType() const
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)
virtual void handleInvalidLockExp(StringRef Kind, SourceLocation Loc)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
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
Expr * IgnoreParenCasts() LLVM_READONLY
virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, SourceLocation Loc)
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.
ID
Defines the set of possible language-specific address spaces.
QualType getPointeeType() const
Dereferencing a variable (e.g. p in *p = 5;)
Stmt * getTerminatorCondition(bool StripParens=true)
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
Expr * getSubExpr() const
virtual void handleIncorrectUnlockKind(StringRef Kind, Name LockName, LockKind Expected, LockKind Received, SourceLocation Loc)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
unsigned getBlockID() const
Making a function call (e.g. fool())
std::string toString() const
const PostOrderCFGView * getSortedGraph() const
The result type of a method or function.
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. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
void printName(raw_ostream &os) const
Represents a static or instance method of a struct/union/class.
const Stmt * getStmt() const
const CFG * getGraph() const
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
static bool getStaticBooleanValue(Expr *E, bool &TCond)
AdjacentBlocks::const_iterator const_succ_iterator
SourceLocation getExprLoc() const LLVM_READONLY
attr::Kind getKind() const
pred_iterator pred_begin()
SourceLocation getLocStart() const LLVM_READONLY
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.
unsigned getNumArgs() const
QualType getNonReferenceType() const
std::string toString(const til::SExpr *E)
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
virtual void handleExclusiveAndShared(StringRef Kind, Name LockName, SourceLocation Loc1, SourceLocation Loc2)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
virtual void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc)
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)
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
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
A boolean literal, per ([C++ lex.bool] Boolean literals).
unsigned getNumBlockIDs() const
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.