clang 22.0.0git
Consumed.cpp
Go to the documentation of this file.
1//===- Consumed.cpp -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// A intra-procedural analysis for checking consumed properties. This is based,
10// in part, on research on linear types.
11//
12//===----------------------------------------------------------------------===//
13
15#include "clang/AST/Attr.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/Stmt.h"
22#include "clang/AST/Type.h"
25#include "clang/Analysis/CFG.h"
26#include "clang/Basic/LLVM.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/Support/ErrorHandling.h"
31#include <cassert>
32#include <memory>
33#include <optional>
34#include <utility>
35
36// TODO: Adjust states of args to constructors in the same way that arguments to
37// function calls are handled.
38// TODO: Use information from tests in for- and while-loop conditional.
39// TODO: Add notes about the actual and expected state for
40// TODO: Correctly identify unreachable blocks when chaining boolean operators.
41// TODO: Adjust the parser and AttributesList class to support lists of
42// identifiers.
43// TODO: Warn about unreachable code.
44// TODO: Switch to using a bitmap to track unreachable blocks.
45// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
46// if (valid) ...; (Deferred)
47// TODO: Take notes on state transitions to provide better warning messages.
48// (Deferred)
49// TODO: Test nested conditionals: A) Checking the same value multiple times,
50// and 2) Checking different values. (Deferred)
51
52using namespace clang;
53using namespace consumed;
54
55// Key method definition
57
59 // Find the source location of the first statement in the block, if the block
60 // is not empty.
61 for (const auto &B : *Block)
62 if (std::optional<CFGStmt> CS = B.getAs<CFGStmt>())
63 return CS->getStmt()->getBeginLoc();
64
65 // Block is empty.
66 // If we have one successor, return the first statement in that block
67 if (Block->succ_size() == 1 && *Block->succ_begin())
69
70 return {};
71}
72
74 // Find the source location of the last statement in the block, if the block
75 // is not empty.
76 if (const Stmt *StmtNode = Block->getTerminatorStmt()) {
77 return StmtNode->getBeginLoc();
78 } else {
80 BE = Block->rend(); BI != BE; ++BI) {
81 if (std::optional<CFGStmt> CS = BI->getAs<CFGStmt>())
82 return CS->getStmt()->getBeginLoc();
83 }
84 }
85
86 // If we have one successor, return the first statement in that block
88 if (Block->succ_size() == 1 && *Block->succ_begin())
90 if (Loc.isValid())
91 return Loc;
92
93 // If we have one predecessor, return the last statement in that block
94 if (Block->pred_size() == 1 && *Block->pred_begin())
96
97 return Loc;
98}
99
101 switch (State) {
102 case CS_Unconsumed:
103 return CS_Consumed;
104 case CS_Consumed:
105 return CS_Unconsumed;
106 case CS_None:
107 return CS_None;
108 case CS_Unknown:
109 return CS_Unknown;
110 }
111 llvm_unreachable("invalid enum");
112}
113
114static bool isCallableInState(const CallableWhenAttr *CWAttr,
115 ConsumedState State) {
116 for (const auto &S : CWAttr->callableStates()) {
117 ConsumedState MappedAttrState = CS_None;
118
119 switch (S) {
120 case CallableWhenAttr::Unknown:
121 MappedAttrState = CS_Unknown;
122 break;
123
124 case CallableWhenAttr::Unconsumed:
125 MappedAttrState = CS_Unconsumed;
126 break;
127
128 case CallableWhenAttr::Consumed:
129 MappedAttrState = CS_Consumed;
130 break;
131 }
132
133 if (MappedAttrState == State)
134 return true;
135 }
136
137 return false;
138}
139
140static bool isConsumableType(const QualType &QT) {
141 if (QT->isPointerOrReferenceType())
142 return false;
143
144 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
145 return RD->hasAttr<ConsumableAttr>();
146
147 return false;
148}
149
150static bool isAutoCastType(const QualType &QT) {
151 if (QT->isPointerOrReferenceType())
152 return false;
153
154 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
155 return RD->hasAttr<ConsumableAutoCastAttr>();
156
157 return false;
158}
159
160static bool isSetOnReadPtrType(const QualType &QT) {
161 if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
162 return RD->hasAttr<ConsumableSetOnReadAttr>();
163 return false;
164}
165
166static bool isKnownState(ConsumedState State) {
167 switch (State) {
168 case CS_Unconsumed:
169 case CS_Consumed:
170 return true;
171 case CS_None:
172 case CS_Unknown:
173 return false;
174 }
175 llvm_unreachable("invalid enum");
176}
177
178static bool isRValueRef(QualType ParamType) {
179 return ParamType->isRValueReferenceType();
180}
181
182static bool isTestingFunction(const FunctionDecl *FunDecl) {
183 return FunDecl->hasAttr<TestTypestateAttr>();
184}
185
187 assert(isConsumableType(QT));
188
189 const ConsumableAttr *CAttr =
190 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
191
192 switch (CAttr->getDefaultState()) {
193 case ConsumableAttr::Unknown:
194 return CS_Unknown;
195 case ConsumableAttr::Unconsumed:
196 return CS_Unconsumed;
197 case ConsumableAttr::Consumed:
198 return CS_Consumed;
199 }
200 llvm_unreachable("invalid enum");
201}
202
203static ConsumedState
204mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
205 switch (PTAttr->getParamState()) {
206 case ParamTypestateAttr::Unknown:
207 return CS_Unknown;
208 case ParamTypestateAttr::Unconsumed:
209 return CS_Unconsumed;
210 case ParamTypestateAttr::Consumed:
211 return CS_Consumed;
212 }
213 llvm_unreachable("invalid_enum");
214}
215
216static ConsumedState
217mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
218 switch (RTSAttr->getState()) {
219 case ReturnTypestateAttr::Unknown:
220 return CS_Unknown;
221 case ReturnTypestateAttr::Unconsumed:
222 return CS_Unconsumed;
223 case ReturnTypestateAttr::Consumed:
224 return CS_Consumed;
225 }
226 llvm_unreachable("invalid enum");
227}
228
229static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
230 switch (STAttr->getNewState()) {
231 case SetTypestateAttr::Unknown:
232 return CS_Unknown;
233 case SetTypestateAttr::Unconsumed:
234 return CS_Unconsumed;
235 case SetTypestateAttr::Consumed:
236 return CS_Consumed;
237 }
238 llvm_unreachable("invalid_enum");
239}
240
241static StringRef stateToString(ConsumedState State) {
242 switch (State) {
244 return "none";
245
247 return "unknown";
248
250 return "unconsumed";
251
253 return "consumed";
254 }
255 llvm_unreachable("invalid enum");
256}
257
258static ConsumedState testsFor(const FunctionDecl *FunDecl) {
259 assert(isTestingFunction(FunDecl));
260 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
261 case TestTypestateAttr::Unconsumed:
262 return CS_Unconsumed;
263 case TestTypestateAttr::Consumed:
264 return CS_Consumed;
265 }
266 llvm_unreachable("invalid enum");
267}
268
269namespace {
270
271struct VarTestResult {
272 const VarDecl *Var;
273 ConsumedState TestsFor;
274};
275
276} // namespace
277
278namespace clang {
279namespace consumed {
280
283 EO_Or
285
287 enum {
288 IT_None,
289 IT_State,
290 IT_VarTest,
291 IT_BinTest,
292 IT_Var,
293 IT_Tmp
294 } InfoType = IT_None;
295
296 struct BinTestTy {
297 const BinaryOperator *Source;
298 EffectiveOp EOp;
299 VarTestResult LTest;
300 VarTestResult RTest;
301 };
302
303 union {
305 VarTestResult VarTest;
306 const VarDecl *Var;
308 BinTestTy BinTest;
309 };
310
311public:
312 PropagationInfo() = default;
313 PropagationInfo(const VarTestResult &VarTest)
314 : InfoType(IT_VarTest), VarTest(VarTest) {}
315
317 : InfoType(IT_VarTest) {
318 VarTest.Var = Var;
319 VarTest.TestsFor = TestsFor;
320 }
321
323 const VarTestResult &LTest, const VarTestResult &RTest)
324 : InfoType(IT_BinTest) {
325 BinTest.Source = Source;
326 BinTest.EOp = EOp;
327 BinTest.LTest = LTest;
328 BinTest.RTest = RTest;
329 }
330
332 const VarDecl *LVar, ConsumedState LTestsFor,
333 const VarDecl *RVar, ConsumedState RTestsFor)
334 : InfoType(IT_BinTest) {
335 BinTest.Source = Source;
336 BinTest.EOp = EOp;
337 BinTest.LTest.Var = LVar;
338 BinTest.LTest.TestsFor = LTestsFor;
339 BinTest.RTest.Var = RVar;
340 BinTest.RTest.TestsFor = RTestsFor;
341 }
342
344 : InfoType(IT_State), State(State) {}
345 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
347 : InfoType(IT_Tmp), Tmp(Tmp) {}
348
349 const ConsumedState &getState() const {
350 assert(InfoType == IT_State);
351 return State;
352 }
353
354 const VarTestResult &getVarTest() const {
355 assert(InfoType == IT_VarTest);
356 return VarTest;
357 }
358
359 const VarTestResult &getLTest() const {
360 assert(InfoType == IT_BinTest);
361 return BinTest.LTest;
362 }
363
364 const VarTestResult &getRTest() const {
365 assert(InfoType == IT_BinTest);
366 return BinTest.RTest;
367 }
368
369 const VarDecl *getVar() const {
370 assert(InfoType == IT_Var);
371 return Var;
372 }
373
375 assert(InfoType == IT_Tmp);
376 return Tmp;
377 }
378
380 assert(isVar() || isTmp() || isState());
381
382 if (isVar())
383 return StateMap->getState(Var);
384 else if (isTmp())
385 return StateMap->getState(Tmp);
386 else if (isState())
387 return State;
388 else
389 return CS_None;
390 }
391
393 assert(InfoType == IT_BinTest);
394 return BinTest.EOp;
395 }
396
398 assert(InfoType == IT_BinTest);
399 return BinTest.Source;
400 }
401
402 bool isValid() const { return InfoType != IT_None; }
403 bool isState() const { return InfoType == IT_State; }
404 bool isVarTest() const { return InfoType == IT_VarTest; }
405 bool isBinTest() const { return InfoType == IT_BinTest; }
406 bool isVar() const { return InfoType == IT_Var; }
407 bool isTmp() const { return InfoType == IT_Tmp; }
408
409 bool isTest() const {
410 return InfoType == IT_VarTest || InfoType == IT_BinTest;
411 }
412
413 bool isPointerToValue() const {
414 return InfoType == IT_Var || InfoType == IT_Tmp;
415 }
416
418 assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
419
420 if (InfoType == IT_VarTest) {
421 return PropagationInfo(VarTest.Var,
423
424 } else if (InfoType == IT_BinTest) {
425 return PropagationInfo(BinTest.Source,
426 BinTest.EOp == EO_And ? EO_Or : EO_And,
427 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
428 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
429 } else {
430 return {};
431 }
432 }
433};
434
435} // namespace consumed
436} // namespace clang
437
438static void
440 ConsumedState State) {
441 assert(PInfo.isVar() || PInfo.isTmp());
442
443 if (PInfo.isVar())
444 StateMap->setState(PInfo.getVar(), State);
445 else
446 StateMap->setState(PInfo.getTmp(), State);
447}
448
449namespace clang {
450namespace consumed {
451
452class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
453 using MapType = llvm::DenseMap<const Stmt *, PropagationInfo>;
454 using PairType= std::pair<const Stmt *, PropagationInfo>;
455 using InfoEntry = MapType::iterator;
456 using ConstInfoEntry = MapType::const_iterator;
457
458 ConsumedAnalyzer &Analyzer;
459 ConsumedStateMap *StateMap;
460 MapType PropagationMap;
461
462 InfoEntry findInfo(const Expr *E) {
463 if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
464 if (!Cleanups->cleanupsHaveSideEffects())
465 E = Cleanups->getSubExpr();
466 return PropagationMap.find(E->IgnoreParens());
467 }
468
469 ConstInfoEntry findInfo(const Expr *E) const {
470 if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
471 if (!Cleanups->cleanupsHaveSideEffects())
472 E = Cleanups->getSubExpr();
473 return PropagationMap.find(E->IgnoreParens());
474 }
475
476 void insertInfo(const Expr *E, const PropagationInfo &PI) {
477 PropagationMap.insert(PairType(E->IgnoreParens(), PI));
478 }
479
480 void forwardInfo(const Expr *From, const Expr *To);
481 void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
482 ConsumedState getInfo(const Expr *From);
483 void setInfo(const Expr *To, ConsumedState NS);
484 void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
485
486public:
487 void checkCallability(const PropagationInfo &PInfo,
488 const FunctionDecl *FunDecl,
489 SourceLocation BlameLoc);
490 bool handleCall(const CallExpr *Call, const Expr *ObjArg,
491 const FunctionDecl *FunD);
492
493 void VisitBinaryOperator(const BinaryOperator *BinOp);
494 void VisitCallExpr(const CallExpr *Call);
495 void VisitCastExpr(const CastExpr *Cast);
500 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
501 void VisitDeclStmt(const DeclStmt *DelcS);
503 void VisitMemberExpr(const MemberExpr *MExpr);
504 void VisitParmVarDecl(const ParmVarDecl *Param);
505 void VisitReturnStmt(const ReturnStmt *Ret);
506 void VisitUnaryOperator(const UnaryOperator *UOp);
507 void VisitVarDecl(const VarDecl *Var);
508
510 : Analyzer(Analyzer), StateMap(StateMap) {}
511
512 PropagationInfo getInfo(const Expr *StmtNode) const {
513 ConstInfoEntry Entry = findInfo(StmtNode);
514
515 if (Entry != PropagationMap.end())
516 return Entry->second;
517 else
518 return {};
519 }
520
521 void reset(ConsumedStateMap *NewStateMap) {
522 StateMap = NewStateMap;
523 }
524};
525
526} // namespace consumed
527} // namespace clang
528
529void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
530 InfoEntry Entry = findInfo(From);
531 if (Entry != PropagationMap.end())
532 insertInfo(To, Entry->second);
533}
534
535// Create a new state for To, which is initialized to the state of From.
536// If NS is not CS_None, sets the state of From to NS.
537void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
538 ConsumedState NS) {
539 InfoEntry Entry = findInfo(From);
540 if (Entry != PropagationMap.end()) {
541 PropagationInfo& PInfo = Entry->second;
542 ConsumedState CS = PInfo.getAsState(StateMap);
543 if (CS != CS_None)
544 insertInfo(To, PropagationInfo(CS));
545 if (NS != CS_None && PInfo.isPointerToValue())
546 setStateForVarOrTmp(StateMap, PInfo, NS);
547 }
548}
549
550// Get the ConsumedState for From
551ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
552 InfoEntry Entry = findInfo(From);
553 if (Entry != PropagationMap.end()) {
554 PropagationInfo& PInfo = Entry->second;
555 return PInfo.getAsState(StateMap);
556 }
557 return CS_None;
558}
559
560// If we already have info for To then update it, otherwise create a new entry.
561void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
562 InfoEntry Entry = findInfo(To);
563 if (Entry != PropagationMap.end()) {
564 PropagationInfo& PInfo = Entry->second;
565 if (PInfo.isPointerToValue())
566 setStateForVarOrTmp(StateMap, PInfo, NS);
567 } else if (NS != CS_None) {
568 insertInfo(To, PropagationInfo(NS));
569 }
570}
571
573 const FunctionDecl *FunDecl,
574 SourceLocation BlameLoc) {
575 assert(!PInfo.isTest());
576
577 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
578 if (!CWAttr)
579 return;
580
581 if (PInfo.isVar()) {
582 ConsumedState VarState = StateMap->getState(PInfo.getVar());
583
584 if (VarState == CS_None || isCallableInState(CWAttr, VarState))
585 return;
586
588 FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
589 stateToString(VarState), BlameLoc);
590 } else {
591 ConsumedState TmpState = PInfo.getAsState(StateMap);
592
593 if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
594 return;
595
597 FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
598 }
599}
600
601// Factors out common behavior for function, method, and operator calls.
602// Check parameters and set parameter state if necessary.
603// Returns true if the state of ObjArg is set, or false otherwise.
605 const FunctionDecl *FunD) {
606 unsigned Offset = 0;
607 if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
608 Offset = 1; // first argument is 'this'
609
610 // check explicit parameters
611 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
612 // Skip variable argument lists.
613 if (Index - Offset >= FunD->getNumParams())
614 break;
615
616 const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
617 QualType ParamType = Param->getType();
618
619 InfoEntry Entry = findInfo(Call->getArg(Index));
620
621 if (Entry == PropagationMap.end() || Entry->second.isTest())
622 continue;
623 PropagationInfo PInfo = Entry->second;
624
625 // Check that the parameter is in the correct state.
626 if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
627 ConsumedState ParamState = PInfo.getAsState(StateMap);
628 ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
629
630 if (ParamState != ExpectedState)
632 Call->getArg(Index)->getExprLoc(),
633 stateToString(ExpectedState), stateToString(ParamState));
634 }
635
636 if (!(Entry->second.isVar() || Entry->second.isTmp()))
637 continue;
638
639 // Adjust state on the caller side.
640 if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
642 else if (isRValueRef(ParamType) || isConsumableType(ParamType))
644 else if (ParamType->isPointerOrReferenceType() &&
645 (!ParamType->getPointeeType().isConstQualified() ||
646 isSetOnReadPtrType(ParamType)))
648 }
649
650 if (!ObjArg)
651 return false;
652
653 // check implicit 'self' parameter, if present
654 InfoEntry Entry = findInfo(ObjArg);
655 if (Entry != PropagationMap.end()) {
656 PropagationInfo PInfo = Entry->second;
657 checkCallability(PInfo, FunD, Call->getExprLoc());
658
659 if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
660 if (PInfo.isVar()) {
661 StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
662 return true;
663 }
664 else if (PInfo.isTmp()) {
665 StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
666 return true;
667 }
668 }
669 else if (isTestingFunction(FunD) && PInfo.isVar()) {
670 PropagationMap.insert(PairType(Call,
671 PropagationInfo(PInfo.getVar(), testsFor(FunD))));
672 }
673 }
674 return false;
675}
676
677void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
678 const FunctionDecl *Fun) {
679 QualType RetType = Fun->getCallResultType();
680 if (RetType->isReferenceType())
681 RetType = RetType->getPointeeType();
682
683 if (isConsumableType(RetType)) {
684 ConsumedState ReturnState;
685 if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
686 ReturnState = mapReturnTypestateAttrState(RTA);
687 else
688 ReturnState = mapConsumableAttrState(RetType);
689
690 PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
691 }
692}
693
695 switch (BinOp->getOpcode()) {
696 case BO_LAnd:
697 case BO_LOr : {
698 InfoEntry LEntry = findInfo(BinOp->getLHS()),
699 REntry = findInfo(BinOp->getRHS());
700
701 VarTestResult LTest, RTest;
702
703 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
704 LTest = LEntry->second.getVarTest();
705 } else {
706 LTest.Var = nullptr;
707 LTest.TestsFor = CS_None;
708 }
709
710 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
711 RTest = REntry->second.getVarTest();
712 } else {
713 RTest.Var = nullptr;
714 RTest.TestsFor = CS_None;
715 }
716
717 if (!(LTest.Var == nullptr && RTest.Var == nullptr))
718 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
719 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
720 break;
721 }
722
723 case BO_PtrMemD:
724 case BO_PtrMemI:
725 forwardInfo(BinOp->getLHS(), BinOp);
726 break;
727
728 default:
729 break;
730 }
731}
732
734 const FunctionDecl *FunDecl = Call->getDirectCallee();
735 if (!FunDecl)
736 return;
737
738 // Special case for the std::move function.
739 // TODO: Make this more specific. (Deferred)
740 if (Call->isCallToStdMove()) {
741 copyInfo(Call->getArg(0), Call, CS_Consumed);
742 return;
743 }
744
745 handleCall(Call, nullptr, FunDecl);
746 propagateReturnType(Call, FunDecl);
747}
748
750 forwardInfo(Cast->getSubExpr(), Cast);
751}
752
754 const CXXBindTemporaryExpr *Temp) {
755
756 InfoEntry Entry = findInfo(Temp->getSubExpr());
757
758 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
759 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
760 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
761 }
762}
763
765 CXXConstructorDecl *Constructor = Call->getConstructor();
766
767 QualType ThisType = Constructor->getFunctionObjectParameterType();
768
769 if (!isConsumableType(ThisType))
770 return;
771
772 // FIXME: What should happen if someone annotates the move constructor?
773 if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
774 // TODO: Adjust state of args appropriately.
776 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
777 } else if (Constructor->isDefaultConstructor()) {
778 PropagationMap.insert(PairType(Call,
780 } else if (Constructor->isMoveConstructor()) {
781 copyInfo(Call->getArg(0), Call, CS_Consumed);
782 } else if (Constructor->isCopyConstructor()) {
783 // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
784 ConsumedState NS =
785 isSetOnReadPtrType(Constructor->getThisType()) ?
787 copyInfo(Call->getArg(0), Call, NS);
788 } else {
789 // TODO: Adjust state of args appropriately.
790 ConsumedState RetState = mapConsumableAttrState(ThisType);
791 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
792 }
793}
794
796 const CXXMemberCallExpr *Call) {
797 CXXMethodDecl* MD = Call->getMethodDecl();
798 if (!MD)
799 return;
800
801 handleCall(Call, Call->getImplicitObjectArgument(), MD);
802 propagateReturnType(Call, MD);
803}
804
806 const CXXOperatorCallExpr *Call) {
807 const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
808 if (!FunDecl) return;
809
810 if (Call->getOperator() == OO_Equal) {
811 ConsumedState CS = getInfo(Call->getArg(1));
812 if (!handleCall(Call, Call->getArg(0), FunDecl))
813 setInfo(Call->getArg(0), CS);
814 return;
815 }
816
817 if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
818 handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
819 else
820 handleCall(Call, Call->getArg(0), FunDecl);
821
822 propagateReturnType(Call, FunDecl);
823}
824
826 if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
827 if (StateMap->getState(Var) != consumed::CS_None)
828 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
829}
830
832 for (const auto *DI : DeclS->decls())
833 if (isa<VarDecl>(DI))
834 VisitVarDecl(cast<VarDecl>(DI));
835
836 if (DeclS->isSingleDecl())
837 if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
838 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
839}
840
842 const MaterializeTemporaryExpr *Temp) {
843 forwardInfo(Temp->getSubExpr(), Temp);
844}
845
847 forwardInfo(MExpr->getBase(), MExpr);
848}
849
851 QualType ParamType = Param->getType();
852 ConsumedState ParamState = consumed::CS_None;
853
854 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
855 ParamState = mapParamTypestateAttrState(PTA);
856 else if (isConsumableType(ParamType))
857 ParamState = mapConsumableAttrState(ParamType);
858 else if (isRValueRef(ParamType) &&
859 isConsumableType(ParamType->getPointeeType()))
860 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
861 else if (ParamType->isReferenceType() &&
862 isConsumableType(ParamType->getPointeeType()))
863 ParamState = consumed::CS_Unknown;
864
865 if (ParamState != CS_None)
866 StateMap->setState(Param, ParamState);
867}
868
870 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
871
872 if (ExpectedState != CS_None) {
873 InfoEntry Entry = findInfo(Ret->getRetValue());
874
875 if (Entry != PropagationMap.end()) {
876 ConsumedState RetState = Entry->second.getAsState(StateMap);
877
878 if (RetState != ExpectedState)
880 Ret->getReturnLoc(), stateToString(ExpectedState),
881 stateToString(RetState));
882 }
883 }
884
885 StateMap->checkParamsForReturnTypestate(Ret->getBeginLoc(),
886 Analyzer.WarningsHandler);
887}
888
890 InfoEntry Entry = findInfo(UOp->getSubExpr());
891 if (Entry == PropagationMap.end()) return;
892
893 switch (UOp->getOpcode()) {
894 case UO_AddrOf:
895 PropagationMap.insert(PairType(UOp, Entry->second));
896 break;
897
898 case UO_LNot:
899 if (Entry->second.isTest())
900 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
901 break;
902
903 default:
904 break;
905 }
906}
907
908// TODO: See if I need to check for reference types here.
910 if (isConsumableType(Var->getType())) {
911 if (Var->hasInit()) {
912 MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
913 if (VIT != PropagationMap.end()) {
914 PropagationInfo PInfo = VIT->second;
915 ConsumedState St = PInfo.getAsState(StateMap);
916
917 if (St != consumed::CS_None) {
918 StateMap->setState(Var, St);
919 return;
920 }
921 }
922 }
923 // Otherwise
924 StateMap->setState(Var, consumed::CS_Unknown);
925 }
926}
927
928static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
929 ConsumedStateMap *ThenStates,
930 ConsumedStateMap *ElseStates) {
931 ConsumedState VarState = ThenStates->getState(Test.Var);
932
933 if (VarState == CS_Unknown) {
934 ThenStates->setState(Test.Var, Test.TestsFor);
935 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
936 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
937 ThenStates->markUnreachable();
938 } else if (VarState == Test.TestsFor) {
939 ElseStates->markUnreachable();
940 }
941}
942
944 ConsumedStateMap *ThenStates,
945 ConsumedStateMap *ElseStates) {
946 const VarTestResult &LTest = PInfo.getLTest(),
947 &RTest = PInfo.getRTest();
948
949 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
950 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
951
952 if (LTest.Var) {
953 if (PInfo.testEffectiveOp() == EO_And) {
954 if (LState == CS_Unknown) {
955 ThenStates->setState(LTest.Var, LTest.TestsFor);
956 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
957 ThenStates->markUnreachable();
958 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
959 if (RState == RTest.TestsFor)
960 ElseStates->markUnreachable();
961 else
962 ThenStates->markUnreachable();
963 }
964 } else {
965 if (LState == CS_Unknown) {
966 ElseStates->setState(LTest.Var,
967 invertConsumedUnconsumed(LTest.TestsFor));
968 } else if (LState == LTest.TestsFor) {
969 ElseStates->markUnreachable();
970 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
971 isKnownState(RState)) {
972 if (RState == RTest.TestsFor)
973 ElseStates->markUnreachable();
974 else
975 ThenStates->markUnreachable();
976 }
977 }
978 }
979
980 if (RTest.Var) {
981 if (PInfo.testEffectiveOp() == EO_And) {
982 if (RState == CS_Unknown)
983 ThenStates->setState(RTest.Var, RTest.TestsFor);
984 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
985 ThenStates->markUnreachable();
986 } else {
987 if (RState == CS_Unknown)
988 ElseStates->setState(RTest.Var,
989 invertConsumedUnconsumed(RTest.TestsFor));
990 else if (RState == RTest.TestsFor)
991 ElseStates->markUnreachable();
992 }
993 }
994}
995
997 const CFGBlock *TargetBlock) {
998 assert(CurrBlock && "Block pointer must not be NULL");
999 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1000
1001 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1002 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1003 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1004 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1005 return false;
1006 }
1007 return true;
1008}
1009
1011 const CFGBlock *Block, ConsumedStateMap *StateMap,
1012 std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
1013 assert(Block && "Block pointer must not be NULL");
1014
1015 auto &Entry = StateMapsArray[Block->getBlockID()];
1016
1017 if (Entry) {
1018 Entry->intersect(*StateMap);
1019 } else if (OwnedStateMap)
1020 Entry = std::move(OwnedStateMap);
1021 else
1022 Entry = std::make_unique<ConsumedStateMap>(*StateMap);
1023}
1024
1026 std::unique_ptr<ConsumedStateMap> StateMap) {
1027 assert(Block && "Block pointer must not be NULL");
1028
1029 auto &Entry = StateMapsArray[Block->getBlockID()];
1030
1031 if (Entry) {
1032 Entry->intersect(*StateMap);
1033 } else {
1034 Entry = std::move(StateMap);
1035 }
1036}
1037
1039 assert(Block && "Block pointer must not be NULL");
1040 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1041
1042 return StateMapsArray[Block->getBlockID()].get();
1043}
1044
1046 StateMapsArray[Block->getBlockID()] = nullptr;
1047}
1048
1049std::unique_ptr<ConsumedStateMap>
1051 assert(Block && "Block pointer must not be NULL");
1052
1053 auto &Entry = StateMapsArray[Block->getBlockID()];
1054 return isBackEdgeTarget(Block) ? std::make_unique<ConsumedStateMap>(*Entry)
1055 : std::move(Entry);
1056}
1057
1059 assert(From && "From block must not be NULL");
1060 assert(To && "From block must not be NULL");
1061
1062 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1063}
1064
1066 assert(Block && "Block pointer must not be NULL");
1067
1068 // Anything with less than two predecessors can't be the target of a back
1069 // edge.
1070 if (Block->pred_size() < 2)
1071 return false;
1072
1073 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1074 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1075 PE = Block->pred_end(); PI != PE; ++PI) {
1076 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1077 return true;
1078 }
1079 return false;
1080}
1081
1083 ConsumedWarningsHandlerBase &WarningsHandler) const {
1084
1085 for (const auto &DM : VarMap) {
1086 if (isa<ParmVarDecl>(DM.first)) {
1087 const auto *Param = cast<ParmVarDecl>(DM.first);
1088 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
1089
1090 if (!RTA)
1091 continue;
1092
1093 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
1094 if (DM.second != ExpectedState)
1095 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1096 Param->getNameAsString(), stateToString(ExpectedState),
1097 stateToString(DM.second));
1098 }
1099 }
1100}
1101
1103 TmpMap.clear();
1104}
1105
1107 VarMapType::const_iterator Entry = VarMap.find(Var);
1108
1109 if (Entry != VarMap.end())
1110 return Entry->second;
1111
1112 return CS_None;
1113}
1114
1117 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1118
1119 if (Entry != TmpMap.end())
1120 return Entry->second;
1121
1122 return CS_None;
1123}
1124
1126 ConsumedState LocalState;
1127
1128 if (this->From && this->From == Other.From && !Other.Reachable) {
1129 this->markUnreachable();
1130 return;
1131 }
1132
1133 for (const auto &DM : Other.VarMap) {
1134 LocalState = this->getState(DM.first);
1135
1136 if (LocalState == CS_None)
1137 continue;
1138
1139 if (LocalState != DM.second)
1140 VarMap[DM.first] = CS_Unknown;
1141 }
1142}
1143
1145 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1146 ConsumedWarningsHandlerBase &WarningsHandler) {
1147
1148 ConsumedState LocalState;
1149 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
1150
1151 for (const auto &DM : LoopBackStates->VarMap) {
1152 LocalState = this->getState(DM.first);
1153
1154 if (LocalState == CS_None)
1155 continue;
1156
1157 if (LocalState != DM.second) {
1158 VarMap[DM.first] = CS_Unknown;
1159 WarningsHandler.warnLoopStateMismatch(BlameLoc,
1160 DM.first->getNameAsString());
1161 }
1162 }
1163}
1164
1166 this->Reachable = false;
1167 VarMap.clear();
1168 TmpMap.clear();
1169}
1170
1172 VarMap[Var] = State;
1173}
1174
1176 ConsumedState State) {
1177 TmpMap[Tmp] = State;
1178}
1179
1181 TmpMap.erase(Tmp);
1182}
1183
1185 for (const auto &DM : Other->VarMap)
1186 if (this->getState(DM.first) != DM.second)
1187 return true;
1188 return false;
1189}
1190
1191void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1192 const FunctionDecl *D) {
1193 QualType ReturnType;
1194 if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1195 ReturnType = Constructor->getFunctionObjectParameterType();
1196 } else
1197 ReturnType = D->getCallResultType();
1198
1199 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
1200 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1201 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1202 // FIXME: This should be removed when template instantiation propagates
1203 // attributes at template specialization definition, not
1204 // declaration. When it is removed the test needs to be enabled
1205 // in SemaDeclAttr.cpp.
1207 RTSAttr->getLocation(), ReturnType.getAsString());
1208 ExpectedReturnState = CS_None;
1209 } else
1210 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1211 } else if (isConsumableType(ReturnType)) {
1212 if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
1213 ExpectedReturnState = CS_None; // expected state.
1214 else
1215 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1216 }
1217 else
1218 ExpectedReturnState = CS_None;
1219}
1220
1221bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1222 const ConsumedStmtVisitor &Visitor) {
1223 std::unique_ptr<ConsumedStateMap> FalseStates(
1224 new ConsumedStateMap(*CurrStates));
1225 PropagationInfo PInfo;
1226
1227 if (const auto *IfNode =
1228 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
1229 if (IfNode->isConsteval())
1230 return false;
1231
1232 const Expr *Cond = IfNode->getCond();
1233
1234 PInfo = Visitor.getInfo(Cond);
1235 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1236 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1237
1238 if (PInfo.isVarTest()) {
1239 CurrStates->setSource(Cond);
1240 FalseStates->setSource(Cond);
1241 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
1242 FalseStates.get());
1243 } else if (PInfo.isBinTest()) {
1244 CurrStates->setSource(PInfo.testSourceNode());
1245 FalseStates->setSource(PInfo.testSourceNode());
1246 splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
1247 } else {
1248 return false;
1249 }
1250 } else if (const auto *BinOp =
1251 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1252 PInfo = Visitor.getInfo(BinOp->getLHS());
1253 if (!PInfo.isVarTest()) {
1254 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1255 PInfo = Visitor.getInfo(BinOp->getRHS());
1256
1257 if (!PInfo.isVarTest())
1258 return false;
1259 } else {
1260 return false;
1261 }
1262 }
1263
1264 CurrStates->setSource(BinOp);
1265 FalseStates->setSource(BinOp);
1266
1267 const VarTestResult &Test = PInfo.getVarTest();
1268 ConsumedState VarState = CurrStates->getState(Test.Var);
1269
1270 if (BinOp->getOpcode() == BO_LAnd) {
1271 if (VarState == CS_Unknown)
1272 CurrStates->setState(Test.Var, Test.TestsFor);
1273 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1274 CurrStates->markUnreachable();
1275
1276 } else if (BinOp->getOpcode() == BO_LOr) {
1277 if (VarState == CS_Unknown)
1278 FalseStates->setState(Test.Var,
1279 invertConsumedUnconsumed(Test.TestsFor));
1280 else if (VarState == Test.TestsFor)
1281 FalseStates->markUnreachable();
1282 }
1283 } else {
1284 return false;
1285 }
1286
1287 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1288
1289 if (*SI)
1290 BlockInfo.addInfo(*SI, std::move(CurrStates));
1291 else
1292 CurrStates = nullptr;
1293
1294 if (*++SI)
1295 BlockInfo.addInfo(*SI, std::move(FalseStates));
1296
1297 return true;
1298}
1299
1301 const auto *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1302 if (!D)
1303 return;
1304
1305 CFG *CFGraph = AC.getCFG();
1306 if (!CFGraph)
1307 return;
1308
1309 determineExpectedReturnState(AC, D);
1310
1311 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1312 // AC.getCFG()->viewCFG(LangOptions());
1313
1314 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
1315
1316 CurrStates = std::make_unique<ConsumedStateMap>();
1317 ConsumedStmtVisitor Visitor(*this, CurrStates.get());
1318
1319 // Add all trackable parameters to the state map.
1320 for (const auto *PI : D->parameters())
1321 Visitor.VisitParmVarDecl(PI);
1322
1323 // Visit all of the function's basic blocks.
1324 for (const auto *CurrBlock : *SortedGraph) {
1325 if (!CurrStates)
1326 CurrStates = BlockInfo.getInfo(CurrBlock);
1327
1328 if (!CurrStates) {
1329 continue;
1330 } else if (!CurrStates->isReachable()) {
1331 CurrStates = nullptr;
1332 continue;
1333 }
1334
1335 Visitor.reset(CurrStates.get());
1336
1337 // Visit all of the basic block's statements.
1338 for (const auto &B : *CurrBlock) {
1339 switch (B.getKind()) {
1341 Visitor.Visit(B.castAs<CFGStmt>().getStmt());
1342 break;
1343
1345 const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
1346 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1347
1348 Visitor.checkCallability(PropagationInfo(BTE),
1349 DTor.getDestructorDecl(AC.getASTContext()),
1350 BTE->getExprLoc());
1351 CurrStates->remove(BTE);
1352 break;
1353 }
1354
1358 const VarDecl *Var = DTor.getVarDecl();
1359
1360 Visitor.checkCallability(PropagationInfo(Var),
1361 DTor.getDestructorDecl(AC.getASTContext()),
1362 Loc);
1363 break;
1364 }
1365
1366 default:
1367 break;
1368 }
1369 }
1370
1371 // TODO: Handle other forms of branching with precision, including while-
1372 // and for-loops. (Deferred)
1373 if (!splitState(CurrBlock, Visitor)) {
1374 CurrStates->setSource(nullptr);
1375
1376 if (CurrBlock->succ_size() > 1 ||
1377 (CurrBlock->succ_size() == 1 &&
1378 (*CurrBlock->succ_begin())->pred_size() > 1)) {
1379
1380 auto *RawState = CurrStates.get();
1381
1382 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1383 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1384 if (*SI == nullptr) continue;
1385
1386 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1387 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
1388 *SI, CurrBlock, RawState, WarningsHandler);
1389
1390 if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
1391 BlockInfo.discardInfo(*SI);
1392 } else {
1393 BlockInfo.addInfo(*SI, RawState, CurrStates);
1394 }
1395 }
1396
1397 CurrStates = nullptr;
1398 }
1399 }
1400
1401 if (CurrBlock == &AC.getCFG()->getExit() &&
1402 D->getCallResultType()->isVoidType())
1403 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1405 } // End of block iterator.
1406
1407 // Delete the last existing state map.
1408 CurrStates = nullptr;
1409
1411}
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
const Decl * D
Expr * E
static void splitVarStateForIfBinOp(const PropagationInfo &PInfo, ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates)
Definition: Consumed.cpp:943
static ConsumedState invertConsumedUnconsumed(ConsumedState State)
Definition: Consumed.cpp:100
static bool isCallableInState(const CallableWhenAttr *CWAttr, ConsumedState State)
Definition: Consumed.cpp:114
static ConsumedState mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr)
Definition: Consumed.cpp:204
static bool isRValueRef(QualType ParamType)
Definition: Consumed.cpp:178
static ConsumedState mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr)
Definition: Consumed.cpp:217
static ConsumedState testsFor(const FunctionDecl *FunDecl)
Definition: Consumed.cpp:258
static bool isConsumableType(const QualType &QT)
Definition: Consumed.cpp:140
static StringRef stateToString(ConsumedState State)
Definition: Consumed.cpp:241
static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test, ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates)
Definition: Consumed.cpp:928
static bool isTestingFunction(const FunctionDecl *FunDecl)
Definition: Consumed.cpp:182
static bool isAutoCastType(const QualType &QT)
Definition: Consumed.cpp:150
static SourceLocation getFirstStmtLoc(const CFGBlock *Block)
Definition: Consumed.cpp:58
static void setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo, ConsumedState State)
Definition: Consumed.cpp:439
static ConsumedState mapConsumableAttrState(const QualType QT)
Definition: Consumed.cpp:186
static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr)
Definition: Consumed.cpp:229
static SourceLocation getLastStmtLoc(const CFGBlock *Block)
Definition: Consumed.cpp:73
static bool isSetOnReadPtrType(const QualType &QT)
Definition: Consumed.cpp:160
static bool isKnownState(ConsumedState State)
Definition: Consumed.cpp:166
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
const CFGBlock * Block
Definition: HTMLLogger.cpp:152
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines an enumeration for C++ overloaded operators.
SourceLocation Loc
Definition: SemaObjC.cpp:754
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".
Definition: Expr.h:3974
Expr * getLHS() const
Definition: Expr.h:4024
Expr * getRHS() const
Definition: Expr.h:4026
Opcode getOpcode() const
Definition: Expr.h:4019
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
Definition: CFG.h:418
const VarDecl * getVarDecl() const
Definition: CFG.h:423
const Stmt * getTriggerStmt() const
Definition: CFG.h:428
Represents a single basic block in a source-level CFG.
Definition: CFG.h:605
pred_iterator pred_end()
Definition: CFG.h:973
reverse_iterator rbegin()
Definition: CFG.h:915
reverse_iterator rend()
Definition: CFG.h:916
CFGTerminator getTerminator() const
Definition: CFG.h:1085
succ_iterator succ_begin()
Definition: CFG.h:990
Stmt * getTerminatorStmt()
Definition: CFG.h:1087
AdjacentBlocks::const_iterator const_pred_iterator
Definition: CFG.h:959
unsigned pred_size() const
Definition: CFG.h:1011
pred_iterator pred_begin()
Definition: CFG.h:972
unsigned getBlockID() const
Definition: CFG.h:1111
AdjacentBlocks::const_iterator const_succ_iterator
Definition: CFG.h:966
unsigned succ_size() const
Definition: CFG.h:1008
Represents a top-level expression in a basic block.
Definition: CFG.h:55
@ AutomaticObjectDtor
Definition: CFG.h:72
@ TemporaryDtor
Definition: CFG.h:76
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
Definition: CFG.h:99
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
Definition: CFG.cpp:5398
const Stmt * getStmt() const
Definition: CFG.h:139
Represents C++ object destructor implicitly generated at the end of full expression for temporary obj...
Definition: CFG.h:511
const CXXBindTemporaryExpr * getBindTemporaryExpr() const
Definition: CFG.h:516
Stmt * getStmt()
Definition: CFG.h:564
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition: CFG.h:1222
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition: CFG.h:1409
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1494
const Expr * getSubExpr() const
Definition: ExprCXX.h:1516
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1549
Represents a C++ constructor within a class.
Definition: DeclCXX.h:2604
Represents a call to a member function that may be written either with member call syntax (e....
Definition: ExprCXX.h:179
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2129
A call to an overloaded operator written using operator syntax.
Definition: ExprCXX.h:84
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2879
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3612
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:196
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1272
ValueDecl * getDecl()
Definition: Expr.h:1340
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1611
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
Definition: Stmt.h:1624
decl_range decls()
Definition: Stmt.h:1659
const Decl * getSingleDecl() const
Definition: Stmt.h:1626
T * getAttr() const
Definition: DeclBase.h:573
SourceLocation getLocation() const
Definition: DeclBase.h:439
bool hasAttr() const
Definition: DeclBase.h:577
This represents one expression.
Definition: Expr.h:112
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3061
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3069
Represents a function declaration or definition.
Definition: Decl.h:1999
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2794
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3767
QualType getCallResultType() const
Determine the type of an expression that calls this function.
Definition: Decl.h:2878
IfStmt - This represents an if/then/else.
Definition: Stmt.h:2259
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition: ExprCXX.h:4914
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition: ExprCXX.h:4931
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3300
Expr * getBase() const
Definition: Expr.h:3377
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...
Definition: Decl.h:316
Represents a parameter to a function.
Definition: Decl.h:1789
A (possibly-)qualified type.
Definition: TypeBase.h:937
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: TypeBase.h:8416
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: TypeBase.h:1332
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3160
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)
Definition: StmtVisitor.h:45
Stmt - This represents one statement.
Definition: Stmt.h:85
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Stmt.cpp:358
bool isRValueReferenceType() const
Definition: TypeBase.h:8612
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.h:26
bool isReferenceType() const
Definition: TypeBase.h:8604
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition: Type.cpp:1909
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:752
bool isPointerOrReferenceType() const
Definition: TypeBase.h:8584
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2246
Expr * getSubExpr() const
Definition: Expr.h:2287
Opcode getOpcode() const
Definition: Expr.h:2282
QualType getType() const
Definition: Decl.h:722
Represents a variable declaration or definition.
Definition: Decl.h:925
bool hasInit() const
Definition: Decl.cpp:2398
const Expr * getInit() const
Definition: Decl.h:1367
A class that handles the analysis of uniqueness violations.
Definition: Consumed.h:243
ConsumedWarningsHandlerBase & WarningsHandler
Definition: Consumed.h:255
ConsumedState getExpectedReturnState() const
Definition: Consumed.h:260
void run(AnalysisDeclContext &AC)
Check a function's CFG for consumed violations.
Definition: Consumed.cpp:1300
ConsumedStateMap * borrowInfo(const CFGBlock *Block)
Definition: Consumed.cpp:1038
bool isBackEdgeTarget(const CFGBlock *Block)
Definition: Consumed.cpp:1065
std::unique_ptr< ConsumedStateMap > getInfo(const CFGBlock *Block)
Definition: Consumed.cpp:1050
void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, std::unique_ptr< ConsumedStateMap > &OwnedStateMap)
Definition: Consumed.cpp:1010
void discardInfo(const CFGBlock *Block)
Definition: Consumed.cpp:1045
bool allBackEdgesVisited(const CFGBlock *CurrBlock, const CFGBlock *TargetBlock)
Definition: Consumed.cpp:996
bool isBackEdge(const CFGBlock *From, const CFGBlock *To)
Definition: Consumed.cpp:1058
void clearTemporaries()
Clear the TmpMap.
Definition: Consumed.cpp:1102
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...
Definition: Consumed.cpp:1082
void intersect(const ConsumedStateMap &Other)
Merge this state map with another map.
Definition: Consumed.cpp:1125
ConsumedState getState(const VarDecl *Var) const
Get the consumed state of a given variable.
Definition: Consumed.cpp:1106
void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, ConsumedWarningsHandlerBase &WarningsHandler)
Definition: Consumed.cpp:1144
void remove(const CXXBindTemporaryExpr *Tmp)
Remove the temporary value from our state map.
Definition: Consumed.cpp:1180
void markUnreachable()
Mark the block as unreachable.
Definition: Consumed.cpp:1165
bool operator!=(const ConsumedStateMap *Other) const
Tests to see if there is a mismatch in the states stored in two maps.
Definition: Consumed.cpp:1184
void setState(const VarDecl *Var, ConsumedState State)
Set the consumed state of a given variable.
Definition: Consumed.cpp:1171
void VisitUnaryOperator(const UnaryOperator *UOp)
Definition: Consumed.cpp:889
PropagationInfo getInfo(const Expr *StmtNode) const
Definition: Consumed.cpp:512
void VisitVarDecl(const VarDecl *Var)
Definition: Consumed.cpp:909
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call)
Definition: Consumed.cpp:795
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp)
Definition: Consumed.cpp:753
void VisitMemberExpr(const MemberExpr *MExpr)
Definition: Consumed.cpp:846
void reset(ConsumedStateMap *NewStateMap)
Definition: Consumed.cpp:521
void VisitReturnStmt(const ReturnStmt *Ret)
Definition: Consumed.cpp:869
void VisitDeclStmt(const DeclStmt *DelcS)
Definition: Consumed.cpp:831
void checkCallability(const PropagationInfo &PInfo, const FunctionDecl *FunDecl, SourceLocation BlameLoc)
Definition: Consumed.cpp:572
void VisitCallExpr(const CallExpr *Call)
Definition: Consumed.cpp:733
void VisitDeclRefExpr(const DeclRefExpr *DeclRef)
Definition: Consumed.cpp:825
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp)
Definition: Consumed.cpp:841
bool handleCall(const CallExpr *Call, const Expr *ObjArg, const FunctionDecl *FunD)
Definition: Consumed.cpp:604
ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap *StateMap)
Definition: Consumed.cpp:509
void VisitCXXConstructExpr(const CXXConstructExpr *Call)
Definition: Consumed.cpp:764
void VisitBinaryOperator(const BinaryOperator *BinOp)
Definition: Consumed.cpp:694
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call)
Definition: Consumed.cpp:805
void VisitCastExpr(const CastExpr *Cast)
Definition: Consumed.cpp:749
void VisitParmVarDecl(const ParmVarDecl *Param)
Definition: Consumed.cpp:850
virtual void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, SourceLocation Loc)
Warn about use-while-consumed errors.
Definition: Consumed.h:122
virtual void warnParamTypestateMismatch(SourceLocation LOC, StringRef ExpectedState, StringRef ObservedState)
Definition: Consumed.h:88
virtual void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName)
Warn that a variable's state doesn't match at the entry and exit of a loop.
Definition: Consumed.h:70
virtual void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, StringRef State, SourceLocation Loc)
Warn about use-while-consumed errors.
Definition: Consumed.h:136
virtual void emitDiagnostics()
Emit the warnings and notes left by the analysis.
Definition: Consumed.h:61
virtual void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, StringRef ObservedState)
Warn about return typestate mismatches.
Definition: Consumed.h:111
virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, StringRef TypeName)
Warn about return typestates set for unconsumable types.
Definition: Consumed.h:99
virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, StringRef VariableName, StringRef ExpectedState, StringRef ObservedState)
Warn about parameter typestate mismatches upon return.
Definition: Consumed.h:82
const VarTestResult & getRTest() const
Definition: Consumed.cpp:364
PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, const VarTestResult &LTest, const VarTestResult &RTest)
Definition: Consumed.cpp:322
const CXXBindTemporaryExpr * Tmp
Definition: Consumed.cpp:307
PropagationInfo(const VarTestResult &VarTest)
Definition: Consumed.cpp:313
EffectiveOp testEffectiveOp() const
Definition: Consumed.cpp:392
PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, const VarDecl *LVar, ConsumedState LTestsFor, const VarDecl *RVar, ConsumedState RTestsFor)
Definition: Consumed.cpp:331
const ConsumedState & getState() const
Definition: Consumed.cpp:349
const VarTestResult & getVarTest() const
Definition: Consumed.cpp:354
const VarDecl * getVar() const
Definition: Consumed.cpp:369
PropagationInfo(ConsumedState State)
Definition: Consumed.cpp:343
PropagationInfo(const VarDecl *Var)
Definition: Consumed.cpp:345
PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
Definition: Consumed.cpp:316
PropagationInfo(const CXXBindTemporaryExpr *Tmp)
Definition: Consumed.cpp:346
const VarTestResult & getLTest() const
Definition: Consumed.cpp:359
const CXXBindTemporaryExpr * getTmp() const
Definition: Consumed.cpp:374
PropagationInfo invertTest() const
Definition: Consumed.cpp:417
ConsumedState getAsState(const ConsumedStateMap *StateMap) const
Definition: Consumed.cpp:379
const BinaryOperator * testSourceNode() const
Definition: Consumed.cpp:397
The JSON file list parser is used to communicate input to InstallAPI.
@ Other
Other implicit parameter.