clang: lib/Analysis/Consumed.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringRef.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/ErrorHandling.h"
34#include
35#include
36#include
37#include
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55using namespace clang;
56using namespace consumed;
57
58
60
62
63
64 for (const auto &B : *Block)
65 if (std::optional CS = B.getAs<CFGStmt>())
66 return CS->getStmt()->getBeginLoc();
67
68
69
72
73 return {};
74}
75
77
78
80 return StmtNode->getBeginLoc();
81 } else {
83 BE = Block->rend(); BI != BE; ++BI) {
84 if (std::optional CS = BI->getAs<CFGStmt>())
85 return CS->getStmt()->getBeginLoc();
86 }
87 }
88
89
94 return Loc;
95
96
99
100 return Loc;
101}
102
104 switch (State) {
113 }
114 llvm_unreachable("invalid enum");
115}
116
119 for (const auto &S : CWAttr->callableStates()) {
121
122 switch (S) {
123 case CallableWhenAttr::Unknown:
125 break;
126
127 case CallableWhenAttr::Unconsumed:
129 break;
130
131 case CallableWhenAttr::Consumed:
133 break;
134 }
135
136 if (MappedAttrState == State)
137 return true;
138 }
139
140 return false;
141}
142
145 return false;
146
148 return RD->hasAttr();
149
150 return false;
151}
152
155 return false;
156
158 return RD->hasAttr();
159
160 return false;
161}
162
165 return RD->hasAttr();
166 return false;
167}
168
170 switch (State) {
173 return true;
176 return false;
177 }
178 llvm_unreachable("invalid enum");
179}
180
183}
184
186 return FunDecl->hasAttr();
187}
188
191
192 const ConsumableAttr *CAttr =
194
195 switch (CAttr->getDefaultState()) {
196 case ConsumableAttr::Unknown:
198 case ConsumableAttr::Unconsumed:
200 case ConsumableAttr::Consumed:
202 }
203 llvm_unreachable("invalid enum");
204}
205
208 switch (PTAttr->getParamState()) {
209 case ParamTypestateAttr::Unknown:
211 case ParamTypestateAttr::Unconsumed:
213 case ParamTypestateAttr::Consumed:
215 }
216 llvm_unreachable("invalid_enum");
217}
218
221 switch (RTSAttr->getState()) {
222 case ReturnTypestateAttr::Unknown:
224 case ReturnTypestateAttr::Unconsumed:
226 case ReturnTypestateAttr::Consumed:
228 }
229 llvm_unreachable("invalid enum");
230}
231
233 switch (STAttr->getNewState()) {
234 case SetTypestateAttr::Unknown:
236 case SetTypestateAttr::Unconsumed:
238 case SetTypestateAttr::Consumed:
240 }
241 llvm_unreachable("invalid_enum");
242}
243
245 switch (State) {
247 return "none";
248
250 return "unknown";
251
253 return "unconsumed";
254
256 return "consumed";
257 }
258 llvm_unreachable("invalid enum");
259}
260
263 switch (FunDecl->getAttr()->getTestState()) {
264 case TestTypestateAttr::Unconsumed:
266 case TestTypestateAttr::Consumed:
268 }
269 llvm_unreachable("invalid enum");
270}
271
272namespace {
273
274struct VarTestResult {
277};
278
279}
280
282namespace consumed {
283
288
290 enum {
291 IT_None,
292 IT_State,
293 IT_VarTest,
294 IT_BinTest,
295 IT_Var,
296 IT_Tmp
297 } InfoType = IT_None;
298
299 struct BinTestTy {
302 VarTestResult LTest;
303 VarTestResult RTest;
304 };
305
306 union {
312 };
313
314public:
318
320 : InfoType(IT_VarTest) {
322 VarTest.TestsFor = TestsFor;
323 }
324
326 const VarTestResult <est, const VarTestResult &RTest)
327 : InfoType(IT_BinTest) {
332 }
333
337 : InfoType(IT_BinTest) {
340 BinTest.LTest.Var = LVar;
341 BinTest.LTest.TestsFor = LTestsFor;
342 BinTest.RTest.Var = RVar;
343 BinTest.RTest.TestsFor = RTestsFor;
344 }
345
347 : InfoType(IT_State), State(State) {}
350 : InfoType(IT_Tmp), Tmp(Tmp) {}
351
353 assert(InfoType == IT_State);
355 }
356
358 assert(InfoType == IT_VarTest);
360 }
361
363 assert(InfoType == IT_BinTest);
365 }
366
368 assert(InfoType == IT_BinTest);
370 }
371
373 assert(InfoType == IT_Var);
374 return Var;
375 }
376
378 assert(InfoType == IT_Tmp);
379 return Tmp;
380 }
381
384
387 else if (isTmp())
391 else
393 }
394
396 assert(InfoType == IT_BinTest);
398 }
399
401 assert(InfoType == IT_BinTest);
403 }
404
405 bool isValid() const { return InfoType != IT_None; }
406 bool isState() const { return InfoType == IT_State; }
407 bool isVarTest() const { return InfoType == IT_VarTest; }
408 bool isBinTest() const { return InfoType == IT_BinTest; }
409 bool isVar() const { return InfoType == IT_Var; }
410 bool isTmp() const { return InfoType == IT_Tmp; }
411
413 return InfoType == IT_VarTest || InfoType == IT_BinTest;
414 }
415
417 return InfoType == IT_Var || InfoType == IT_Tmp;
418 }
419
421 assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
422
423 if (InfoType == IT_VarTest) {
426
427 } else if (InfoType == IT_BinTest) {
432 } else {
433 return {};
434 }
435 }
436};
437
438}
439}
440
441static void
444 assert(PInfo.isVar() || PInfo.isTmp());
445
446 if (PInfo.isVar())
448 else
450}
451
453namespace consumed {
454
456 using MapType = llvm::DenseMap<const Stmt *, PropagationInfo>;
457 using PairType= std::pair<const Stmt *, PropagationInfo>;
458 using InfoEntry = MapType::iterator;
459 using ConstInfoEntry = MapType::const_iterator;
460
463 MapType PropagationMap;
464
465 InfoEntry findInfo(const Expr *E) {
466 if (const auto Cleanups = dyn_cast(E))
467 if (!Cleanups->cleanupsHaveSideEffects())
468 E = Cleanups->getSubExpr();
470 }
471
472 ConstInfoEntry findInfo(const Expr *E) const {
473 if (const auto Cleanups = dyn_cast(E))
474 if (!Cleanups->cleanupsHaveSideEffects())
475 E = Cleanups->getSubExpr();
477 }
478
480 PropagationMap.insert(PairType(E->IgnoreParens(), PI));
481 }
482
483 void forwardInfo(const Expr *From, const Expr *To);
488
489public:
495
511
513 : Analyzer(Analyzer), StateMap(StateMap) {}
514
516 ConstInfoEntry Entry = findInfo(StmtNode);
517
518 if (Entry != PropagationMap.end())
519 return Entry->second;
520 else
521 return {};
522 }
523
525 StateMap = NewStateMap;
526 }
527};
528
529}
530}
531
532void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
533 InfoEntry Entry = findInfo(From);
534 if (Entry != PropagationMap.end())
535 insertInfo(To, Entry->second);
536}
537
538
539
540void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
542 InfoEntry Entry = findInfo(From);
543 if (Entry != PropagationMap.end()) {
550 }
551}
552
553
555 InfoEntry Entry = findInfo(From);
556 if (Entry != PropagationMap.end()) {
559 }
561}
562
563
564void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
565 InfoEntry Entry = findInfo(To);
566 if (Entry != PropagationMap.end()) {
570 } else if (NS != CS_None) {
572 }
573}
574
578 assert(!PInfo.isTest());
579
580 const CallableWhenAttr *CWAttr = FunDecl->getAttr();
581 if (!CWAttr)
582 return;
583
584 if (PInfo.isVar()) {
586
588 return;
589
593 } else {
595
597 return;
598
601 }
602}
603
604
605
606
609 unsigned Offset = 0;
610 if (isa(Call) && isa(FunD))
611 Offset = 1;
612
613
614 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
615
617 break;
618
621
622 InfoEntry Entry = findInfo(Call->getArg(Index));
623
624 if (Entry == PropagationMap.end() || Entry->second.isTest())
625 continue;
627
628
629 if (ParamTypestateAttr *PTA = Param->getAttr()) {
632
633 if (ParamState != ExpectedState)
635 Call->getArg(Index)->getExprLoc(),
637 }
638
639 if (!(Entry->second.isVar() || Entry->second.isTmp()))
640 continue;
641
642
643 if (ReturnTypestateAttr *RT = Param->getAttr())
651 }
652
653 if (!ObjArg)
654 return false;
655
656
657 InfoEntry Entry = findInfo(ObjArg);
658 if (Entry != PropagationMap.end()) {
661
662 if (SetTypestateAttr *STA = FunD->getAttr()) {
663 if (PInfo.isVar()) {
665 return true;
666 }
667 else if (PInfo.isTmp()) {
669 return true;
670 }
671 }
673 PropagationMap.insert(PairType(Call,
675 }
676 }
677 return false;
678}
679
680void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
685
688 if (ReturnTypestateAttr *RTA = Fun->getAttr())
690 else
692
694 }
695}
696
699 case BO_LAnd:
700 case BO_LOr : {
701 InfoEntry LEntry = findInfo(BinOp->getLHS()),
702 REntry = findInfo(BinOp->getRHS());
703
704 VarTestResult LTest, RTest;
705
706 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
707 LTest = LEntry->second.getVarTest();
708 } else {
709 LTest.Var = nullptr;
710 LTest.TestsFor = CS_None;
711 }
712
713 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
714 RTest = REntry->second.getVarTest();
715 } else {
716 RTest.Var = nullptr;
717 RTest.TestsFor = CS_None;
718 }
719
720 if (!(LTest.Var == nullptr && RTest.Var == nullptr))
721 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
723 break;
724 }
725
726 case BO_PtrMemD:
727 case BO_PtrMemI:
728 forwardInfo(BinOp->getLHS(), BinOp);
729 break;
730
731 default:
732 break;
733 }
734}
735
738 if (!FunDecl)
739 return;
740
741
742
743 if (Call->isCallToStdMove()) {
745 return;
746 }
747
749 propagateReturnType(Call, FunDecl);
750}
751
753 forwardInfo(Cast->getSubExpr(), Cast);
754}
755
758
759 InfoEntry Entry = findInfo(Temp->getSubExpr());
760
761 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
762 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
763 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
764 }
765}
766
769
770 QualType ThisType = Constructor->getFunctionObjectParameterType();
771
773 return;
774
775
776 if (ReturnTypestateAttr *RTA = Constructor->getAttr()) {
777
780 } else if (Constructor->isDefaultConstructor()) {
781 PropagationMap.insert(PairType(Call,
783 } else if (Constructor->isMoveConstructor()) {
785 } else if (Constructor->isCopyConstructor()) {
786
790 copyInfo(Call->getArg(0), Call, NS);
791 } else {
792
795 }
796}
797
801 if (!MD)
802 return;
803
805 propagateReturnType(Call, MD);
806}
807
810 const auto *FunDecl = dyn_cast_or_null(Call->getDirectCallee());
811 if (!FunDecl) return;
812
813 if (Call->getOperator() == OO_Equal) {
816 setInfo(Call->getArg(0), CS);
817 return;
818 }
819
820 if (const auto *MCall = dyn_cast(Call))
821 handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
822 else
824
825 propagateReturnType(Call, FunDecl);
826}
827
829 if (const auto *Var = dyn_cast_or_null(DeclRef->getDecl()))
831 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
832}
833
835 for (const auto *DI : DeclS->decls())
836 if (isa(DI))
838
840 if (const auto *Var = dyn_cast_or_null(DeclS->getSingleDecl()))
841 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
842}
843
846 forwardInfo(Temp->getSubExpr(), Temp);
847}
848
850 forwardInfo(MExpr->getBase(), MExpr);
851}
852
856
857 if (const ParamTypestateAttr *PTA = Param->getAttr())
867
868 if (ParamState != CS_None)
869 StateMap->setState(Param, ParamState);
870}
871
874
875 if (ExpectedState != CS_None) {
876 InfoEntry Entry = findInfo(Ret->getRetValue());
877
878 if (Entry != PropagationMap.end()) {
879 ConsumedState RetState = Entry->second.getAsState(StateMap);
880
881 if (RetState != ExpectedState)
883 Ret->getReturnLoc(), stateToString(ExpectedState),
885 }
886 }
887
890}
891
893 InfoEntry Entry = findInfo(UOp->getSubExpr());
894 if (Entry == PropagationMap.end()) return;
895
897 case UO_AddrOf:
898 PropagationMap.insert(PairType(UOp, Entry->second));
899 break;
900
901 case UO_LNot:
902 if (Entry->second.isTest())
903 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
904 break;
905
906 default:
907 break;
908 }
909}
910
911
916 if (VIT != PropagationMap.end()) {
919
922 return;
923 }
924 }
925 }
926
928 }
929}
930
935
937 ThenStates->setState(Test.Var, Test.TestsFor);
941 } else if (VarState == Test.TestsFor) {
943 }
944}
945
949 const VarTestResult <est = PInfo.getLTest(),
951
953 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
954
955 if (LTest.Var) {
958 ThenStates->setState(LTest.Var, LTest.TestsFor);
961 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
962 if (RState == RTest.TestsFor)
964 else
966 }
967 } else {
969 ElseStates->setState(LTest.Var,
971 } else if (LState == LTest.TestsFor) {
975 if (RState == RTest.TestsFor)
977 else
979 }
980 }
981 }
982
983 if (RTest.Var) {
986 ThenStates->setState(RTest.Var, RTest.TestsFor);
989 } else {
991 ElseStates->setState(RTest.Var,
993 else if (RState == RTest.TestsFor)
995 }
996 }
997}
998
1000 const CFGBlock *TargetBlock) {
1001 assert(CurrBlock && "Block pointer must not be NULL");
1002 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1003
1004 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1006 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1007 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1008 return false;
1009 }
1010 return true;
1011}
1012
1015 std::unique_ptr &OwnedStateMap) {
1016 assert(Block && "Block pointer must not be NULL");
1017
1018 auto &Entry = StateMapsArray[Block->getBlockID()];
1019
1020 if (Entry) {
1021 Entry->intersect(*StateMap);
1022 } else if (OwnedStateMap)
1023 Entry = std::move(OwnedStateMap);
1024 else
1025 Entry = std::make_unique(*StateMap);
1026}
1027
1029 std::unique_ptr StateMap) {
1030 assert(Block && "Block pointer must not be NULL");
1031
1032 auto &Entry = StateMapsArray[Block->getBlockID()];
1033
1034 if (Entry) {
1035 Entry->intersect(*StateMap);
1036 } else {
1037 Entry = std::move(StateMap);
1038 }
1039}
1040
1042 assert(Block && "Block pointer must not be NULL");
1043 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1044
1045 return StateMapsArray[Block->getBlockID()].get();
1046}
1047
1049 StateMapsArray[Block->getBlockID()] = nullptr;
1050}
1051
1052std::unique_ptr
1054 assert(Block && "Block pointer must not be NULL");
1055
1056 auto &Entry = StateMapsArray[Block->getBlockID()];
1058 : std::move(Entry);
1059}
1060
1062 assert(From && "From block must not be NULL");
1063 assert(To && "From block must not be NULL");
1064
1066}
1067
1069 assert(Block && "Block pointer must not be NULL");
1070
1071
1072
1073 if (Block->pred_size() < 2)
1074 return false;
1075
1076 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1078 PE = Block->pred_end(); PI != PE; ++PI) {
1079 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1080 return true;
1081 }
1082 return false;
1083}
1084
1087
1088 for (const auto &DM : VarMap) {
1089 if (isa(DM.first)) {
1090 const auto *Param = cast(DM.first);
1091 const ReturnTypestateAttr *RTA = Param->getAttr();
1092
1093 if (!RTA)
1094 continue;
1095
1097 if (DM.second != ExpectedState)
1099 Param->getNameAsString(), stateToString(ExpectedState),
1101 }
1102 }
1103}
1104
1107}
1108
1110 VarMapType::const_iterator Entry = VarMap.find(Var);
1111
1112 if (Entry != VarMap.end())
1113 return Entry->second;
1114
1116}
1117
1120 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1121
1122 if (Entry != TmpMap.end())
1123 return Entry->second;
1124
1126}
1127
1130
1131 if (this->From && this->From == Other.From && .Reachable) {
1133 return;
1134 }
1135
1136 for (const auto &DM : Other.VarMap) {
1137 LocalState = this->getState(DM.first);
1138
1139 if (LocalState == CS_None)
1140 continue;
1141
1142 if (LocalState != DM.second)
1144 }
1145}
1146
1150
1153
1154 for (const auto &DM : LoopBackStates->VarMap) {
1155 LocalState = this->getState(DM.first);
1156
1157 if (LocalState == CS_None)
1158 continue;
1159
1160 if (LocalState != DM.second) {
1163 DM.first->getNameAsString());
1164 }
1165 }
1166}
1167
1172}
1173
1175 VarMap[Var] = State;
1176}
1177
1180 TmpMap[Tmp] = State;
1181}
1182
1185}
1186
1188 for (const auto &DM : Other->VarMap)
1189 if (this->getState(DM.first) != DM.second)
1190 return true;
1191 return false;
1192}
1193
1194void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1197 if (const auto *Constructor = dyn_cast(D)) {
1198 ReturnType = Constructor->getFunctionObjectParameterType();
1199 } else
1200 ReturnType = D->getCallResultType();
1201
1202 if (const ReturnTypestateAttr *RTSAttr = D->getAttr()) {
1204 if (!RD || !RD->hasAttr()) {
1205
1206
1207
1208
1210 RTSAttr->getLocation(), ReturnType.getAsString());
1211 ExpectedReturnState = CS_None;
1212 } else
1215 if (isAutoCastType(ReturnType))
1216 ExpectedReturnState = CS_None;
1217 else
1219 }
1220 else
1221 ExpectedReturnState = CS_None;
1222}
1223
1224bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1226 std::unique_ptr FalseStates(
1229
1230 if (const auto *IfNode =
1232 if (IfNode->isConsteval())
1233 return false;
1234
1235 const Expr *Cond = IfNode->getCond();
1236
1237 PInfo = Visitor.getInfo(Cond);
1238 if (!PInfo.isValid() && isa(Cond))
1239 PInfo = Visitor.getInfo(cast(Cond)->getRHS());
1240
1242 CurrStates->setSource(Cond);
1243 FalseStates->setSource(Cond);
1245 FalseStates.get());
1250 } else {
1251 return false;
1252 }
1253 } else if (const auto *BinOp =
1255 PInfo = Visitor.getInfo(BinOp->getLHS());
1257 if ((BinOp = dyn_cast_or_null(BinOp->getLHS()))) {
1258 PInfo = Visitor.getInfo(BinOp->getRHS());
1259
1261 return false;
1262 } else {
1263 return false;
1264 }
1265 }
1266
1267 CurrStates->setSource(BinOp);
1268 FalseStates->setSource(BinOp);
1269
1270 const VarTestResult &Test = PInfo.getVarTest();
1271 ConsumedState VarState = CurrStates->getState(Test.Var);
1272
1273 if (BinOp->getOpcode() == BO_LAnd) {
1275 CurrStates->setState(Test.Var, Test.TestsFor);
1277 CurrStates->markUnreachable();
1278
1279 } else if (BinOp->getOpcode() == BO_LOr) {
1281 FalseStates->setState(Test.Var,
1283 else if (VarState == Test.TestsFor)
1284 FalseStates->markUnreachable();
1285 }
1286 } else {
1287 return false;
1288 }
1289
1291
1292 if (*SI)
1293 BlockInfo.addInfo(*SI, std::move(CurrStates));
1294 else
1295 CurrStates = nullptr;
1296
1297 if (*++SI)
1298 BlockInfo.addInfo(*SI, std::move(FalseStates));
1299
1300 return true;
1301}
1302
1304 const auto *D = dyn_cast_or_null(AC.getDecl());
1305 if ()
1306 return;
1307
1308 CFG *CFGraph = AC.getCFG();
1309 if (!CFGraph)
1310 return;
1311
1312 determineExpectedReturnState(AC, D);
1313
1315
1316
1318
1319 CurrStates = std::make_unique();
1321
1322
1323 for (const auto *PI : D->parameters())
1325
1326
1327 for (const auto *CurrBlock : *SortedGraph) {
1328 if (!CurrStates)
1329 CurrStates = BlockInfo.getInfo(CurrBlock);
1330
1331 if (!CurrStates) {
1332 continue;
1333 } else if (!CurrStates->isReachable()) {
1334 CurrStates = nullptr;
1335 continue;
1336 }
1337
1338 Visitor.reset(CurrStates.get());
1339
1340
1341 for (const auto &B : *CurrBlock) {
1342 switch (B.getKind()) {
1345 break;
1346
1350
1353 BTE->getExprLoc());
1354 CurrStates->remove(BTE);
1355 break;
1356 }
1357
1362
1366 break;
1367 }
1368
1369 default:
1370 break;
1371 }
1372 }
1373
1374
1375
1376 if (!splitState(CurrBlock, Visitor)) {
1377 CurrStates->setSource(nullptr);
1378
1379 if (CurrBlock->succ_size() > 1 ||
1380 (CurrBlock->succ_size() == 1 &&
1381 (*CurrBlock->succ_begin())->pred_size() > 1)) {
1382
1383 auto *RawState = CurrStates.get();
1384
1386 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1387 if (*SI == nullptr) continue;
1388
1389 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1390 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
1392
1393 if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
1394 BlockInfo.discardInfo(*SI);
1395 } else {
1396 BlockInfo.addInfo(*SI, RawState, CurrStates);
1397 }
1398 }
1399
1400 CurrStates = nullptr;
1401 }
1402 }
1403
1404 if (CurrBlock == &AC.getCFG()->getExit() &&
1405 D->getCallResultType()->isVoidType())
1406 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1408 }
1409
1410
1411 CurrStates = nullptr;
1412
1414}
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static void splitVarStateForIfBinOp(const PropagationInfo &PInfo, ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates)
static ConsumedState invertConsumedUnconsumed(ConsumedState State)
static bool isCallableInState(const CallableWhenAttr *CWAttr, ConsumedState State)
static ConsumedState mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr)
static bool isRValueRef(QualType ParamType)
static ConsumedState mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr)
static ConsumedState testsFor(const FunctionDecl *FunDecl)
static bool isConsumableType(const QualType &QT)
static StringRef stateToString(ConsumedState State)
static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test, ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates)
static bool isTestingFunction(const FunctionDecl *FunDecl)
static bool isAutoCastType(const QualType &QT)
static SourceLocation getFirstStmtLoc(const CFGBlock *Block)
static void setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo, ConsumedState State)
static ConsumedState mapConsumableAttrState(const QualType QT)
static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr)
static SourceLocation getLastStmtLoc(const CFGBlock *Block)
static bool isSetOnReadPtrType(const QualType &QT)
static bool isKnownState(ConsumedState State)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines an enumeration for C++ overloaded operators.
Defines the clang::SourceLocation class and associated facilities.
C Language Family Type Representation.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
A builtin binary operation expression such as "x + y" or "x <= y".
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
const VarDecl * getVarDecl() const
const Stmt * getTriggerStmt() const
Represents a single basic block in a source-level CFG.
reverse_iterator rbegin()
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
AdjacentBlocks::const_iterator const_pred_iterator
unsigned pred_size() const
pred_iterator pred_begin()
unsigned getBlockID() const
AdjacentBlocks::const_iterator const_succ_iterator
unsigned succ_size() const
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
const Stmt * getStmt() const
Represents C++ object destructor implicitly generated at the end of full expression for temporary obj...
const CXXBindTemporaryExpr * getBindTemporaryExpr() const
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents binding an expression to a temporary.
const Expr * getSubExpr() const
Represents a call to a C++ constructor.
Represents a C++ constructor within a class.
Represents a call to a member function that may be written either with member call syntax (e....
Represents a static or instance method of a struct/union/class.
A call to an overloaded operator written using operator syntax.
Represents a C++ struct/union/class.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
SourceLocation getLocation() const
This represents one expression.
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
QualType getCallResultType() const
Determine the type of an expression that calls this function.
IfStmt - This represents an if/then/else.
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Represents a parameter to a function.
A (possibly-)qualified type.
bool isConstQualified() const
Determine whether this type is const-qualified.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Stmt - This represents one statement.
SourceLocation getEndLoc() const LLVM_READONLY
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isRValueReferenceType() const
bool isReferenceType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isPointerOrReferenceType() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
Represents a variable declaration or definition.
const Expr * getInit() const
A class that handles the analysis of uniqueness violations.
ConsumedWarningsHandlerBase & WarningsHandler
ConsumedState getExpectedReturnState() const
void run(AnalysisDeclContext &AC)
Check a function's CFG for consumed violations.
ConsumedStateMap * borrowInfo(const CFGBlock *Block)
bool isBackEdgeTarget(const CFGBlock *Block)
std::unique_ptr< ConsumedStateMap > getInfo(const CFGBlock *Block)
void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, std::unique_ptr< ConsumedStateMap > &OwnedStateMap)
void discardInfo(const CFGBlock *Block)
bool allBackEdgesVisited(const CFGBlock *CurrBlock, const CFGBlock *TargetBlock)
bool isBackEdge(const CFGBlock *From, const CFGBlock *To)
void clearTemporaries()
Clear the TmpMap.
void checkParamsForReturnTypestate(SourceLocation BlameLoc, ConsumedWarningsHandlerBase &WarningsHandler) const
Warn if any of the parameters being tracked are not in the state they were declared to be in upon ret...
void intersect(const ConsumedStateMap &Other)
Merge this state map with another map.
ConsumedState getState(const VarDecl *Var) const
Get the consumed state of a given variable.
void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, ConsumedWarningsHandlerBase &WarningsHandler)
void remove(const CXXBindTemporaryExpr *Tmp)
Remove the temporary value from our state map.
void markUnreachable()
Mark the block as unreachable.
bool operator!=(const ConsumedStateMap *Other) const
Tests to see if there is a mismatch in the states stored in two maps.
void setState(const VarDecl *Var, ConsumedState State)
Set the consumed state of a given variable.
void VisitUnaryOperator(const UnaryOperator *UOp)
PropagationInfo getInfo(const Expr *StmtNode) const
void VisitVarDecl(const VarDecl *Var)
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call)
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp)
void VisitMemberExpr(const MemberExpr *MExpr)
void reset(ConsumedStateMap *NewStateMap)
void VisitReturnStmt(const ReturnStmt *Ret)
void VisitDeclStmt(const DeclStmt *DelcS)
void checkCallability(const PropagationInfo &PInfo, const FunctionDecl *FunDecl, SourceLocation BlameLoc)
void VisitCallExpr(const CallExpr *Call)
void VisitDeclRefExpr(const DeclRefExpr *DeclRef)
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp)
bool handleCall(const CallExpr *Call, const Expr *ObjArg, const FunctionDecl *FunD)
ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap *StateMap)
void VisitCXXConstructExpr(const CXXConstructExpr *Call)
void VisitBinaryOperator(const BinaryOperator *BinOp)
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call)
void VisitCastExpr(const CastExpr *Cast)
void VisitParmVarDecl(const ParmVarDecl *Param)
virtual void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, SourceLocation Loc)
Warn about use-while-consumed errors.
virtual void warnParamTypestateMismatch(SourceLocation LOC, StringRef ExpectedState, StringRef ObservedState)
virtual void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName)
Warn that a variable's state doesn't match at the entry and exit of a loop.
virtual void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, StringRef State, SourceLocation Loc)
Warn about use-while-consumed errors.
virtual void emitDiagnostics()
Emit the warnings and notes left by the analysis.
virtual void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, StringRef ObservedState)
Warn about return typestate mismatches.
virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, StringRef TypeName)
Warn about return typestates set for unconsumable types.
virtual ~ConsumedWarningsHandlerBase()
virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, StringRef VariableName, StringRef ExpectedState, StringRef ObservedState)
Warn about parameter typestate mismatches upon return.
const VarTestResult & getRTest() const
PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, const VarTestResult <est, const VarTestResult &RTest)
const CXXBindTemporaryExpr * Tmp
PropagationInfo(const VarTestResult &VarTest)
EffectiveOp testEffectiveOp() const
PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, const VarDecl *LVar, ConsumedState LTestsFor, const VarDecl *RVar, ConsumedState RTestsFor)
const ConsumedState & getState() const
const VarTestResult & getVarTest() const
const VarDecl * getVar() const
PropagationInfo(ConsumedState State)
PropagationInfo(const VarDecl *Var)
PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
PropagationInfo(const CXXBindTemporaryExpr *Tmp)
const VarTestResult & getLTest() const
bool isPointerToValue() const
PropagationInfo()=default
const CXXBindTemporaryExpr * getTmp() const
PropagationInfo invertTest() const
ConsumedState getAsState(const ConsumedStateMap *StateMap) const
const BinaryOperator * testSourceNode() const
The JSON file list parser is used to communicate input to InstallAPI.
@ Other
Other implicit parameter.