1 //===- Consumed.cpp --------------------------------------------*- C++ --*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // A intra-procedural analysis for checking consumed properties. This is based,
11 // in part, on research on linear types.
13 //===----------------------------------------------------------------------===//
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Attr.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/AST/RecursiveASTVisitor.h"
20 #include "clang/AST/StmtVisitor.h"
21 #include "clang/AST/StmtCXX.h"
22 #include "clang/AST/Type.h"
23 #include "clang/Analysis/Analyses/PostOrderCFGView.h"
24 #include "clang/Analysis/AnalysisContext.h"
25 #include "clang/Analysis/CFG.h"
26 #include "clang/Analysis/Analyses/Consumed.h"
27 #include "clang/Basic/OperatorKinds.h"
28 #include "clang/Basic/SourceLocation.h"
29 #include "llvm/ADT/DenseMap.h"
30 #include "llvm/ADT/OwningPtr.h"
31 #include "llvm/ADT/SmallVector.h"
32 #include "llvm/Support/Compiler.h"
33 #include "llvm/Support/raw_ostream.h"
35 // TODO: Adjust states of args to constructors in the same way that arguments to
36 // function calls are handled.
37 // TODO: Use information from tests in for- and while-loop conditional.
38 // TODO: Add notes about the actual and expected state for
39 // TODO: Correctly identify unreachable blocks when chaining boolean operators.
40 // TODO: Adjust the parser and AttributesList class to support lists of
42 // TODO: Warn about unreachable code.
43 // TODO: Switch to using a bitmap to track unreachable blocks.
44 // TODO: Handle variable definitions, e.g. bool valid = x.isValid();
45 // if (valid) ...; (Deferred)
46 // TODO: Take notes on state transitions to provide better warning messages.
48 // TODO: Test nested conditionals: A) Checking the same value multiple times,
49 // and 2) Checking different values. (Deferred)
51 using namespace clang;
52 using namespace consumed;
54 // Key method definition
55 ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
57 static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
58 // Find the source location of the first statement in the block, if the block
60 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
62 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
63 return CS->getStmt()->getLocStart();
67 // If we have one successor, return the first statement in that block
68 if (Block->succ_size() == 1 && *Block->succ_begin())
69 return getFirstStmtLoc(*Block->succ_begin());
71 return SourceLocation();
74 static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
75 // Find the source location of the last statement in the block, if the block
77 if (const Stmt *StmtNode = Block->getTerminator()) {
78 return StmtNode->getLocStart();
80 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
81 BE = Block->rend(); BI != BE; ++BI) {
82 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
83 return CS->getStmt()->getLocStart();
87 // If we have one successor, return the first statement in that block
89 if (Block->succ_size() == 1 && *Block->succ_begin())
90 Loc = getFirstStmtLoc(*Block->succ_begin());
94 // If we have one predecessor, return the last statement in that block
95 if (Block->pred_size() == 1 && *Block->pred_begin())
96 return getLastStmtLoc(*Block->pred_begin());
101 static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
106 return CS_Unconsumed;
112 llvm_unreachable("invalid enum");
115 static bool isCallableInState(const CallableWhenAttr *CWAttr,
116 ConsumedState State) {
118 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
119 E = CWAttr->callableState_end();
121 for (; I != E; ++I) {
123 ConsumedState MappedAttrState = CS_None;
126 case CallableWhenAttr::Unknown:
127 MappedAttrState = CS_Unknown;
130 case CallableWhenAttr::Unconsumed:
131 MappedAttrState = CS_Unconsumed;
134 case CallableWhenAttr::Consumed:
135 MappedAttrState = CS_Consumed;
139 if (MappedAttrState == State)
146 static bool isConsumableType(const QualType &QT) {
147 if (QT->isPointerType() || QT->isReferenceType())
150 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
151 return RD->hasAttr<ConsumableAttr>();
156 static bool isKnownState(ConsumedState State) {
165 llvm_unreachable("invalid enum");
168 static bool isRValueRefish(QualType ParamType) {
169 return ParamType->isRValueReferenceType() ||
170 (ParamType->isLValueReferenceType() &&
171 !cast<LValueReferenceType>(
172 ParamType.getCanonicalType())->isSpelledAsLValue());
175 static bool isTestingFunction(const FunctionDecl *FunDecl) {
176 return FunDecl->hasAttr<TestTypestateAttr>();
179 static bool isValueType(QualType ParamType) {
180 return !(ParamType->isPointerType() || ParamType->isReferenceType());
183 static ConsumedState mapConsumableAttrState(const QualType QT) {
184 assert(isConsumableType(QT));
186 const ConsumableAttr *CAttr =
187 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
189 switch (CAttr->getDefaultState()) {
190 case ConsumableAttr::Unknown:
192 case ConsumableAttr::Unconsumed:
193 return CS_Unconsumed;
194 case ConsumableAttr::Consumed:
197 llvm_unreachable("invalid enum");
201 mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
202 switch (PTAttr->getParamState()) {
203 case ParamTypestateAttr::Unknown:
205 case ParamTypestateAttr::Unconsumed:
206 return CS_Unconsumed;
207 case ParamTypestateAttr::Consumed:
210 llvm_unreachable("invalid_enum");
214 mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
215 switch (RTSAttr->getState()) {
216 case ReturnTypestateAttr::Unknown:
218 case ReturnTypestateAttr::Unconsumed:
219 return CS_Unconsumed;
220 case ReturnTypestateAttr::Consumed:
223 llvm_unreachable("invalid enum");
226 static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
227 switch (STAttr->getNewState()) {
228 case SetTypestateAttr::Unknown:
230 case SetTypestateAttr::Unconsumed:
231 return CS_Unconsumed;
232 case SetTypestateAttr::Consumed:
235 llvm_unreachable("invalid_enum");
238 static StringRef stateToString(ConsumedState State) {
240 case consumed::CS_None:
243 case consumed::CS_Unknown:
246 case consumed::CS_Unconsumed:
249 case consumed::CS_Consumed:
252 llvm_unreachable("invalid enum");
255 static ConsumedState testsFor(const FunctionDecl *FunDecl) {
256 assert(isTestingFunction(FunDecl));
257 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
258 case TestTypestateAttr::Unconsumed:
259 return CS_Unconsumed;
260 case TestTypestateAttr::Consumed:
263 llvm_unreachable("invalid enum");
267 struct VarTestResult {
269 ConsumedState TestsFor;
271 } // end anonymous::VarTestResult
281 class PropagationInfo {
292 const BinaryOperator *Source;
300 VarTestResult VarTest;
302 const CXXBindTemporaryExpr *Tmp;
307 PropagationInfo() : InfoType(IT_None) {}
309 PropagationInfo(const VarTestResult &VarTest)
310 : InfoType(IT_VarTest), VarTest(VarTest) {}
312 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
313 : InfoType(IT_VarTest) {
316 VarTest.TestsFor = TestsFor;
319 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
320 const VarTestResult <est, const VarTestResult &RTest)
321 : InfoType(IT_BinTest) {
323 BinTest.Source = Source;
325 BinTest.LTest = LTest;
326 BinTest.RTest = RTest;
329 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
330 const VarDecl *LVar, ConsumedState LTestsFor,
331 const VarDecl *RVar, ConsumedState RTestsFor)
332 : InfoType(IT_BinTest) {
334 BinTest.Source = Source;
336 BinTest.LTest.Var = LVar;
337 BinTest.LTest.TestsFor = LTestsFor;
338 BinTest.RTest.Var = RVar;
339 BinTest.RTest.TestsFor = RTestsFor;
342 PropagationInfo(ConsumedState State)
343 : InfoType(IT_State), State(State) {}
345 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
346 PropagationInfo(const CXXBindTemporaryExpr *Tmp)
347 : InfoType(IT_Tmp), Tmp(Tmp) {}
349 const ConsumedState & getState() const {
350 assert(InfoType == IT_State);
354 const VarTestResult & getVarTest() const {
355 assert(InfoType == IT_VarTest);
359 const VarTestResult & getLTest() const {
360 assert(InfoType == IT_BinTest);
361 return BinTest.LTest;
364 const VarTestResult & getRTest() const {
365 assert(InfoType == IT_BinTest);
366 return BinTest.RTest;
369 const VarDecl * getVar() const {
370 assert(InfoType == IT_Var);
374 const CXXBindTemporaryExpr * getTmp() const {
375 assert(InfoType == IT_Tmp);
379 ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
380 assert(isVar() || isTmp() || isState());
383 return StateMap->getState(Var);
385 return StateMap->getState(Tmp);
392 EffectiveOp testEffectiveOp() const {
393 assert(InfoType == IT_BinTest);
397 const BinaryOperator * testSourceNode() const {
398 assert(InfoType == IT_BinTest);
399 return BinTest.Source;
402 inline bool isValid() const { return InfoType != IT_None; }
403 inline bool isState() const { return InfoType == IT_State; }
404 inline bool isVarTest() const { return InfoType == IT_VarTest; }
405 inline bool isBinTest() const { return InfoType == IT_BinTest; }
406 inline bool isVar() const { return InfoType == IT_Var; }
407 inline bool isTmp() const { return InfoType == IT_Tmp; }
409 bool isTest() const {
410 return InfoType == IT_VarTest || InfoType == IT_BinTest;
413 bool isPointerToValue() const {
414 return InfoType == IT_Var || InfoType == IT_Tmp;
417 PropagationInfo invertTest() const {
418 assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
420 if (InfoType == IT_VarTest) {
421 return PropagationInfo(VarTest.Var,
422 invertConsumedUnconsumed(VarTest.TestsFor));
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));
430 return PropagationInfo();
436 setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
437 ConsumedState State) {
439 assert(PInfo.isVar() || PInfo.isTmp());
442 StateMap->setState(PInfo.getVar(), State);
444 StateMap->setState(PInfo.getTmp(), State);
447 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
449 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
450 typedef std::pair<const Stmt *, PropagationInfo> PairType;
451 typedef MapType::iterator InfoEntry;
452 typedef MapType::const_iterator ConstInfoEntry;
454 AnalysisDeclContext &AC;
455 ConsumedAnalyzer &Analyzer;
456 ConsumedStateMap *StateMap;
457 MapType PropagationMap;
458 void forwardInfo(const Stmt *From, const Stmt *To);
459 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
460 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
461 QualType ReturnType);
464 void checkCallability(const PropagationInfo &PInfo,
465 const FunctionDecl *FunDecl,
466 SourceLocation BlameLoc);
468 void VisitBinaryOperator(const BinaryOperator *BinOp);
469 void VisitCallExpr(const CallExpr *Call);
470 void VisitCastExpr(const CastExpr *Cast);
471 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
472 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
473 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
474 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
475 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
476 void VisitDeclStmt(const DeclStmt *DelcS);
477 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
478 void VisitMemberExpr(const MemberExpr *MExpr);
479 void VisitParmVarDecl(const ParmVarDecl *Param);
480 void VisitReturnStmt(const ReturnStmt *Ret);
481 void VisitUnaryOperator(const UnaryOperator *UOp);
482 void VisitVarDecl(const VarDecl *Var);
484 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
485 ConsumedStateMap *StateMap)
486 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
488 PropagationInfo getInfo(const Stmt *StmtNode) const {
489 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
491 if (Entry != PropagationMap.end())
492 return Entry->second;
494 return PropagationInfo();
497 void reset(ConsumedStateMap *NewStateMap) {
498 StateMap = NewStateMap;
502 void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
503 const FunctionDecl *FunDecl,
504 SourceLocation BlameLoc) {
505 assert(!PInfo.isTest());
507 if (!FunDecl->hasAttr<CallableWhenAttr>())
510 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
513 ConsumedState VarState = StateMap->getState(PInfo.getVar());
515 if (VarState == CS_None || isCallableInState(CWAttr, VarState))
518 Analyzer.WarningsHandler.warnUseInInvalidState(
519 FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
520 stateToString(VarState), BlameLoc);
523 ConsumedState TmpState = PInfo.getAsState(StateMap);
525 if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
528 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
529 FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
533 void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
534 InfoEntry Entry = PropagationMap.find(From);
536 if (Entry != PropagationMap.end())
537 PropagationMap.insert(PairType(To, Entry->second));
540 bool ConsumedStmtVisitor::isLikeMoveAssignment(
541 const CXXMethodDecl *MethodDecl) {
543 return MethodDecl->isMoveAssignmentOperator() ||
544 (MethodDecl->getOverloadedOperator() == OO_Equal &&
545 MethodDecl->getNumParams() == 1 &&
546 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
549 void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
550 const FunctionDecl *Fun,
551 QualType ReturnType) {
552 if (isConsumableType(ReturnType)) {
554 ConsumedState ReturnState;
556 if (Fun->hasAttr<ReturnTypestateAttr>())
557 ReturnState = mapReturnTypestateAttrState(
558 Fun->getAttr<ReturnTypestateAttr>());
560 ReturnState = mapConsumableAttrState(ReturnType);
562 PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
566 void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
567 switch (BinOp->getOpcode()) {
570 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
571 REntry = PropagationMap.find(BinOp->getRHS());
573 VarTestResult LTest, RTest;
575 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
576 LTest = LEntry->second.getVarTest();
580 LTest.TestsFor = CS_None;
583 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
584 RTest = REntry->second.getVarTest();
588 RTest.TestsFor = CS_None;
591 if (!(LTest.Var == NULL && RTest.Var == NULL))
592 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
593 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
600 forwardInfo(BinOp->getLHS(), BinOp);
608 static bool isStdNamespace(const DeclContext *DC) {
609 if (!DC->isNamespace()) return false;
610 while (DC->getParent()->isNamespace())
611 DC = DC->getParent();
612 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
614 return ND && ND->getName() == "std" &&
615 ND->getDeclContext()->isTranslationUnit();
618 void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
619 if (const FunctionDecl *FunDecl =
620 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
622 // Special case for the std::move function.
623 // TODO: Make this more specific. (Deferred)
624 if (Call->getNumArgs() == 1 &&
625 FunDecl->getNameAsString() == "move" &&
626 isStdNamespace(FunDecl->getDeclContext())) {
627 forwardInfo(Call->getArg(0), Call);
631 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
633 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
634 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
635 QualType ParamType = Param->getType();
637 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
639 if (Entry == PropagationMap.end() || Entry->second.isTest())
642 PropagationInfo PInfo = Entry->second;
644 // Check that the parameter is in the correct state.
646 if (Param->hasAttr<ParamTypestateAttr>()) {
647 ConsumedState ParamState = PInfo.getAsState(StateMap);
649 ConsumedState ExpectedState =
650 mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
652 if (ParamState != ExpectedState)
653 Analyzer.WarningsHandler.warnParamTypestateMismatch(
654 Call->getArg(Index - Offset)->getExprLoc(),
655 stateToString(ExpectedState), stateToString(ParamState));
658 if (!(Entry->second.isVar() || Entry->second.isTmp()))
661 // Adjust state on the caller side.
663 if (isRValueRefish(ParamType)) {
664 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
666 } else if (Param->hasAttr<ReturnTypestateAttr>()) {
667 setStateForVarOrTmp(StateMap, PInfo,
668 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
670 } else if (!isValueType(ParamType) &&
671 !ParamType->getPointeeType().isConstQualified()) {
673 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
677 QualType RetType = FunDecl->getCallResultType();
678 if (RetType->isReferenceType())
679 RetType = RetType->getPointeeType();
681 propagateReturnType(Call, FunDecl, RetType);
685 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
686 forwardInfo(Cast->getSubExpr(), Cast);
689 void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
690 const CXXBindTemporaryExpr *Temp) {
692 InfoEntry Entry = PropagationMap.find(Temp->getSubExpr());
694 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
695 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
696 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
700 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
701 CXXConstructorDecl *Constructor = Call->getConstructor();
703 ASTContext &CurrContext = AC.getASTContext();
704 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
706 if (!isConsumableType(ThisType))
709 // FIXME: What should happen if someone annotates the move constructor?
710 if (Constructor->hasAttr<ReturnTypestateAttr>()) {
711 // TODO: Adjust state of args appropriately.
713 ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
714 ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
715 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
717 } else if (Constructor->isDefaultConstructor()) {
719 PropagationMap.insert(PairType(Call,
720 PropagationInfo(consumed::CS_Consumed)));
722 } else if (Constructor->isMoveConstructor()) {
724 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
726 if (Entry != PropagationMap.end()) {
727 PropagationInfo PInfo = Entry->second;
730 const VarDecl* Var = PInfo.getVar();
732 PropagationMap.insert(PairType(Call,
733 PropagationInfo(StateMap->getState(Var))));
735 StateMap->setState(Var, consumed::CS_Consumed);
737 } else if (PInfo.isTmp()) {
738 const CXXBindTemporaryExpr *Tmp = PInfo.getTmp();
740 PropagationMap.insert(PairType(Call,
741 PropagationInfo(StateMap->getState(Tmp))));
743 StateMap->setState(Tmp, consumed::CS_Consumed);
746 PropagationMap.insert(PairType(Call, PInfo));
749 } else if (Constructor->isCopyConstructor()) {
750 forwardInfo(Call->getArg(0), Call);
753 // TODO: Adjust state of args appropriately.
755 ConsumedState RetState = mapConsumableAttrState(ThisType);
756 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
760 void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
761 const CXXMemberCallExpr *Call) {
765 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
767 if (Entry != PropagationMap.end()) {
768 PropagationInfo PInfo = Entry->second;
769 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
771 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
774 if (isTestingFunction(MethodDecl))
775 PropagationMap.insert(PairType(Call,
776 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
777 else if (MethodDecl->hasAttr<SetTypestateAttr>())
778 StateMap->setState(PInfo.getVar(),
779 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
780 } else if (PInfo.isTmp() && MethodDecl->hasAttr<SetTypestateAttr>()) {
781 StateMap->setState(PInfo.getTmp(),
782 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
787 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
788 const CXXOperatorCallExpr *Call) {
790 const FunctionDecl *FunDecl =
791 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
793 if (!FunDecl) return;
795 if (isa<CXXMethodDecl>(FunDecl) &&
796 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
798 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
799 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
801 PropagationInfo LPInfo, RPInfo;
803 if (LEntry != PropagationMap.end() &&
804 REntry != PropagationMap.end()) {
806 LPInfo = LEntry->second;
807 RPInfo = REntry->second;
809 if (LPInfo.isPointerToValue() && RPInfo.isPointerToValue()) {
810 setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getAsState(StateMap));
811 PropagationMap.insert(PairType(Call, LPInfo));
812 setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
814 } else if (RPInfo.isState()) {
815 setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getState());
816 PropagationMap.insert(PairType(Call, LPInfo));
819 setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
822 } else if (LEntry != PropagationMap.end() &&
823 REntry == PropagationMap.end()) {
825 LPInfo = LEntry->second;
827 assert(!LPInfo.isTest());
829 if (LPInfo.isPointerToValue()) {
830 setStateForVarOrTmp(StateMap, LPInfo, consumed::CS_Unknown);
831 PropagationMap.insert(PairType(Call, LPInfo));
834 PropagationMap.insert(PairType(Call,
835 PropagationInfo(consumed::CS_Unknown)));
838 } else if (LEntry == PropagationMap.end() &&
839 REntry != PropagationMap.end()) {
841 RPInfo = REntry->second;
843 if (RPInfo.isPointerToValue())
844 setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
851 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
853 if (Entry != PropagationMap.end()) {
854 PropagationInfo PInfo = Entry->second;
856 checkCallability(PInfo, FunDecl, Call->getExprLoc());
859 if (isTestingFunction(FunDecl))
860 PropagationMap.insert(PairType(Call,
861 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
862 else if (FunDecl->hasAttr<SetTypestateAttr>())
863 StateMap->setState(PInfo.getVar(),
864 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
866 } else if (PInfo.isTmp() && FunDecl->hasAttr<SetTypestateAttr>()) {
867 StateMap->setState(PInfo.getTmp(),
868 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
874 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
875 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
876 if (StateMap->getState(Var) != consumed::CS_None)
877 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
880 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
881 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
882 DE = DeclS->decl_end(); DI != DE; ++DI) {
884 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
887 if (DeclS->isSingleDecl())
888 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
889 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
892 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
893 const MaterializeTemporaryExpr *Temp) {
895 forwardInfo(Temp->GetTemporaryExpr(), Temp);
898 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
899 forwardInfo(MExpr->getBase(), MExpr);
903 void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
904 QualType ParamType = Param->getType();
905 ConsumedState ParamState = consumed::CS_None;
907 if (Param->hasAttr<ParamTypestateAttr>()) {
908 const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
909 ParamState = mapParamTypestateAttrState(PTAttr);
911 } else if (isConsumableType(ParamType)) {
912 ParamState = mapConsumableAttrState(ParamType);
914 } else if (isRValueRefish(ParamType) &&
915 isConsumableType(ParamType->getPointeeType())) {
917 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
919 } else if (ParamType->isReferenceType() &&
920 isConsumableType(ParamType->getPointeeType())) {
921 ParamState = consumed::CS_Unknown;
924 if (ParamState != CS_None)
925 StateMap->setState(Param, ParamState);
928 void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
929 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
931 if (ExpectedState != CS_None) {
932 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
934 if (Entry != PropagationMap.end()) {
935 ConsumedState RetState = Entry->second.getAsState(StateMap);
937 if (RetState != ExpectedState)
938 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
939 Ret->getReturnLoc(), stateToString(ExpectedState),
940 stateToString(RetState));
944 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
945 Analyzer.WarningsHandler);
948 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
949 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
950 if (Entry == PropagationMap.end()) return;
952 switch (UOp->getOpcode()) {
954 PropagationMap.insert(PairType(UOp, Entry->second));
958 if (Entry->second.isTest())
959 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
967 // TODO: See if I need to check for reference types here.
968 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
969 if (isConsumableType(Var->getType())) {
970 if (Var->hasInit()) {
971 MapType::iterator VIT = PropagationMap.find(
972 Var->getInit()->IgnoreImplicit());
973 if (VIT != PropagationMap.end()) {
974 PropagationInfo PInfo = VIT->second;
975 ConsumedState St = PInfo.getAsState(StateMap);
977 if (St != consumed::CS_None) {
978 StateMap->setState(Var, St);
984 StateMap->setState(Var, consumed::CS_Unknown);
987 }} // end clang::consumed::ConsumedStmtVisitor
992 void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
993 ConsumedStateMap *ThenStates,
994 ConsumedStateMap *ElseStates) {
996 ConsumedState VarState = ThenStates->getState(Test.Var);
998 if (VarState == CS_Unknown) {
999 ThenStates->setState(Test.Var, Test.TestsFor);
1000 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
1002 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
1003 ThenStates->markUnreachable();
1005 } else if (VarState == Test.TestsFor) {
1006 ElseStates->markUnreachable();
1010 void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
1011 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
1013 const VarTestResult <est = PInfo.getLTest(),
1014 &RTest = PInfo.getRTest();
1016 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
1017 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
1020 if (PInfo.testEffectiveOp() == EO_And) {
1021 if (LState == CS_Unknown) {
1022 ThenStates->setState(LTest.Var, LTest.TestsFor);
1024 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
1025 ThenStates->markUnreachable();
1027 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
1028 if (RState == RTest.TestsFor)
1029 ElseStates->markUnreachable();
1031 ThenStates->markUnreachable();
1035 if (LState == CS_Unknown) {
1036 ElseStates->setState(LTest.Var,
1037 invertConsumedUnconsumed(LTest.TestsFor));
1039 } else if (LState == LTest.TestsFor) {
1040 ElseStates->markUnreachable();
1042 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1043 isKnownState(RState)) {
1045 if (RState == RTest.TestsFor)
1046 ElseStates->markUnreachable();
1048 ThenStates->markUnreachable();
1054 if (PInfo.testEffectiveOp() == EO_And) {
1055 if (RState == CS_Unknown)
1056 ThenStates->setState(RTest.Var, RTest.TestsFor);
1057 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1058 ThenStates->markUnreachable();
1061 if (RState == CS_Unknown)
1062 ElseStates->setState(RTest.Var,
1063 invertConsumedUnconsumed(RTest.TestsFor));
1064 else if (RState == RTest.TestsFor)
1065 ElseStates->markUnreachable();
1070 bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1071 const CFGBlock *TargetBlock) {
1073 assert(CurrBlock && "Block pointer must not be NULL");
1074 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1076 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1077 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1078 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1079 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1085 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1086 ConsumedStateMap *StateMap,
1087 bool &AlreadyOwned) {
1089 assert(Block && "Block pointer must not be NULL");
1091 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1094 Entry->intersect(StateMap);
1096 } else if (AlreadyOwned) {
1097 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1100 StateMapsArray[Block->getBlockID()] = StateMap;
1101 AlreadyOwned = true;
1105 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1106 ConsumedStateMap *StateMap) {
1108 assert(Block != NULL && "Block pointer must not be NULL");
1110 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1113 Entry->intersect(StateMap);
1117 StateMapsArray[Block->getBlockID()] = StateMap;
1121 ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1122 assert(Block && "Block pointer must not be NULL");
1123 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1125 return StateMapsArray[Block->getBlockID()];
1128 void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1129 unsigned int BlockID = Block->getBlockID();
1130 delete StateMapsArray[BlockID];
1131 StateMapsArray[BlockID] = NULL;
1134 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1135 assert(Block && "Block pointer must not be NULL");
1137 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1138 if (isBackEdgeTarget(Block)) {
1139 return new ConsumedStateMap(*StateMap);
1141 StateMapsArray[Block->getBlockID()] = NULL;
1146 bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1147 assert(From && "From block must not be NULL");
1148 assert(To && "From block must not be NULL");
1150 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1153 bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1154 assert(Block != NULL && "Block pointer must not be NULL");
1156 // Anything with less than two predecessors can't be the target of a back
1158 if (Block->pred_size() < 2)
1161 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1162 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1163 PE = Block->pred_end(); PI != PE; ++PI) {
1164 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1170 void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1171 ConsumedWarningsHandlerBase &WarningsHandler) const {
1173 ConsumedState ExpectedState;
1175 for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
1176 DMI != DME; ++DMI) {
1178 if (isa<ParmVarDecl>(DMI->first)) {
1179 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
1181 if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
1184 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
1186 if (DMI->second != ExpectedState) {
1187 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1188 Param->getNameAsString(), stateToString(ExpectedState),
1189 stateToString(DMI->second));
1195 void ConsumedStateMap::clearTemporaries() {
1199 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
1200 VarMapType::const_iterator Entry = VarMap.find(Var);
1202 if (Entry != VarMap.end())
1203 return Entry->second;
1209 ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1210 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1212 if (Entry != TmpMap.end())
1213 return Entry->second;
1218 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1219 ConsumedState LocalState;
1221 if (this->From && this->From == Other->From && !Other->Reachable) {
1222 this->markUnreachable();
1226 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1227 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
1229 LocalState = this->getState(DMI->first);
1231 if (LocalState == CS_None)
1234 if (LocalState != DMI->second)
1235 VarMap[DMI->first] = CS_Unknown;
1239 void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1240 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1241 ConsumedWarningsHandlerBase &WarningsHandler) {
1243 ConsumedState LocalState;
1244 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
1246 for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
1247 DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
1249 LocalState = this->getState(DMI->first);
1251 if (LocalState == CS_None)
1254 if (LocalState != DMI->second) {
1255 VarMap[DMI->first] = CS_Unknown;
1256 WarningsHandler.warnLoopStateMismatch(
1257 BlameLoc, DMI->first->getNameAsString());
1262 void ConsumedStateMap::markUnreachable() {
1263 this->Reachable = false;
1268 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1269 VarMap[Var] = State;
1272 void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1273 ConsumedState State) {
1274 TmpMap[Tmp] = State;
1277 void ConsumedStateMap::remove(const VarDecl *Var) {
1281 bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1282 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1283 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
1285 if (this->getState(DMI->first) != DMI->second)
1292 void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1293 const FunctionDecl *D) {
1294 QualType ReturnType;
1295 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1296 ASTContext &CurrContext = AC.getASTContext();
1297 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1299 ReturnType = D->getCallResultType();
1301 if (D->hasAttr<ReturnTypestateAttr>()) {
1302 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1304 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1305 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1306 // FIXME: This should be removed when template instantiation propagates
1307 // attributes at template specialization definition, not
1308 // declaration. When it is removed the test needs to be enabled
1309 // in SemaDeclAttr.cpp.
1310 WarningsHandler.warnReturnTypestateForUnconsumableType(
1311 RTSAttr->getLocation(), ReturnType.getAsString());
1312 ExpectedReturnState = CS_None;
1314 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1315 } else if (isConsumableType(ReturnType))
1316 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1318 ExpectedReturnState = CS_None;
1321 bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1322 const ConsumedStmtVisitor &Visitor) {
1324 OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates));
1325 PropagationInfo PInfo;
1327 if (const IfStmt *IfNode =
1328 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
1330 const Stmt *Cond = IfNode->getCond();
1332 PInfo = Visitor.getInfo(Cond);
1333 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1334 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1336 if (PInfo.isVarTest()) {
1337 CurrStates->setSource(Cond);
1338 FalseStates->setSource(Cond);
1339 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
1342 } else if (PInfo.isBinTest()) {
1343 CurrStates->setSource(PInfo.testSourceNode());
1344 FalseStates->setSource(PInfo.testSourceNode());
1345 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
1351 } else if (const BinaryOperator *BinOp =
1352 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1354 PInfo = Visitor.getInfo(BinOp->getLHS());
1355 if (!PInfo.isVarTest()) {
1356 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1357 PInfo = Visitor.getInfo(BinOp->getRHS());
1359 if (!PInfo.isVarTest())
1367 CurrStates->setSource(BinOp);
1368 FalseStates->setSource(BinOp);
1370 const VarTestResult &Test = PInfo.getVarTest();
1371 ConsumedState VarState = CurrStates->getState(Test.Var);
1373 if (BinOp->getOpcode() == BO_LAnd) {
1374 if (VarState == CS_Unknown)
1375 CurrStates->setState(Test.Var, Test.TestsFor);
1376 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1377 CurrStates->markUnreachable();
1379 } else if (BinOp->getOpcode() == BO_LOr) {
1380 if (VarState == CS_Unknown)
1381 FalseStates->setState(Test.Var,
1382 invertConsumedUnconsumed(Test.TestsFor));
1383 else if (VarState == Test.TestsFor)
1384 FalseStates->markUnreachable();
1391 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1394 BlockInfo.addInfo(*SI, CurrStates);
1399 BlockInfo.addInfo(*SI, FalseStates.take());
1405 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1406 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1410 CFG *CFGraph = AC.getCFG();
1414 determineExpectedReturnState(AC, D);
1416 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1417 // AC.getCFG()->viewCFG(LangOptions());
1419 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
1421 CurrStates = new ConsumedStateMap();
1422 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1424 // Add all trackable parameters to the state map.
1425 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1426 PE = D->param_end(); PI != PE; ++PI) {
1427 Visitor.VisitParmVarDecl(*PI);
1430 // Visit all of the function's basic blocks.
1431 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1432 E = SortedGraph->end(); I != E; ++I) {
1434 const CFGBlock *CurrBlock = *I;
1436 if (CurrStates == NULL)
1437 CurrStates = BlockInfo.getInfo(CurrBlock);
1442 } else if (!CurrStates->isReachable()) {
1448 Visitor.reset(CurrStates);
1450 // Visit all of the basic block's statements.
1451 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1452 BE = CurrBlock->end(); BI != BE; ++BI) {
1454 switch (BI->getKind()) {
1455 case CFGElement::Statement:
1456 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
1459 case CFGElement::TemporaryDtor: {
1460 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1461 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1463 Visitor.checkCallability(PropagationInfo(BTE),
1464 DTor.getDestructorDecl(AC.getASTContext()),
1469 case CFGElement::AutomaticObjectDtor: {
1470 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1471 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
1472 const VarDecl *Var = DTor.getVarDecl();
1474 Visitor.checkCallability(PropagationInfo(Var),
1475 DTor.getDestructorDecl(AC.getASTContext()),
1485 CurrStates->clearTemporaries();
1487 // TODO: Handle other forms of branching with precision, including while-
1488 // and for-loops. (Deferred)
1489 if (!splitState(CurrBlock, Visitor)) {
1490 CurrStates->setSource(NULL);
1492 if (CurrBlock->succ_size() > 1 ||
1493 (CurrBlock->succ_size() == 1 &&
1494 (*CurrBlock->succ_begin())->pred_size() > 1)) {
1496 bool OwnershipTaken = false;
1498 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1499 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1501 if (*SI == NULL) continue;
1503 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1504 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1508 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1509 BlockInfo.discardInfo(*SI);
1511 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1515 if (!OwnershipTaken)
1522 if (CurrBlock == &AC.getCFG()->getExit() &&
1523 D->getCallResultType()->isVoidType())
1524 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1526 } // End of block iterator.
1528 // Delete the last existing state map.
1531 WarningsHandler.emitDiagnostics();
1533 }} // end namespace clang::consumed