10b57cec5SDimitry Andric //===- Consumed.cpp -------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // A intra-procedural analysis for checking consumed properties. This is based,
100b57cec5SDimitry Andric // in part, on research on linear types.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/Analysis/Analyses/Consumed.h"
150b57cec5SDimitry Andric #include "clang/AST/Attr.h"
160b57cec5SDimitry Andric #include "clang/AST/Decl.h"
170b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
180b57cec5SDimitry Andric #include "clang/AST/Expr.h"
190b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
200b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
210b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
220b57cec5SDimitry Andric #include "clang/AST/Type.h"
230b57cec5SDimitry Andric #include "clang/Analysis/Analyses/PostOrderCFGView.h"
240b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
250b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
260b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
270b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.h"
280b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
290b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
300b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
310b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
320b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
330b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
340b57cec5SDimitry Andric #include <cassert>
350b57cec5SDimitry Andric #include <memory>
36bdd1243dSDimitry Andric #include <optional>
370b57cec5SDimitry Andric #include <utility>
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric // TODO: Adjust states of args to constructors in the same way that arguments to
400b57cec5SDimitry Andric // function calls are handled.
410b57cec5SDimitry Andric // TODO: Use information from tests in for- and while-loop conditional.
420b57cec5SDimitry Andric // TODO: Add notes about the actual and expected state for
430b57cec5SDimitry Andric // TODO: Correctly identify unreachable blocks when chaining boolean operators.
440b57cec5SDimitry Andric // TODO: Adjust the parser and AttributesList class to support lists of
450b57cec5SDimitry Andric // identifiers.
460b57cec5SDimitry Andric // TODO: Warn about unreachable code.
470b57cec5SDimitry Andric // TODO: Switch to using a bitmap to track unreachable blocks.
480b57cec5SDimitry Andric // TODO: Handle variable definitions, e.g. bool valid = x.isValid();
490b57cec5SDimitry Andric // if (valid) ...; (Deferred)
500b57cec5SDimitry Andric // TODO: Take notes on state transitions to provide better warning messages.
510b57cec5SDimitry Andric // (Deferred)
520b57cec5SDimitry Andric // TODO: Test nested conditionals: A) Checking the same value multiple times,
530b57cec5SDimitry Andric // and 2) Checking different values. (Deferred)
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric using namespace clang;
560b57cec5SDimitry Andric using namespace consumed;
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric // Key method definition
590b57cec5SDimitry Andric ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() = default;
600b57cec5SDimitry Andric
getFirstStmtLoc(const CFGBlock * Block)610b57cec5SDimitry Andric static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
620b57cec5SDimitry Andric // Find the source location of the first statement in the block, if the block
630b57cec5SDimitry Andric // is not empty.
640b57cec5SDimitry Andric for (const auto &B : *Block)
65bdd1243dSDimitry Andric if (std::optional<CFGStmt> CS = B.getAs<CFGStmt>())
660b57cec5SDimitry Andric return CS->getStmt()->getBeginLoc();
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric // Block is empty.
690b57cec5SDimitry Andric // If we have one successor, return the first statement in that block
700b57cec5SDimitry Andric if (Block->succ_size() == 1 && *Block->succ_begin())
710b57cec5SDimitry Andric return getFirstStmtLoc(*Block->succ_begin());
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric return {};
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
getLastStmtLoc(const CFGBlock * Block)760b57cec5SDimitry Andric static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
770b57cec5SDimitry Andric // Find the source location of the last statement in the block, if the block
780b57cec5SDimitry Andric // is not empty.
790b57cec5SDimitry Andric if (const Stmt *StmtNode = Block->getTerminatorStmt()) {
800b57cec5SDimitry Andric return StmtNode->getBeginLoc();
810b57cec5SDimitry Andric } else {
820b57cec5SDimitry Andric for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
830b57cec5SDimitry Andric BE = Block->rend(); BI != BE; ++BI) {
84bdd1243dSDimitry Andric if (std::optional<CFGStmt> CS = BI->getAs<CFGStmt>())
850b57cec5SDimitry Andric return CS->getStmt()->getBeginLoc();
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric // If we have one successor, return the first statement in that block
900b57cec5SDimitry Andric SourceLocation Loc;
910b57cec5SDimitry Andric if (Block->succ_size() == 1 && *Block->succ_begin())
920b57cec5SDimitry Andric Loc = getFirstStmtLoc(*Block->succ_begin());
930b57cec5SDimitry Andric if (Loc.isValid())
940b57cec5SDimitry Andric return Loc;
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric // If we have one predecessor, return the last statement in that block
970b57cec5SDimitry Andric if (Block->pred_size() == 1 && *Block->pred_begin())
980b57cec5SDimitry Andric return getLastStmtLoc(*Block->pred_begin());
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric return Loc;
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
invertConsumedUnconsumed(ConsumedState State)1030b57cec5SDimitry Andric static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
1040b57cec5SDimitry Andric switch (State) {
1050b57cec5SDimitry Andric case CS_Unconsumed:
1060b57cec5SDimitry Andric return CS_Consumed;
1070b57cec5SDimitry Andric case CS_Consumed:
1080b57cec5SDimitry Andric return CS_Unconsumed;
1090b57cec5SDimitry Andric case CS_None:
1100b57cec5SDimitry Andric return CS_None;
1110b57cec5SDimitry Andric case CS_Unknown:
1120b57cec5SDimitry Andric return CS_Unknown;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric llvm_unreachable("invalid enum");
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
isCallableInState(const CallableWhenAttr * CWAttr,ConsumedState State)1170b57cec5SDimitry Andric static bool isCallableInState(const CallableWhenAttr *CWAttr,
1180b57cec5SDimitry Andric ConsumedState State) {
1190b57cec5SDimitry Andric for (const auto &S : CWAttr->callableStates()) {
1200b57cec5SDimitry Andric ConsumedState MappedAttrState = CS_None;
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric switch (S) {
1230b57cec5SDimitry Andric case CallableWhenAttr::Unknown:
1240b57cec5SDimitry Andric MappedAttrState = CS_Unknown;
1250b57cec5SDimitry Andric break;
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric case CallableWhenAttr::Unconsumed:
1280b57cec5SDimitry Andric MappedAttrState = CS_Unconsumed;
1290b57cec5SDimitry Andric break;
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric case CallableWhenAttr::Consumed:
1320b57cec5SDimitry Andric MappedAttrState = CS_Consumed;
1330b57cec5SDimitry Andric break;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric if (MappedAttrState == State)
1370b57cec5SDimitry Andric return true;
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric
1400b57cec5SDimitry Andric return false;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric
isConsumableType(const QualType & QT)1430b57cec5SDimitry Andric static bool isConsumableType(const QualType &QT) {
1440b57cec5SDimitry Andric if (QT->isPointerType() || QT->isReferenceType())
1450b57cec5SDimitry Andric return false;
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
1480b57cec5SDimitry Andric return RD->hasAttr<ConsumableAttr>();
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric return false;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
isAutoCastType(const QualType & QT)1530b57cec5SDimitry Andric static bool isAutoCastType(const QualType &QT) {
1540b57cec5SDimitry Andric if (QT->isPointerType() || QT->isReferenceType())
1550b57cec5SDimitry Andric return false;
1560b57cec5SDimitry Andric
1570b57cec5SDimitry Andric if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
1580b57cec5SDimitry Andric return RD->hasAttr<ConsumableAutoCastAttr>();
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric return false;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric
isSetOnReadPtrType(const QualType & QT)1630b57cec5SDimitry Andric static bool isSetOnReadPtrType(const QualType &QT) {
1640b57cec5SDimitry Andric if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
1650b57cec5SDimitry Andric return RD->hasAttr<ConsumableSetOnReadAttr>();
1660b57cec5SDimitry Andric return false;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric
isKnownState(ConsumedState State)1690b57cec5SDimitry Andric static bool isKnownState(ConsumedState State) {
1700b57cec5SDimitry Andric switch (State) {
1710b57cec5SDimitry Andric case CS_Unconsumed:
1720b57cec5SDimitry Andric case CS_Consumed:
1730b57cec5SDimitry Andric return true;
1740b57cec5SDimitry Andric case CS_None:
1750b57cec5SDimitry Andric case CS_Unknown:
1760b57cec5SDimitry Andric return false;
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric llvm_unreachable("invalid enum");
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric
isRValueRef(QualType ParamType)1810b57cec5SDimitry Andric static bool isRValueRef(QualType ParamType) {
1820b57cec5SDimitry Andric return ParamType->isRValueReferenceType();
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric
isTestingFunction(const FunctionDecl * FunDecl)1850b57cec5SDimitry Andric static bool isTestingFunction(const FunctionDecl *FunDecl) {
1860b57cec5SDimitry Andric return FunDecl->hasAttr<TestTypestateAttr>();
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric
isPointerOrRef(QualType ParamType)1890b57cec5SDimitry Andric static bool isPointerOrRef(QualType ParamType) {
1900b57cec5SDimitry Andric return ParamType->isPointerType() || ParamType->isReferenceType();
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
mapConsumableAttrState(const QualType QT)1930b57cec5SDimitry Andric static ConsumedState mapConsumableAttrState(const QualType QT) {
1940b57cec5SDimitry Andric assert(isConsumableType(QT));
1950b57cec5SDimitry Andric
1960b57cec5SDimitry Andric const ConsumableAttr *CAttr =
1970b57cec5SDimitry Andric QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric switch (CAttr->getDefaultState()) {
2000b57cec5SDimitry Andric case ConsumableAttr::Unknown:
2010b57cec5SDimitry Andric return CS_Unknown;
2020b57cec5SDimitry Andric case ConsumableAttr::Unconsumed:
2030b57cec5SDimitry Andric return CS_Unconsumed;
2040b57cec5SDimitry Andric case ConsumableAttr::Consumed:
2050b57cec5SDimitry Andric return CS_Consumed;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric llvm_unreachable("invalid enum");
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric static ConsumedState
mapParamTypestateAttrState(const ParamTypestateAttr * PTAttr)2110b57cec5SDimitry Andric mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
2120b57cec5SDimitry Andric switch (PTAttr->getParamState()) {
2130b57cec5SDimitry Andric case ParamTypestateAttr::Unknown:
2140b57cec5SDimitry Andric return CS_Unknown;
2150b57cec5SDimitry Andric case ParamTypestateAttr::Unconsumed:
2160b57cec5SDimitry Andric return CS_Unconsumed;
2170b57cec5SDimitry Andric case ParamTypestateAttr::Consumed:
2180b57cec5SDimitry Andric return CS_Consumed;
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric llvm_unreachable("invalid_enum");
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric static ConsumedState
mapReturnTypestateAttrState(const ReturnTypestateAttr * RTSAttr)2240b57cec5SDimitry Andric mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
2250b57cec5SDimitry Andric switch (RTSAttr->getState()) {
2260b57cec5SDimitry Andric case ReturnTypestateAttr::Unknown:
2270b57cec5SDimitry Andric return CS_Unknown;
2280b57cec5SDimitry Andric case ReturnTypestateAttr::Unconsumed:
2290b57cec5SDimitry Andric return CS_Unconsumed;
2300b57cec5SDimitry Andric case ReturnTypestateAttr::Consumed:
2310b57cec5SDimitry Andric return CS_Consumed;
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric llvm_unreachable("invalid enum");
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric
mapSetTypestateAttrState(const SetTypestateAttr * STAttr)2360b57cec5SDimitry Andric static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
2370b57cec5SDimitry Andric switch (STAttr->getNewState()) {
2380b57cec5SDimitry Andric case SetTypestateAttr::Unknown:
2390b57cec5SDimitry Andric return CS_Unknown;
2400b57cec5SDimitry Andric case SetTypestateAttr::Unconsumed:
2410b57cec5SDimitry Andric return CS_Unconsumed;
2420b57cec5SDimitry Andric case SetTypestateAttr::Consumed:
2430b57cec5SDimitry Andric return CS_Consumed;
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric llvm_unreachable("invalid_enum");
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric
stateToString(ConsumedState State)2480b57cec5SDimitry Andric static StringRef stateToString(ConsumedState State) {
2490b57cec5SDimitry Andric switch (State) {
2500b57cec5SDimitry Andric case consumed::CS_None:
2510b57cec5SDimitry Andric return "none";
2520b57cec5SDimitry Andric
2530b57cec5SDimitry Andric case consumed::CS_Unknown:
2540b57cec5SDimitry Andric return "unknown";
2550b57cec5SDimitry Andric
2560b57cec5SDimitry Andric case consumed::CS_Unconsumed:
2570b57cec5SDimitry Andric return "unconsumed";
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric case consumed::CS_Consumed:
2600b57cec5SDimitry Andric return "consumed";
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric llvm_unreachable("invalid enum");
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric
testsFor(const FunctionDecl * FunDecl)2650b57cec5SDimitry Andric static ConsumedState testsFor(const FunctionDecl *FunDecl) {
2660b57cec5SDimitry Andric assert(isTestingFunction(FunDecl));
2670b57cec5SDimitry Andric switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
2680b57cec5SDimitry Andric case TestTypestateAttr::Unconsumed:
2690b57cec5SDimitry Andric return CS_Unconsumed;
2700b57cec5SDimitry Andric case TestTypestateAttr::Consumed:
2710b57cec5SDimitry Andric return CS_Consumed;
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric llvm_unreachable("invalid enum");
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric
2760b57cec5SDimitry Andric namespace {
2770b57cec5SDimitry Andric
2780b57cec5SDimitry Andric struct VarTestResult {
2790b57cec5SDimitry Andric const VarDecl *Var;
2800b57cec5SDimitry Andric ConsumedState TestsFor;
2810b57cec5SDimitry Andric };
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric } // namespace
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric namespace clang {
2860b57cec5SDimitry Andric namespace consumed {
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric enum EffectiveOp {
2890b57cec5SDimitry Andric EO_And,
2900b57cec5SDimitry Andric EO_Or
2910b57cec5SDimitry Andric };
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric class PropagationInfo {
2940b57cec5SDimitry Andric enum {
2950b57cec5SDimitry Andric IT_None,
2960b57cec5SDimitry Andric IT_State,
2970b57cec5SDimitry Andric IT_VarTest,
2980b57cec5SDimitry Andric IT_BinTest,
2990b57cec5SDimitry Andric IT_Var,
3000b57cec5SDimitry Andric IT_Tmp
3010b57cec5SDimitry Andric } InfoType = IT_None;
3020b57cec5SDimitry Andric
3030b57cec5SDimitry Andric struct BinTestTy {
3040b57cec5SDimitry Andric const BinaryOperator *Source;
3050b57cec5SDimitry Andric EffectiveOp EOp;
3060b57cec5SDimitry Andric VarTestResult LTest;
3070b57cec5SDimitry Andric VarTestResult RTest;
3080b57cec5SDimitry Andric };
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric union {
3110b57cec5SDimitry Andric ConsumedState State;
3120b57cec5SDimitry Andric VarTestResult VarTest;
3130b57cec5SDimitry Andric const VarDecl *Var;
3140b57cec5SDimitry Andric const CXXBindTemporaryExpr *Tmp;
3150b57cec5SDimitry Andric BinTestTy BinTest;
3160b57cec5SDimitry Andric };
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andric public:
3190b57cec5SDimitry Andric PropagationInfo() = default;
PropagationInfo(const VarTestResult & VarTest)3200b57cec5SDimitry Andric PropagationInfo(const VarTestResult &VarTest)
3210b57cec5SDimitry Andric : InfoType(IT_VarTest), VarTest(VarTest) {}
3220b57cec5SDimitry Andric
PropagationInfo(const VarDecl * Var,ConsumedState TestsFor)3230b57cec5SDimitry Andric PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
3240b57cec5SDimitry Andric : InfoType(IT_VarTest) {
3250b57cec5SDimitry Andric VarTest.Var = Var;
3260b57cec5SDimitry Andric VarTest.TestsFor = TestsFor;
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric
PropagationInfo(const BinaryOperator * Source,EffectiveOp EOp,const VarTestResult & LTest,const VarTestResult & RTest)3290b57cec5SDimitry Andric PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
3300b57cec5SDimitry Andric const VarTestResult <est, const VarTestResult &RTest)
3310b57cec5SDimitry Andric : InfoType(IT_BinTest) {
3320b57cec5SDimitry Andric BinTest.Source = Source;
3330b57cec5SDimitry Andric BinTest.EOp = EOp;
3340b57cec5SDimitry Andric BinTest.LTest = LTest;
3350b57cec5SDimitry Andric BinTest.RTest = RTest;
3360b57cec5SDimitry Andric }
3370b57cec5SDimitry Andric
PropagationInfo(const BinaryOperator * Source,EffectiveOp EOp,const VarDecl * LVar,ConsumedState LTestsFor,const VarDecl * RVar,ConsumedState RTestsFor)3380b57cec5SDimitry Andric PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
3390b57cec5SDimitry Andric const VarDecl *LVar, ConsumedState LTestsFor,
3400b57cec5SDimitry Andric const VarDecl *RVar, ConsumedState RTestsFor)
3410b57cec5SDimitry Andric : InfoType(IT_BinTest) {
3420b57cec5SDimitry Andric BinTest.Source = Source;
3430b57cec5SDimitry Andric BinTest.EOp = EOp;
3440b57cec5SDimitry Andric BinTest.LTest.Var = LVar;
3450b57cec5SDimitry Andric BinTest.LTest.TestsFor = LTestsFor;
3460b57cec5SDimitry Andric BinTest.RTest.Var = RVar;
3470b57cec5SDimitry Andric BinTest.RTest.TestsFor = RTestsFor;
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric
PropagationInfo(ConsumedState State)3500b57cec5SDimitry Andric PropagationInfo(ConsumedState State)
3510b57cec5SDimitry Andric : InfoType(IT_State), State(State) {}
PropagationInfo(const VarDecl * Var)3520b57cec5SDimitry Andric PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
PropagationInfo(const CXXBindTemporaryExpr * Tmp)3530b57cec5SDimitry Andric PropagationInfo(const CXXBindTemporaryExpr *Tmp)
3540b57cec5SDimitry Andric : InfoType(IT_Tmp), Tmp(Tmp) {}
3550b57cec5SDimitry Andric
getState() const3560b57cec5SDimitry Andric const ConsumedState &getState() const {
3570b57cec5SDimitry Andric assert(InfoType == IT_State);
3580b57cec5SDimitry Andric return State;
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric
getVarTest() const3610b57cec5SDimitry Andric const VarTestResult &getVarTest() const {
3620b57cec5SDimitry Andric assert(InfoType == IT_VarTest);
3630b57cec5SDimitry Andric return VarTest;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric
getLTest() const3660b57cec5SDimitry Andric const VarTestResult &getLTest() const {
3670b57cec5SDimitry Andric assert(InfoType == IT_BinTest);
3680b57cec5SDimitry Andric return BinTest.LTest;
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric
getRTest() const3710b57cec5SDimitry Andric const VarTestResult &getRTest() const {
3720b57cec5SDimitry Andric assert(InfoType == IT_BinTest);
3730b57cec5SDimitry Andric return BinTest.RTest;
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric
getVar() const3760b57cec5SDimitry Andric const VarDecl *getVar() const {
3770b57cec5SDimitry Andric assert(InfoType == IT_Var);
3780b57cec5SDimitry Andric return Var;
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric
getTmp() const3810b57cec5SDimitry Andric const CXXBindTemporaryExpr *getTmp() const {
3820b57cec5SDimitry Andric assert(InfoType == IT_Tmp);
3830b57cec5SDimitry Andric return Tmp;
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric
getAsState(const ConsumedStateMap * StateMap) const3860b57cec5SDimitry Andric ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
3870b57cec5SDimitry Andric assert(isVar() || isTmp() || isState());
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric if (isVar())
3900b57cec5SDimitry Andric return StateMap->getState(Var);
3910b57cec5SDimitry Andric else if (isTmp())
3920b57cec5SDimitry Andric return StateMap->getState(Tmp);
3930b57cec5SDimitry Andric else if (isState())
3940b57cec5SDimitry Andric return State;
3950b57cec5SDimitry Andric else
3960b57cec5SDimitry Andric return CS_None;
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric
testEffectiveOp() const3990b57cec5SDimitry Andric EffectiveOp testEffectiveOp() const {
4000b57cec5SDimitry Andric assert(InfoType == IT_BinTest);
4010b57cec5SDimitry Andric return BinTest.EOp;
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric
testSourceNode() const4040b57cec5SDimitry Andric const BinaryOperator * testSourceNode() const {
4050b57cec5SDimitry Andric assert(InfoType == IT_BinTest);
4060b57cec5SDimitry Andric return BinTest.Source;
4070b57cec5SDimitry Andric }
4080b57cec5SDimitry Andric
isValid() const4090b57cec5SDimitry Andric bool isValid() const { return InfoType != IT_None; }
isState() const4100b57cec5SDimitry Andric bool isState() const { return InfoType == IT_State; }
isVarTest() const4110b57cec5SDimitry Andric bool isVarTest() const { return InfoType == IT_VarTest; }
isBinTest() const4120b57cec5SDimitry Andric bool isBinTest() const { return InfoType == IT_BinTest; }
isVar() const4130b57cec5SDimitry Andric bool isVar() const { return InfoType == IT_Var; }
isTmp() const4140b57cec5SDimitry Andric bool isTmp() const { return InfoType == IT_Tmp; }
4150b57cec5SDimitry Andric
isTest() const4160b57cec5SDimitry Andric bool isTest() const {
4170b57cec5SDimitry Andric return InfoType == IT_VarTest || InfoType == IT_BinTest;
4180b57cec5SDimitry Andric }
4190b57cec5SDimitry Andric
isPointerToValue() const4200b57cec5SDimitry Andric bool isPointerToValue() const {
4210b57cec5SDimitry Andric return InfoType == IT_Var || InfoType == IT_Tmp;
4220b57cec5SDimitry Andric }
4230b57cec5SDimitry Andric
invertTest() const4240b57cec5SDimitry Andric PropagationInfo invertTest() const {
4250b57cec5SDimitry Andric assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
4260b57cec5SDimitry Andric
4270b57cec5SDimitry Andric if (InfoType == IT_VarTest) {
4280b57cec5SDimitry Andric return PropagationInfo(VarTest.Var,
4290b57cec5SDimitry Andric invertConsumedUnconsumed(VarTest.TestsFor));
4300b57cec5SDimitry Andric
4310b57cec5SDimitry Andric } else if (InfoType == IT_BinTest) {
4320b57cec5SDimitry Andric return PropagationInfo(BinTest.Source,
4330b57cec5SDimitry Andric BinTest.EOp == EO_And ? EO_Or : EO_And,
4340b57cec5SDimitry Andric BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
4350b57cec5SDimitry Andric BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
4360b57cec5SDimitry Andric } else {
4370b57cec5SDimitry Andric return {};
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric }
4400b57cec5SDimitry Andric };
4410b57cec5SDimitry Andric
4420b57cec5SDimitry Andric } // namespace consumed
4430b57cec5SDimitry Andric } // namespace clang
4440b57cec5SDimitry Andric
4450b57cec5SDimitry Andric static void
setStateForVarOrTmp(ConsumedStateMap * StateMap,const PropagationInfo & PInfo,ConsumedState State)4460b57cec5SDimitry Andric setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
4470b57cec5SDimitry Andric ConsumedState State) {
4480b57cec5SDimitry Andric assert(PInfo.isVar() || PInfo.isTmp());
4490b57cec5SDimitry Andric
4500b57cec5SDimitry Andric if (PInfo.isVar())
4510b57cec5SDimitry Andric StateMap->setState(PInfo.getVar(), State);
4520b57cec5SDimitry Andric else
4530b57cec5SDimitry Andric StateMap->setState(PInfo.getTmp(), State);
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric
4560b57cec5SDimitry Andric namespace clang {
4570b57cec5SDimitry Andric namespace consumed {
4580b57cec5SDimitry Andric
4590b57cec5SDimitry Andric class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
4600b57cec5SDimitry Andric using MapType = llvm::DenseMap<const Stmt *, PropagationInfo>;
4610b57cec5SDimitry Andric using PairType= std::pair<const Stmt *, PropagationInfo>;
4620b57cec5SDimitry Andric using InfoEntry = MapType::iterator;
4630b57cec5SDimitry Andric using ConstInfoEntry = MapType::const_iterator;
4640b57cec5SDimitry Andric
4650b57cec5SDimitry Andric ConsumedAnalyzer &Analyzer;
4660b57cec5SDimitry Andric ConsumedStateMap *StateMap;
4670b57cec5SDimitry Andric MapType PropagationMap;
4680b57cec5SDimitry Andric
findInfo(const Expr * E)4690b57cec5SDimitry Andric InfoEntry findInfo(const Expr *E) {
4700b57cec5SDimitry Andric if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
4710b57cec5SDimitry Andric if (!Cleanups->cleanupsHaveSideEffects())
4720b57cec5SDimitry Andric E = Cleanups->getSubExpr();
4730b57cec5SDimitry Andric return PropagationMap.find(E->IgnoreParens());
4740b57cec5SDimitry Andric }
4750b57cec5SDimitry Andric
findInfo(const Expr * E) const4760b57cec5SDimitry Andric ConstInfoEntry findInfo(const Expr *E) const {
4770b57cec5SDimitry Andric if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
4780b57cec5SDimitry Andric if (!Cleanups->cleanupsHaveSideEffects())
4790b57cec5SDimitry Andric E = Cleanups->getSubExpr();
4800b57cec5SDimitry Andric return PropagationMap.find(E->IgnoreParens());
4810b57cec5SDimitry Andric }
4820b57cec5SDimitry Andric
insertInfo(const Expr * E,const PropagationInfo & PI)4830b57cec5SDimitry Andric void insertInfo(const Expr *E, const PropagationInfo &PI) {
4840b57cec5SDimitry Andric PropagationMap.insert(PairType(E->IgnoreParens(), PI));
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric
4870b57cec5SDimitry Andric void forwardInfo(const Expr *From, const Expr *To);
4880b57cec5SDimitry Andric void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
4890b57cec5SDimitry Andric ConsumedState getInfo(const Expr *From);
4900b57cec5SDimitry Andric void setInfo(const Expr *To, ConsumedState NS);
4910b57cec5SDimitry Andric void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
4920b57cec5SDimitry Andric
4930b57cec5SDimitry Andric public:
4940b57cec5SDimitry Andric void checkCallability(const PropagationInfo &PInfo,
4950b57cec5SDimitry Andric const FunctionDecl *FunDecl,
4960b57cec5SDimitry Andric SourceLocation BlameLoc);
4970b57cec5SDimitry Andric bool handleCall(const CallExpr *Call, const Expr *ObjArg,
4980b57cec5SDimitry Andric const FunctionDecl *FunD);
4990b57cec5SDimitry Andric
5000b57cec5SDimitry Andric void VisitBinaryOperator(const BinaryOperator *BinOp);
5010b57cec5SDimitry Andric void VisitCallExpr(const CallExpr *Call);
5020b57cec5SDimitry Andric void VisitCastExpr(const CastExpr *Cast);
5030b57cec5SDimitry Andric void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
5040b57cec5SDimitry Andric void VisitCXXConstructExpr(const CXXConstructExpr *Call);
5050b57cec5SDimitry Andric void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
5060b57cec5SDimitry Andric void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
5070b57cec5SDimitry Andric void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
5080b57cec5SDimitry Andric void VisitDeclStmt(const DeclStmt *DelcS);
5090b57cec5SDimitry Andric void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
5100b57cec5SDimitry Andric void VisitMemberExpr(const MemberExpr *MExpr);
5110b57cec5SDimitry Andric void VisitParmVarDecl(const ParmVarDecl *Param);
5120b57cec5SDimitry Andric void VisitReturnStmt(const ReturnStmt *Ret);
5130b57cec5SDimitry Andric void VisitUnaryOperator(const UnaryOperator *UOp);
5140b57cec5SDimitry Andric void VisitVarDecl(const VarDecl *Var);
5150b57cec5SDimitry Andric
ConsumedStmtVisitor(ConsumedAnalyzer & Analyzer,ConsumedStateMap * StateMap)5160b57cec5SDimitry Andric ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap *StateMap)
5170b57cec5SDimitry Andric : Analyzer(Analyzer), StateMap(StateMap) {}
5180b57cec5SDimitry Andric
getInfo(const Expr * StmtNode) const5190b57cec5SDimitry Andric PropagationInfo getInfo(const Expr *StmtNode) const {
5200b57cec5SDimitry Andric ConstInfoEntry Entry = findInfo(StmtNode);
5210b57cec5SDimitry Andric
5220b57cec5SDimitry Andric if (Entry != PropagationMap.end())
5230b57cec5SDimitry Andric return Entry->second;
5240b57cec5SDimitry Andric else
5250b57cec5SDimitry Andric return {};
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric
reset(ConsumedStateMap * NewStateMap)5280b57cec5SDimitry Andric void reset(ConsumedStateMap *NewStateMap) {
5290b57cec5SDimitry Andric StateMap = NewStateMap;
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric };
5320b57cec5SDimitry Andric
5330b57cec5SDimitry Andric } // namespace consumed
5340b57cec5SDimitry Andric } // namespace clang
5350b57cec5SDimitry Andric
forwardInfo(const Expr * From,const Expr * To)5360b57cec5SDimitry Andric void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
5370b57cec5SDimitry Andric InfoEntry Entry = findInfo(From);
5380b57cec5SDimitry Andric if (Entry != PropagationMap.end())
5390b57cec5SDimitry Andric insertInfo(To, Entry->second);
5400b57cec5SDimitry Andric }
5410b57cec5SDimitry Andric
5420b57cec5SDimitry Andric // Create a new state for To, which is initialized to the state of From.
5430b57cec5SDimitry Andric // If NS is not CS_None, sets the state of From to NS.
copyInfo(const Expr * From,const Expr * To,ConsumedState NS)5440b57cec5SDimitry Andric void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
5450b57cec5SDimitry Andric ConsumedState NS) {
5460b57cec5SDimitry Andric InfoEntry Entry = findInfo(From);
5470b57cec5SDimitry Andric if (Entry != PropagationMap.end()) {
5480b57cec5SDimitry Andric PropagationInfo& PInfo = Entry->second;
5490b57cec5SDimitry Andric ConsumedState CS = PInfo.getAsState(StateMap);
5500b57cec5SDimitry Andric if (CS != CS_None)
5510b57cec5SDimitry Andric insertInfo(To, PropagationInfo(CS));
5520b57cec5SDimitry Andric if (NS != CS_None && PInfo.isPointerToValue())
5530b57cec5SDimitry Andric setStateForVarOrTmp(StateMap, PInfo, NS);
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
5570b57cec5SDimitry Andric // Get the ConsumedState for From
getInfo(const Expr * From)5580b57cec5SDimitry Andric ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
5590b57cec5SDimitry Andric InfoEntry Entry = findInfo(From);
5600b57cec5SDimitry Andric if (Entry != PropagationMap.end()) {
5610b57cec5SDimitry Andric PropagationInfo& PInfo = Entry->second;
5620b57cec5SDimitry Andric return PInfo.getAsState(StateMap);
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric return CS_None;
5650b57cec5SDimitry Andric }
5660b57cec5SDimitry Andric
5670b57cec5SDimitry Andric // If we already have info for To then update it, otherwise create a new entry.
setInfo(const Expr * To,ConsumedState NS)5680b57cec5SDimitry Andric void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
5690b57cec5SDimitry Andric InfoEntry Entry = findInfo(To);
5700b57cec5SDimitry Andric if (Entry != PropagationMap.end()) {
5710b57cec5SDimitry Andric PropagationInfo& PInfo = Entry->second;
5720b57cec5SDimitry Andric if (PInfo.isPointerToValue())
5730b57cec5SDimitry Andric setStateForVarOrTmp(StateMap, PInfo, NS);
5740b57cec5SDimitry Andric } else if (NS != CS_None) {
5750b57cec5SDimitry Andric insertInfo(To, PropagationInfo(NS));
5760b57cec5SDimitry Andric }
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric
checkCallability(const PropagationInfo & PInfo,const FunctionDecl * FunDecl,SourceLocation BlameLoc)5790b57cec5SDimitry Andric void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
5800b57cec5SDimitry Andric const FunctionDecl *FunDecl,
5810b57cec5SDimitry Andric SourceLocation BlameLoc) {
5820b57cec5SDimitry Andric assert(!PInfo.isTest());
5830b57cec5SDimitry Andric
5840b57cec5SDimitry Andric const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
5850b57cec5SDimitry Andric if (!CWAttr)
5860b57cec5SDimitry Andric return;
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric if (PInfo.isVar()) {
5890b57cec5SDimitry Andric ConsumedState VarState = StateMap->getState(PInfo.getVar());
5900b57cec5SDimitry Andric
5910b57cec5SDimitry Andric if (VarState == CS_None || isCallableInState(CWAttr, VarState))
5920b57cec5SDimitry Andric return;
5930b57cec5SDimitry Andric
5940b57cec5SDimitry Andric Analyzer.WarningsHandler.warnUseInInvalidState(
5950b57cec5SDimitry Andric FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
5960b57cec5SDimitry Andric stateToString(VarState), BlameLoc);
5970b57cec5SDimitry Andric } else {
5980b57cec5SDimitry Andric ConsumedState TmpState = PInfo.getAsState(StateMap);
5990b57cec5SDimitry Andric
6000b57cec5SDimitry Andric if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
6010b57cec5SDimitry Andric return;
6020b57cec5SDimitry Andric
6030b57cec5SDimitry Andric Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
6040b57cec5SDimitry Andric FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
6050b57cec5SDimitry Andric }
6060b57cec5SDimitry Andric }
6070b57cec5SDimitry Andric
6080b57cec5SDimitry Andric // Factors out common behavior for function, method, and operator calls.
6090b57cec5SDimitry Andric // Check parameters and set parameter state if necessary.
6100b57cec5SDimitry Andric // Returns true if the state of ObjArg is set, or false otherwise.
handleCall(const CallExpr * Call,const Expr * ObjArg,const FunctionDecl * FunD)6110b57cec5SDimitry Andric bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
6120b57cec5SDimitry Andric const FunctionDecl *FunD) {
6130b57cec5SDimitry Andric unsigned Offset = 0;
6140b57cec5SDimitry Andric if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
6150b57cec5SDimitry Andric Offset = 1; // first argument is 'this'
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric // check explicit parameters
6180b57cec5SDimitry Andric for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
6190b57cec5SDimitry Andric // Skip variable argument lists.
6200b57cec5SDimitry Andric if (Index - Offset >= FunD->getNumParams())
6210b57cec5SDimitry Andric break;
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
6240b57cec5SDimitry Andric QualType ParamType = Param->getType();
6250b57cec5SDimitry Andric
6260b57cec5SDimitry Andric InfoEntry Entry = findInfo(Call->getArg(Index));
6270b57cec5SDimitry Andric
6280b57cec5SDimitry Andric if (Entry == PropagationMap.end() || Entry->second.isTest())
6290b57cec5SDimitry Andric continue;
6300b57cec5SDimitry Andric PropagationInfo PInfo = Entry->second;
6310b57cec5SDimitry Andric
6320b57cec5SDimitry Andric // Check that the parameter is in the correct state.
6330b57cec5SDimitry Andric if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
6340b57cec5SDimitry Andric ConsumedState ParamState = PInfo.getAsState(StateMap);
6350b57cec5SDimitry Andric ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
6360b57cec5SDimitry Andric
6370b57cec5SDimitry Andric if (ParamState != ExpectedState)
6380b57cec5SDimitry Andric Analyzer.WarningsHandler.warnParamTypestateMismatch(
6390b57cec5SDimitry Andric Call->getArg(Index)->getExprLoc(),
6400b57cec5SDimitry Andric stateToString(ExpectedState), stateToString(ParamState));
6410b57cec5SDimitry Andric }
6420b57cec5SDimitry Andric
6430b57cec5SDimitry Andric if (!(Entry->second.isVar() || Entry->second.isTmp()))
6440b57cec5SDimitry Andric continue;
6450b57cec5SDimitry Andric
6460b57cec5SDimitry Andric // Adjust state on the caller side.
647a7dea167SDimitry Andric if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
6480b57cec5SDimitry Andric setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
649a7dea167SDimitry Andric else if (isRValueRef(ParamType) || isConsumableType(ParamType))
650a7dea167SDimitry Andric setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
6510b57cec5SDimitry Andric else if (isPointerOrRef(ParamType) &&
6520b57cec5SDimitry Andric (!ParamType->getPointeeType().isConstQualified() ||
6530b57cec5SDimitry Andric isSetOnReadPtrType(ParamType)))
6540b57cec5SDimitry Andric setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
6550b57cec5SDimitry Andric }
6560b57cec5SDimitry Andric
6570b57cec5SDimitry Andric if (!ObjArg)
6580b57cec5SDimitry Andric return false;
6590b57cec5SDimitry Andric
6600b57cec5SDimitry Andric // check implicit 'self' parameter, if present
6610b57cec5SDimitry Andric InfoEntry Entry = findInfo(ObjArg);
6620b57cec5SDimitry Andric if (Entry != PropagationMap.end()) {
6630b57cec5SDimitry Andric PropagationInfo PInfo = Entry->second;
6640b57cec5SDimitry Andric checkCallability(PInfo, FunD, Call->getExprLoc());
6650b57cec5SDimitry Andric
6660b57cec5SDimitry Andric if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
6670b57cec5SDimitry Andric if (PInfo.isVar()) {
6680b57cec5SDimitry Andric StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
6690b57cec5SDimitry Andric return true;
6700b57cec5SDimitry Andric }
6710b57cec5SDimitry Andric else if (PInfo.isTmp()) {
6720b57cec5SDimitry Andric StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
6730b57cec5SDimitry Andric return true;
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric }
6760b57cec5SDimitry Andric else if (isTestingFunction(FunD) && PInfo.isVar()) {
6770b57cec5SDimitry Andric PropagationMap.insert(PairType(Call,
6780b57cec5SDimitry Andric PropagationInfo(PInfo.getVar(), testsFor(FunD))));
6790b57cec5SDimitry Andric }
6800b57cec5SDimitry Andric }
6810b57cec5SDimitry Andric return false;
6820b57cec5SDimitry Andric }
6830b57cec5SDimitry Andric
propagateReturnType(const Expr * Call,const FunctionDecl * Fun)6840b57cec5SDimitry Andric void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
6850b57cec5SDimitry Andric const FunctionDecl *Fun) {
6860b57cec5SDimitry Andric QualType RetType = Fun->getCallResultType();
6870b57cec5SDimitry Andric if (RetType->isReferenceType())
6880b57cec5SDimitry Andric RetType = RetType->getPointeeType();
6890b57cec5SDimitry Andric
6900b57cec5SDimitry Andric if (isConsumableType(RetType)) {
6910b57cec5SDimitry Andric ConsumedState ReturnState;
6920b57cec5SDimitry Andric if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
6930b57cec5SDimitry Andric ReturnState = mapReturnTypestateAttrState(RTA);
6940b57cec5SDimitry Andric else
6950b57cec5SDimitry Andric ReturnState = mapConsumableAttrState(RetType);
6960b57cec5SDimitry Andric
6970b57cec5SDimitry Andric PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
6980b57cec5SDimitry Andric }
6990b57cec5SDimitry Andric }
7000b57cec5SDimitry Andric
VisitBinaryOperator(const BinaryOperator * BinOp)7010b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
7020b57cec5SDimitry Andric switch (BinOp->getOpcode()) {
7030b57cec5SDimitry Andric case BO_LAnd:
7040b57cec5SDimitry Andric case BO_LOr : {
7050b57cec5SDimitry Andric InfoEntry LEntry = findInfo(BinOp->getLHS()),
7060b57cec5SDimitry Andric REntry = findInfo(BinOp->getRHS());
7070b57cec5SDimitry Andric
7080b57cec5SDimitry Andric VarTestResult LTest, RTest;
7090b57cec5SDimitry Andric
7100b57cec5SDimitry Andric if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
7110b57cec5SDimitry Andric LTest = LEntry->second.getVarTest();
7120b57cec5SDimitry Andric } else {
7130b57cec5SDimitry Andric LTest.Var = nullptr;
7140b57cec5SDimitry Andric LTest.TestsFor = CS_None;
7150b57cec5SDimitry Andric }
7160b57cec5SDimitry Andric
7170b57cec5SDimitry Andric if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
7180b57cec5SDimitry Andric RTest = REntry->second.getVarTest();
7190b57cec5SDimitry Andric } else {
7200b57cec5SDimitry Andric RTest.Var = nullptr;
7210b57cec5SDimitry Andric RTest.TestsFor = CS_None;
7220b57cec5SDimitry Andric }
7230b57cec5SDimitry Andric
7240b57cec5SDimitry Andric if (!(LTest.Var == nullptr && RTest.Var == nullptr))
7250b57cec5SDimitry Andric PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
7260b57cec5SDimitry Andric static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
7270b57cec5SDimitry Andric break;
7280b57cec5SDimitry Andric }
7290b57cec5SDimitry Andric
7300b57cec5SDimitry Andric case BO_PtrMemD:
7310b57cec5SDimitry Andric case BO_PtrMemI:
7320b57cec5SDimitry Andric forwardInfo(BinOp->getLHS(), BinOp);
7330b57cec5SDimitry Andric break;
7340b57cec5SDimitry Andric
7350b57cec5SDimitry Andric default:
7360b57cec5SDimitry Andric break;
7370b57cec5SDimitry Andric }
7380b57cec5SDimitry Andric }
7390b57cec5SDimitry Andric
VisitCallExpr(const CallExpr * Call)7400b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
7410b57cec5SDimitry Andric const FunctionDecl *FunDecl = Call->getDirectCallee();
7420b57cec5SDimitry Andric if (!FunDecl)
7430b57cec5SDimitry Andric return;
7440b57cec5SDimitry Andric
7450b57cec5SDimitry Andric // Special case for the std::move function.
7460b57cec5SDimitry Andric // TODO: Make this more specific. (Deferred)
7470b57cec5SDimitry Andric if (Call->isCallToStdMove()) {
7480b57cec5SDimitry Andric copyInfo(Call->getArg(0), Call, CS_Consumed);
7490b57cec5SDimitry Andric return;
7500b57cec5SDimitry Andric }
7510b57cec5SDimitry Andric
7520b57cec5SDimitry Andric handleCall(Call, nullptr, FunDecl);
7530b57cec5SDimitry Andric propagateReturnType(Call, FunDecl);
7540b57cec5SDimitry Andric }
7550b57cec5SDimitry Andric
VisitCastExpr(const CastExpr * Cast)7560b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
7570b57cec5SDimitry Andric forwardInfo(Cast->getSubExpr(), Cast);
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * Temp)7600b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
7610b57cec5SDimitry Andric const CXXBindTemporaryExpr *Temp) {
7620b57cec5SDimitry Andric
7630b57cec5SDimitry Andric InfoEntry Entry = findInfo(Temp->getSubExpr());
7640b57cec5SDimitry Andric
7650b57cec5SDimitry Andric if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
7660b57cec5SDimitry Andric StateMap->setState(Temp, Entry->second.getAsState(StateMap));
7670b57cec5SDimitry Andric PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric }
7700b57cec5SDimitry Andric
VisitCXXConstructExpr(const CXXConstructExpr * Call)7710b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
7720b57cec5SDimitry Andric CXXConstructorDecl *Constructor = Call->getConstructor();
7730b57cec5SDimitry Andric
774*5f757f3fSDimitry Andric QualType ThisType = Constructor->getFunctionObjectParameterType();
7750b57cec5SDimitry Andric
7760b57cec5SDimitry Andric if (!isConsumableType(ThisType))
7770b57cec5SDimitry Andric return;
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric // FIXME: What should happen if someone annotates the move constructor?
7800b57cec5SDimitry Andric if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
7810b57cec5SDimitry Andric // TODO: Adjust state of args appropriately.
7820b57cec5SDimitry Andric ConsumedState RetState = mapReturnTypestateAttrState(RTA);
7830b57cec5SDimitry Andric PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
7840b57cec5SDimitry Andric } else if (Constructor->isDefaultConstructor()) {
7850b57cec5SDimitry Andric PropagationMap.insert(PairType(Call,
7860b57cec5SDimitry Andric PropagationInfo(consumed::CS_Consumed)));
7870b57cec5SDimitry Andric } else if (Constructor->isMoveConstructor()) {
7880b57cec5SDimitry Andric copyInfo(Call->getArg(0), Call, CS_Consumed);
7890b57cec5SDimitry Andric } else if (Constructor->isCopyConstructor()) {
7900b57cec5SDimitry Andric // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
7910b57cec5SDimitry Andric ConsumedState NS =
7920b57cec5SDimitry Andric isSetOnReadPtrType(Constructor->getThisType()) ?
7930b57cec5SDimitry Andric CS_Unknown : CS_None;
7940b57cec5SDimitry Andric copyInfo(Call->getArg(0), Call, NS);
7950b57cec5SDimitry Andric } else {
7960b57cec5SDimitry Andric // TODO: Adjust state of args appropriately.
7970b57cec5SDimitry Andric ConsumedState RetState = mapConsumableAttrState(ThisType);
7980b57cec5SDimitry Andric PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric
VisitCXXMemberCallExpr(const CXXMemberCallExpr * Call)8020b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
8030b57cec5SDimitry Andric const CXXMemberCallExpr *Call) {
8040b57cec5SDimitry Andric CXXMethodDecl* MD = Call->getMethodDecl();
8050b57cec5SDimitry Andric if (!MD)
8060b57cec5SDimitry Andric return;
8070b57cec5SDimitry Andric
8080b57cec5SDimitry Andric handleCall(Call, Call->getImplicitObjectArgument(), MD);
8090b57cec5SDimitry Andric propagateReturnType(Call, MD);
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric
VisitCXXOperatorCallExpr(const CXXOperatorCallExpr * Call)8120b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
8130b57cec5SDimitry Andric const CXXOperatorCallExpr *Call) {
8140b57cec5SDimitry Andric const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
8150b57cec5SDimitry Andric if (!FunDecl) return;
8160b57cec5SDimitry Andric
8170b57cec5SDimitry Andric if (Call->getOperator() == OO_Equal) {
8180b57cec5SDimitry Andric ConsumedState CS = getInfo(Call->getArg(1));
8190b57cec5SDimitry Andric if (!handleCall(Call, Call->getArg(0), FunDecl))
8200b57cec5SDimitry Andric setInfo(Call->getArg(0), CS);
8210b57cec5SDimitry Andric return;
8220b57cec5SDimitry Andric }
8230b57cec5SDimitry Andric
8240b57cec5SDimitry Andric if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
8250b57cec5SDimitry Andric handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
8260b57cec5SDimitry Andric else
8270b57cec5SDimitry Andric handleCall(Call, Call->getArg(0), FunDecl);
8280b57cec5SDimitry Andric
8290b57cec5SDimitry Andric propagateReturnType(Call, FunDecl);
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric
VisitDeclRefExpr(const DeclRefExpr * DeclRef)8320b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
8330b57cec5SDimitry Andric if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
8340b57cec5SDimitry Andric if (StateMap->getState(Var) != consumed::CS_None)
8350b57cec5SDimitry Andric PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
8360b57cec5SDimitry Andric }
8370b57cec5SDimitry Andric
VisitDeclStmt(const DeclStmt * DeclS)8380b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
8390b57cec5SDimitry Andric for (const auto *DI : DeclS->decls())
8400b57cec5SDimitry Andric if (isa<VarDecl>(DI))
8410b57cec5SDimitry Andric VisitVarDecl(cast<VarDecl>(DI));
8420b57cec5SDimitry Andric
8430b57cec5SDimitry Andric if (DeclS->isSingleDecl())
8440b57cec5SDimitry Andric if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
8450b57cec5SDimitry Andric PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric
VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * Temp)8480b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
8490b57cec5SDimitry Andric const MaterializeTemporaryExpr *Temp) {
850480093f4SDimitry Andric forwardInfo(Temp->getSubExpr(), Temp);
8510b57cec5SDimitry Andric }
8520b57cec5SDimitry Andric
VisitMemberExpr(const MemberExpr * MExpr)8530b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
8540b57cec5SDimitry Andric forwardInfo(MExpr->getBase(), MExpr);
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric
VisitParmVarDecl(const ParmVarDecl * Param)8570b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
8580b57cec5SDimitry Andric QualType ParamType = Param->getType();
8590b57cec5SDimitry Andric ConsumedState ParamState = consumed::CS_None;
8600b57cec5SDimitry Andric
8610b57cec5SDimitry Andric if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
8620b57cec5SDimitry Andric ParamState = mapParamTypestateAttrState(PTA);
8630b57cec5SDimitry Andric else if (isConsumableType(ParamType))
8640b57cec5SDimitry Andric ParamState = mapConsumableAttrState(ParamType);
8650b57cec5SDimitry Andric else if (isRValueRef(ParamType) &&
8660b57cec5SDimitry Andric isConsumableType(ParamType->getPointeeType()))
8670b57cec5SDimitry Andric ParamState = mapConsumableAttrState(ParamType->getPointeeType());
8680b57cec5SDimitry Andric else if (ParamType->isReferenceType() &&
8690b57cec5SDimitry Andric isConsumableType(ParamType->getPointeeType()))
8700b57cec5SDimitry Andric ParamState = consumed::CS_Unknown;
8710b57cec5SDimitry Andric
8720b57cec5SDimitry Andric if (ParamState != CS_None)
8730b57cec5SDimitry Andric StateMap->setState(Param, ParamState);
8740b57cec5SDimitry Andric }
8750b57cec5SDimitry Andric
VisitReturnStmt(const ReturnStmt * Ret)8760b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
8770b57cec5SDimitry Andric ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
8780b57cec5SDimitry Andric
8790b57cec5SDimitry Andric if (ExpectedState != CS_None) {
8800b57cec5SDimitry Andric InfoEntry Entry = findInfo(Ret->getRetValue());
8810b57cec5SDimitry Andric
8820b57cec5SDimitry Andric if (Entry != PropagationMap.end()) {
8830b57cec5SDimitry Andric ConsumedState RetState = Entry->second.getAsState(StateMap);
8840b57cec5SDimitry Andric
8850b57cec5SDimitry Andric if (RetState != ExpectedState)
8860b57cec5SDimitry Andric Analyzer.WarningsHandler.warnReturnTypestateMismatch(
8870b57cec5SDimitry Andric Ret->getReturnLoc(), stateToString(ExpectedState),
8880b57cec5SDimitry Andric stateToString(RetState));
8890b57cec5SDimitry Andric }
8900b57cec5SDimitry Andric }
8910b57cec5SDimitry Andric
8920b57cec5SDimitry Andric StateMap->checkParamsForReturnTypestate(Ret->getBeginLoc(),
8930b57cec5SDimitry Andric Analyzer.WarningsHandler);
8940b57cec5SDimitry Andric }
8950b57cec5SDimitry Andric
VisitUnaryOperator(const UnaryOperator * UOp)8960b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
8970b57cec5SDimitry Andric InfoEntry Entry = findInfo(UOp->getSubExpr());
8980b57cec5SDimitry Andric if (Entry == PropagationMap.end()) return;
8990b57cec5SDimitry Andric
9000b57cec5SDimitry Andric switch (UOp->getOpcode()) {
9010b57cec5SDimitry Andric case UO_AddrOf:
9020b57cec5SDimitry Andric PropagationMap.insert(PairType(UOp, Entry->second));
9030b57cec5SDimitry Andric break;
9040b57cec5SDimitry Andric
9050b57cec5SDimitry Andric case UO_LNot:
9060b57cec5SDimitry Andric if (Entry->second.isTest())
9070b57cec5SDimitry Andric PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
9080b57cec5SDimitry Andric break;
9090b57cec5SDimitry Andric
9100b57cec5SDimitry Andric default:
9110b57cec5SDimitry Andric break;
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric }
9140b57cec5SDimitry Andric
9150b57cec5SDimitry Andric // TODO: See if I need to check for reference types here.
VisitVarDecl(const VarDecl * Var)9160b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
9170b57cec5SDimitry Andric if (isConsumableType(Var->getType())) {
9180b57cec5SDimitry Andric if (Var->hasInit()) {
9190b57cec5SDimitry Andric MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
9200b57cec5SDimitry Andric if (VIT != PropagationMap.end()) {
9210b57cec5SDimitry Andric PropagationInfo PInfo = VIT->second;
9220b57cec5SDimitry Andric ConsumedState St = PInfo.getAsState(StateMap);
9230b57cec5SDimitry Andric
9240b57cec5SDimitry Andric if (St != consumed::CS_None) {
9250b57cec5SDimitry Andric StateMap->setState(Var, St);
9260b57cec5SDimitry Andric return;
9270b57cec5SDimitry Andric }
9280b57cec5SDimitry Andric }
9290b57cec5SDimitry Andric }
9300b57cec5SDimitry Andric // Otherwise
9310b57cec5SDimitry Andric StateMap->setState(Var, consumed::CS_Unknown);
9320b57cec5SDimitry Andric }
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric
splitVarStateForIf(const IfStmt * IfNode,const VarTestResult & Test,ConsumedStateMap * ThenStates,ConsumedStateMap * ElseStates)9350b57cec5SDimitry Andric static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
9360b57cec5SDimitry Andric ConsumedStateMap *ThenStates,
9370b57cec5SDimitry Andric ConsumedStateMap *ElseStates) {
9380b57cec5SDimitry Andric ConsumedState VarState = ThenStates->getState(Test.Var);
9390b57cec5SDimitry Andric
9400b57cec5SDimitry Andric if (VarState == CS_Unknown) {
9410b57cec5SDimitry Andric ThenStates->setState(Test.Var, Test.TestsFor);
9420b57cec5SDimitry Andric ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
9430b57cec5SDimitry Andric } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
9440b57cec5SDimitry Andric ThenStates->markUnreachable();
9450b57cec5SDimitry Andric } else if (VarState == Test.TestsFor) {
9460b57cec5SDimitry Andric ElseStates->markUnreachable();
9470b57cec5SDimitry Andric }
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric
splitVarStateForIfBinOp(const PropagationInfo & PInfo,ConsumedStateMap * ThenStates,ConsumedStateMap * ElseStates)9500b57cec5SDimitry Andric static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
9510b57cec5SDimitry Andric ConsumedStateMap *ThenStates,
9520b57cec5SDimitry Andric ConsumedStateMap *ElseStates) {
9530b57cec5SDimitry Andric const VarTestResult <est = PInfo.getLTest(),
9540b57cec5SDimitry Andric &RTest = PInfo.getRTest();
9550b57cec5SDimitry Andric
9560b57cec5SDimitry Andric ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
9570b57cec5SDimitry Andric RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
9580b57cec5SDimitry Andric
9590b57cec5SDimitry Andric if (LTest.Var) {
9600b57cec5SDimitry Andric if (PInfo.testEffectiveOp() == EO_And) {
9610b57cec5SDimitry Andric if (LState == CS_Unknown) {
9620b57cec5SDimitry Andric ThenStates->setState(LTest.Var, LTest.TestsFor);
9630b57cec5SDimitry Andric } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
9640b57cec5SDimitry Andric ThenStates->markUnreachable();
9650b57cec5SDimitry Andric } else if (LState == LTest.TestsFor && isKnownState(RState)) {
9660b57cec5SDimitry Andric if (RState == RTest.TestsFor)
9670b57cec5SDimitry Andric ElseStates->markUnreachable();
9680b57cec5SDimitry Andric else
9690b57cec5SDimitry Andric ThenStates->markUnreachable();
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric } else {
9720b57cec5SDimitry Andric if (LState == CS_Unknown) {
9730b57cec5SDimitry Andric ElseStates->setState(LTest.Var,
9740b57cec5SDimitry Andric invertConsumedUnconsumed(LTest.TestsFor));
9750b57cec5SDimitry Andric } else if (LState == LTest.TestsFor) {
9760b57cec5SDimitry Andric ElseStates->markUnreachable();
9770b57cec5SDimitry Andric } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
9780b57cec5SDimitry Andric isKnownState(RState)) {
9790b57cec5SDimitry Andric if (RState == RTest.TestsFor)
9800b57cec5SDimitry Andric ElseStates->markUnreachable();
9810b57cec5SDimitry Andric else
9820b57cec5SDimitry Andric ThenStates->markUnreachable();
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric }
9850b57cec5SDimitry Andric }
9860b57cec5SDimitry Andric
9870b57cec5SDimitry Andric if (RTest.Var) {
9880b57cec5SDimitry Andric if (PInfo.testEffectiveOp() == EO_And) {
9890b57cec5SDimitry Andric if (RState == CS_Unknown)
9900b57cec5SDimitry Andric ThenStates->setState(RTest.Var, RTest.TestsFor);
9910b57cec5SDimitry Andric else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
9920b57cec5SDimitry Andric ThenStates->markUnreachable();
9930b57cec5SDimitry Andric } else {
9940b57cec5SDimitry Andric if (RState == CS_Unknown)
9950b57cec5SDimitry Andric ElseStates->setState(RTest.Var,
9960b57cec5SDimitry Andric invertConsumedUnconsumed(RTest.TestsFor));
9970b57cec5SDimitry Andric else if (RState == RTest.TestsFor)
9980b57cec5SDimitry Andric ElseStates->markUnreachable();
9990b57cec5SDimitry Andric }
10000b57cec5SDimitry Andric }
10010b57cec5SDimitry Andric }
10020b57cec5SDimitry Andric
allBackEdgesVisited(const CFGBlock * CurrBlock,const CFGBlock * TargetBlock)10030b57cec5SDimitry Andric bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
10040b57cec5SDimitry Andric const CFGBlock *TargetBlock) {
10050b57cec5SDimitry Andric assert(CurrBlock && "Block pointer must not be NULL");
10060b57cec5SDimitry Andric assert(TargetBlock && "TargetBlock pointer must not be NULL");
10070b57cec5SDimitry Andric
10080b57cec5SDimitry Andric unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
10090b57cec5SDimitry Andric for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
10100b57cec5SDimitry Andric PE = TargetBlock->pred_end(); PI != PE; ++PI) {
10110b57cec5SDimitry Andric if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
10120b57cec5SDimitry Andric return false;
10130b57cec5SDimitry Andric }
10140b57cec5SDimitry Andric return true;
10150b57cec5SDimitry Andric }
10160b57cec5SDimitry Andric
addInfo(const CFGBlock * Block,ConsumedStateMap * StateMap,std::unique_ptr<ConsumedStateMap> & OwnedStateMap)10170b57cec5SDimitry Andric void ConsumedBlockInfo::addInfo(
10180b57cec5SDimitry Andric const CFGBlock *Block, ConsumedStateMap *StateMap,
10190b57cec5SDimitry Andric std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
10200b57cec5SDimitry Andric assert(Block && "Block pointer must not be NULL");
10210b57cec5SDimitry Andric
10220b57cec5SDimitry Andric auto &Entry = StateMapsArray[Block->getBlockID()];
10230b57cec5SDimitry Andric
10240b57cec5SDimitry Andric if (Entry) {
10250b57cec5SDimitry Andric Entry->intersect(*StateMap);
10260b57cec5SDimitry Andric } else if (OwnedStateMap)
10270b57cec5SDimitry Andric Entry = std::move(OwnedStateMap);
10280b57cec5SDimitry Andric else
1029a7dea167SDimitry Andric Entry = std::make_unique<ConsumedStateMap>(*StateMap);
10300b57cec5SDimitry Andric }
10310b57cec5SDimitry Andric
addInfo(const CFGBlock * Block,std::unique_ptr<ConsumedStateMap> StateMap)10320b57cec5SDimitry Andric void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
10330b57cec5SDimitry Andric std::unique_ptr<ConsumedStateMap> StateMap) {
10340b57cec5SDimitry Andric assert(Block && "Block pointer must not be NULL");
10350b57cec5SDimitry Andric
10360b57cec5SDimitry Andric auto &Entry = StateMapsArray[Block->getBlockID()];
10370b57cec5SDimitry Andric
10380b57cec5SDimitry Andric if (Entry) {
10390b57cec5SDimitry Andric Entry->intersect(*StateMap);
10400b57cec5SDimitry Andric } else {
10410b57cec5SDimitry Andric Entry = std::move(StateMap);
10420b57cec5SDimitry Andric }
10430b57cec5SDimitry Andric }
10440b57cec5SDimitry Andric
borrowInfo(const CFGBlock * Block)10450b57cec5SDimitry Andric ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
10460b57cec5SDimitry Andric assert(Block && "Block pointer must not be NULL");
10470b57cec5SDimitry Andric assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
10480b57cec5SDimitry Andric
10490b57cec5SDimitry Andric return StateMapsArray[Block->getBlockID()].get();
10500b57cec5SDimitry Andric }
10510b57cec5SDimitry Andric
discardInfo(const CFGBlock * Block)10520b57cec5SDimitry Andric void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
10530b57cec5SDimitry Andric StateMapsArray[Block->getBlockID()] = nullptr;
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric
10560b57cec5SDimitry Andric std::unique_ptr<ConsumedStateMap>
getInfo(const CFGBlock * Block)10570b57cec5SDimitry Andric ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
10580b57cec5SDimitry Andric assert(Block && "Block pointer must not be NULL");
10590b57cec5SDimitry Andric
10600b57cec5SDimitry Andric auto &Entry = StateMapsArray[Block->getBlockID()];
1061a7dea167SDimitry Andric return isBackEdgeTarget(Block) ? std::make_unique<ConsumedStateMap>(*Entry)
10620b57cec5SDimitry Andric : std::move(Entry);
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric
isBackEdge(const CFGBlock * From,const CFGBlock * To)10650b57cec5SDimitry Andric bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
10660b57cec5SDimitry Andric assert(From && "From block must not be NULL");
10670b57cec5SDimitry Andric assert(To && "From block must not be NULL");
10680b57cec5SDimitry Andric
10690b57cec5SDimitry Andric return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
10700b57cec5SDimitry Andric }
10710b57cec5SDimitry Andric
isBackEdgeTarget(const CFGBlock * Block)10720b57cec5SDimitry Andric bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
10730b57cec5SDimitry Andric assert(Block && "Block pointer must not be NULL");
10740b57cec5SDimitry Andric
10750b57cec5SDimitry Andric // Anything with less than two predecessors can't be the target of a back
10760b57cec5SDimitry Andric // edge.
10770b57cec5SDimitry Andric if (Block->pred_size() < 2)
10780b57cec5SDimitry Andric return false;
10790b57cec5SDimitry Andric
10800b57cec5SDimitry Andric unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
10810b57cec5SDimitry Andric for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
10820b57cec5SDimitry Andric PE = Block->pred_end(); PI != PE; ++PI) {
10830b57cec5SDimitry Andric if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
10840b57cec5SDimitry Andric return true;
10850b57cec5SDimitry Andric }
10860b57cec5SDimitry Andric return false;
10870b57cec5SDimitry Andric }
10880b57cec5SDimitry Andric
checkParamsForReturnTypestate(SourceLocation BlameLoc,ConsumedWarningsHandlerBase & WarningsHandler) const10890b57cec5SDimitry Andric void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
10900b57cec5SDimitry Andric ConsumedWarningsHandlerBase &WarningsHandler) const {
10910b57cec5SDimitry Andric
10920b57cec5SDimitry Andric for (const auto &DM : VarMap) {
10930b57cec5SDimitry Andric if (isa<ParmVarDecl>(DM.first)) {
10940b57cec5SDimitry Andric const auto *Param = cast<ParmVarDecl>(DM.first);
10950b57cec5SDimitry Andric const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
10960b57cec5SDimitry Andric
10970b57cec5SDimitry Andric if (!RTA)
10980b57cec5SDimitry Andric continue;
10990b57cec5SDimitry Andric
11000b57cec5SDimitry Andric ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
11010b57cec5SDimitry Andric if (DM.second != ExpectedState)
11020b57cec5SDimitry Andric WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
11030b57cec5SDimitry Andric Param->getNameAsString(), stateToString(ExpectedState),
11040b57cec5SDimitry Andric stateToString(DM.second));
11050b57cec5SDimitry Andric }
11060b57cec5SDimitry Andric }
11070b57cec5SDimitry Andric }
11080b57cec5SDimitry Andric
clearTemporaries()11090b57cec5SDimitry Andric void ConsumedStateMap::clearTemporaries() {
11100b57cec5SDimitry Andric TmpMap.clear();
11110b57cec5SDimitry Andric }
11120b57cec5SDimitry Andric
getState(const VarDecl * Var) const11130b57cec5SDimitry Andric ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
11140b57cec5SDimitry Andric VarMapType::const_iterator Entry = VarMap.find(Var);
11150b57cec5SDimitry Andric
11160b57cec5SDimitry Andric if (Entry != VarMap.end())
11170b57cec5SDimitry Andric return Entry->second;
11180b57cec5SDimitry Andric
11190b57cec5SDimitry Andric return CS_None;
11200b57cec5SDimitry Andric }
11210b57cec5SDimitry Andric
11220b57cec5SDimitry Andric ConsumedState
getState(const CXXBindTemporaryExpr * Tmp) const11230b57cec5SDimitry Andric ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
11240b57cec5SDimitry Andric TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
11250b57cec5SDimitry Andric
11260b57cec5SDimitry Andric if (Entry != TmpMap.end())
11270b57cec5SDimitry Andric return Entry->second;
11280b57cec5SDimitry Andric
11290b57cec5SDimitry Andric return CS_None;
11300b57cec5SDimitry Andric }
11310b57cec5SDimitry Andric
intersect(const ConsumedStateMap & Other)11320b57cec5SDimitry Andric void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
11330b57cec5SDimitry Andric ConsumedState LocalState;
11340b57cec5SDimitry Andric
11350b57cec5SDimitry Andric if (this->From && this->From == Other.From && !Other.Reachable) {
11360b57cec5SDimitry Andric this->markUnreachable();
11370b57cec5SDimitry Andric return;
11380b57cec5SDimitry Andric }
11390b57cec5SDimitry Andric
11400b57cec5SDimitry Andric for (const auto &DM : Other.VarMap) {
11410b57cec5SDimitry Andric LocalState = this->getState(DM.first);
11420b57cec5SDimitry Andric
11430b57cec5SDimitry Andric if (LocalState == CS_None)
11440b57cec5SDimitry Andric continue;
11450b57cec5SDimitry Andric
11460b57cec5SDimitry Andric if (LocalState != DM.second)
11470b57cec5SDimitry Andric VarMap[DM.first] = CS_Unknown;
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric }
11500b57cec5SDimitry Andric
intersectAtLoopHead(const CFGBlock * LoopHead,const CFGBlock * LoopBack,const ConsumedStateMap * LoopBackStates,ConsumedWarningsHandlerBase & WarningsHandler)11510b57cec5SDimitry Andric void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
11520b57cec5SDimitry Andric const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
11530b57cec5SDimitry Andric ConsumedWarningsHandlerBase &WarningsHandler) {
11540b57cec5SDimitry Andric
11550b57cec5SDimitry Andric ConsumedState LocalState;
11560b57cec5SDimitry Andric SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
11570b57cec5SDimitry Andric
11580b57cec5SDimitry Andric for (const auto &DM : LoopBackStates->VarMap) {
11590b57cec5SDimitry Andric LocalState = this->getState(DM.first);
11600b57cec5SDimitry Andric
11610b57cec5SDimitry Andric if (LocalState == CS_None)
11620b57cec5SDimitry Andric continue;
11630b57cec5SDimitry Andric
11640b57cec5SDimitry Andric if (LocalState != DM.second) {
11650b57cec5SDimitry Andric VarMap[DM.first] = CS_Unknown;
11660b57cec5SDimitry Andric WarningsHandler.warnLoopStateMismatch(BlameLoc,
11670b57cec5SDimitry Andric DM.first->getNameAsString());
11680b57cec5SDimitry Andric }
11690b57cec5SDimitry Andric }
11700b57cec5SDimitry Andric }
11710b57cec5SDimitry Andric
markUnreachable()11720b57cec5SDimitry Andric void ConsumedStateMap::markUnreachable() {
11730b57cec5SDimitry Andric this->Reachable = false;
11740b57cec5SDimitry Andric VarMap.clear();
11750b57cec5SDimitry Andric TmpMap.clear();
11760b57cec5SDimitry Andric }
11770b57cec5SDimitry Andric
setState(const VarDecl * Var,ConsumedState State)11780b57cec5SDimitry Andric void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
11790b57cec5SDimitry Andric VarMap[Var] = State;
11800b57cec5SDimitry Andric }
11810b57cec5SDimitry Andric
setState(const CXXBindTemporaryExpr * Tmp,ConsumedState State)11820b57cec5SDimitry Andric void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
11830b57cec5SDimitry Andric ConsumedState State) {
11840b57cec5SDimitry Andric TmpMap[Tmp] = State;
11850b57cec5SDimitry Andric }
11860b57cec5SDimitry Andric
remove(const CXXBindTemporaryExpr * Tmp)11870b57cec5SDimitry Andric void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
11880b57cec5SDimitry Andric TmpMap.erase(Tmp);
11890b57cec5SDimitry Andric }
11900b57cec5SDimitry Andric
operator !=(const ConsumedStateMap * Other) const11910b57cec5SDimitry Andric bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
11920b57cec5SDimitry Andric for (const auto &DM : Other->VarMap)
11930b57cec5SDimitry Andric if (this->getState(DM.first) != DM.second)
11940b57cec5SDimitry Andric return true;
11950b57cec5SDimitry Andric return false;
11960b57cec5SDimitry Andric }
11970b57cec5SDimitry Andric
determineExpectedReturnState(AnalysisDeclContext & AC,const FunctionDecl * D)11980b57cec5SDimitry Andric void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
11990b57cec5SDimitry Andric const FunctionDecl *D) {
12000b57cec5SDimitry Andric QualType ReturnType;
12010b57cec5SDimitry Andric if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1202*5f757f3fSDimitry Andric ReturnType = Constructor->getFunctionObjectParameterType();
12030b57cec5SDimitry Andric } else
12040b57cec5SDimitry Andric ReturnType = D->getCallResultType();
12050b57cec5SDimitry Andric
12060b57cec5SDimitry Andric if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
12070b57cec5SDimitry Andric const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
12080b57cec5SDimitry Andric if (!RD || !RD->hasAttr<ConsumableAttr>()) {
12090b57cec5SDimitry Andric // FIXME: This should be removed when template instantiation propagates
12100b57cec5SDimitry Andric // attributes at template specialization definition, not
12110b57cec5SDimitry Andric // declaration. When it is removed the test needs to be enabled
12120b57cec5SDimitry Andric // in SemaDeclAttr.cpp.
12130b57cec5SDimitry Andric WarningsHandler.warnReturnTypestateForUnconsumableType(
12140b57cec5SDimitry Andric RTSAttr->getLocation(), ReturnType.getAsString());
12150b57cec5SDimitry Andric ExpectedReturnState = CS_None;
12160b57cec5SDimitry Andric } else
12170b57cec5SDimitry Andric ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
12180b57cec5SDimitry Andric } else if (isConsumableType(ReturnType)) {
12190b57cec5SDimitry Andric if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
12200b57cec5SDimitry Andric ExpectedReturnState = CS_None; // expected state.
12210b57cec5SDimitry Andric else
12220b57cec5SDimitry Andric ExpectedReturnState = mapConsumableAttrState(ReturnType);
12230b57cec5SDimitry Andric }
12240b57cec5SDimitry Andric else
12250b57cec5SDimitry Andric ExpectedReturnState = CS_None;
12260b57cec5SDimitry Andric }
12270b57cec5SDimitry Andric
splitState(const CFGBlock * CurrBlock,const ConsumedStmtVisitor & Visitor)12280b57cec5SDimitry Andric bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
12290b57cec5SDimitry Andric const ConsumedStmtVisitor &Visitor) {
12300b57cec5SDimitry Andric std::unique_ptr<ConsumedStateMap> FalseStates(
12310b57cec5SDimitry Andric new ConsumedStateMap(*CurrStates));
12320b57cec5SDimitry Andric PropagationInfo PInfo;
12330b57cec5SDimitry Andric
12340b57cec5SDimitry Andric if (const auto *IfNode =
12350b57cec5SDimitry Andric dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
12360b57cec5SDimitry Andric const Expr *Cond = IfNode->getCond();
12370b57cec5SDimitry Andric
12380b57cec5SDimitry Andric PInfo = Visitor.getInfo(Cond);
12390b57cec5SDimitry Andric if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
12400b57cec5SDimitry Andric PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
12410b57cec5SDimitry Andric
12420b57cec5SDimitry Andric if (PInfo.isVarTest()) {
12430b57cec5SDimitry Andric CurrStates->setSource(Cond);
12440b57cec5SDimitry Andric FalseStates->setSource(Cond);
12450b57cec5SDimitry Andric splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
12460b57cec5SDimitry Andric FalseStates.get());
12470b57cec5SDimitry Andric } else if (PInfo.isBinTest()) {
12480b57cec5SDimitry Andric CurrStates->setSource(PInfo.testSourceNode());
12490b57cec5SDimitry Andric FalseStates->setSource(PInfo.testSourceNode());
12500b57cec5SDimitry Andric splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
12510b57cec5SDimitry Andric } else {
12520b57cec5SDimitry Andric return false;
12530b57cec5SDimitry Andric }
12540b57cec5SDimitry Andric } else if (const auto *BinOp =
12550b57cec5SDimitry Andric dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
12560b57cec5SDimitry Andric PInfo = Visitor.getInfo(BinOp->getLHS());
12570b57cec5SDimitry Andric if (!PInfo.isVarTest()) {
12580b57cec5SDimitry Andric if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
12590b57cec5SDimitry Andric PInfo = Visitor.getInfo(BinOp->getRHS());
12600b57cec5SDimitry Andric
12610b57cec5SDimitry Andric if (!PInfo.isVarTest())
12620b57cec5SDimitry Andric return false;
12630b57cec5SDimitry Andric } else {
12640b57cec5SDimitry Andric return false;
12650b57cec5SDimitry Andric }
12660b57cec5SDimitry Andric }
12670b57cec5SDimitry Andric
12680b57cec5SDimitry Andric CurrStates->setSource(BinOp);
12690b57cec5SDimitry Andric FalseStates->setSource(BinOp);
12700b57cec5SDimitry Andric
12710b57cec5SDimitry Andric const VarTestResult &Test = PInfo.getVarTest();
12720b57cec5SDimitry Andric ConsumedState VarState = CurrStates->getState(Test.Var);
12730b57cec5SDimitry Andric
12740b57cec5SDimitry Andric if (BinOp->getOpcode() == BO_LAnd) {
12750b57cec5SDimitry Andric if (VarState == CS_Unknown)
12760b57cec5SDimitry Andric CurrStates->setState(Test.Var, Test.TestsFor);
12770b57cec5SDimitry Andric else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
12780b57cec5SDimitry Andric CurrStates->markUnreachable();
12790b57cec5SDimitry Andric
12800b57cec5SDimitry Andric } else if (BinOp->getOpcode() == BO_LOr) {
12810b57cec5SDimitry Andric if (VarState == CS_Unknown)
12820b57cec5SDimitry Andric FalseStates->setState(Test.Var,
12830b57cec5SDimitry Andric invertConsumedUnconsumed(Test.TestsFor));
12840b57cec5SDimitry Andric else if (VarState == Test.TestsFor)
12850b57cec5SDimitry Andric FalseStates->markUnreachable();
12860b57cec5SDimitry Andric }
12870b57cec5SDimitry Andric } else {
12880b57cec5SDimitry Andric return false;
12890b57cec5SDimitry Andric }
12900b57cec5SDimitry Andric
12910b57cec5SDimitry Andric CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
12920b57cec5SDimitry Andric
12930b57cec5SDimitry Andric if (*SI)
12940b57cec5SDimitry Andric BlockInfo.addInfo(*SI, std::move(CurrStates));
12950b57cec5SDimitry Andric else
12960b57cec5SDimitry Andric CurrStates = nullptr;
12970b57cec5SDimitry Andric
12980b57cec5SDimitry Andric if (*++SI)
12990b57cec5SDimitry Andric BlockInfo.addInfo(*SI, std::move(FalseStates));
13000b57cec5SDimitry Andric
13010b57cec5SDimitry Andric return true;
13020b57cec5SDimitry Andric }
13030b57cec5SDimitry Andric
run(AnalysisDeclContext & AC)13040b57cec5SDimitry Andric void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
13050b57cec5SDimitry Andric const auto *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
13060b57cec5SDimitry Andric if (!D)
13070b57cec5SDimitry Andric return;
13080b57cec5SDimitry Andric
13090b57cec5SDimitry Andric CFG *CFGraph = AC.getCFG();
13100b57cec5SDimitry Andric if (!CFGraph)
13110b57cec5SDimitry Andric return;
13120b57cec5SDimitry Andric
13130b57cec5SDimitry Andric determineExpectedReturnState(AC, D);
13140b57cec5SDimitry Andric
13150b57cec5SDimitry Andric PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
13160b57cec5SDimitry Andric // AC.getCFG()->viewCFG(LangOptions());
13170b57cec5SDimitry Andric
13180b57cec5SDimitry Andric BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
13190b57cec5SDimitry Andric
1320a7dea167SDimitry Andric CurrStates = std::make_unique<ConsumedStateMap>();
13210b57cec5SDimitry Andric ConsumedStmtVisitor Visitor(*this, CurrStates.get());
13220b57cec5SDimitry Andric
13230b57cec5SDimitry Andric // Add all trackable parameters to the state map.
13240b57cec5SDimitry Andric for (const auto *PI : D->parameters())
13250b57cec5SDimitry Andric Visitor.VisitParmVarDecl(PI);
13260b57cec5SDimitry Andric
13270b57cec5SDimitry Andric // Visit all of the function's basic blocks.
13280b57cec5SDimitry Andric for (const auto *CurrBlock : *SortedGraph) {
13290b57cec5SDimitry Andric if (!CurrStates)
13300b57cec5SDimitry Andric CurrStates = BlockInfo.getInfo(CurrBlock);
13310b57cec5SDimitry Andric
13320b57cec5SDimitry Andric if (!CurrStates) {
13330b57cec5SDimitry Andric continue;
13340b57cec5SDimitry Andric } else if (!CurrStates->isReachable()) {
13350b57cec5SDimitry Andric CurrStates = nullptr;
13360b57cec5SDimitry Andric continue;
13370b57cec5SDimitry Andric }
13380b57cec5SDimitry Andric
13390b57cec5SDimitry Andric Visitor.reset(CurrStates.get());
13400b57cec5SDimitry Andric
13410b57cec5SDimitry Andric // Visit all of the basic block's statements.
13420b57cec5SDimitry Andric for (const auto &B : *CurrBlock) {
13430b57cec5SDimitry Andric switch (B.getKind()) {
13440b57cec5SDimitry Andric case CFGElement::Statement:
13450b57cec5SDimitry Andric Visitor.Visit(B.castAs<CFGStmt>().getStmt());
13460b57cec5SDimitry Andric break;
13470b57cec5SDimitry Andric
13480b57cec5SDimitry Andric case CFGElement::TemporaryDtor: {
13490b57cec5SDimitry Andric const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
13500b57cec5SDimitry Andric const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
13510b57cec5SDimitry Andric
13520b57cec5SDimitry Andric Visitor.checkCallability(PropagationInfo(BTE),
13530b57cec5SDimitry Andric DTor.getDestructorDecl(AC.getASTContext()),
13540b57cec5SDimitry Andric BTE->getExprLoc());
13550b57cec5SDimitry Andric CurrStates->remove(BTE);
13560b57cec5SDimitry Andric break;
13570b57cec5SDimitry Andric }
13580b57cec5SDimitry Andric
13590b57cec5SDimitry Andric case CFGElement::AutomaticObjectDtor: {
13600b57cec5SDimitry Andric const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
13610b57cec5SDimitry Andric SourceLocation Loc = DTor.getTriggerStmt()->getEndLoc();
13620b57cec5SDimitry Andric const VarDecl *Var = DTor.getVarDecl();
13630b57cec5SDimitry Andric
13640b57cec5SDimitry Andric Visitor.checkCallability(PropagationInfo(Var),
13650b57cec5SDimitry Andric DTor.getDestructorDecl(AC.getASTContext()),
13660b57cec5SDimitry Andric Loc);
13670b57cec5SDimitry Andric break;
13680b57cec5SDimitry Andric }
13690b57cec5SDimitry Andric
13700b57cec5SDimitry Andric default:
13710b57cec5SDimitry Andric break;
13720b57cec5SDimitry Andric }
13730b57cec5SDimitry Andric }
13740b57cec5SDimitry Andric
13750b57cec5SDimitry Andric // TODO: Handle other forms of branching with precision, including while-
13760b57cec5SDimitry Andric // and for-loops. (Deferred)
13770b57cec5SDimitry Andric if (!splitState(CurrBlock, Visitor)) {
13780b57cec5SDimitry Andric CurrStates->setSource(nullptr);
13790b57cec5SDimitry Andric
13800b57cec5SDimitry Andric if (CurrBlock->succ_size() > 1 ||
13810b57cec5SDimitry Andric (CurrBlock->succ_size() == 1 &&
13820b57cec5SDimitry Andric (*CurrBlock->succ_begin())->pred_size() > 1)) {
13830b57cec5SDimitry Andric
13840b57cec5SDimitry Andric auto *RawState = CurrStates.get();
13850b57cec5SDimitry Andric
13860b57cec5SDimitry Andric for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
13870b57cec5SDimitry Andric SE = CurrBlock->succ_end(); SI != SE; ++SI) {
13880b57cec5SDimitry Andric if (*SI == nullptr) continue;
13890b57cec5SDimitry Andric
13900b57cec5SDimitry Andric if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
13910b57cec5SDimitry Andric BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
13920b57cec5SDimitry Andric *SI, CurrBlock, RawState, WarningsHandler);
13930b57cec5SDimitry Andric
13940b57cec5SDimitry Andric if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
13950b57cec5SDimitry Andric BlockInfo.discardInfo(*SI);
13960b57cec5SDimitry Andric } else {
13970b57cec5SDimitry Andric BlockInfo.addInfo(*SI, RawState, CurrStates);
13980b57cec5SDimitry Andric }
13990b57cec5SDimitry Andric }
14000b57cec5SDimitry Andric
14010b57cec5SDimitry Andric CurrStates = nullptr;
14020b57cec5SDimitry Andric }
14030b57cec5SDimitry Andric }
14040b57cec5SDimitry Andric
14050b57cec5SDimitry Andric if (CurrBlock == &AC.getCFG()->getExit() &&
14060b57cec5SDimitry Andric D->getCallResultType()->isVoidType())
14070b57cec5SDimitry Andric CurrStates->checkParamsForReturnTypestate(D->getLocation(),
14080b57cec5SDimitry Andric WarningsHandler);
14090b57cec5SDimitry Andric } // End of block iterator.
14100b57cec5SDimitry Andric
14110b57cec5SDimitry Andric // Delete the last existing state map.
14120b57cec5SDimitry Andric CurrStates = nullptr;
14130b57cec5SDimitry Andric
14140b57cec5SDimitry Andric WarningsHandler.emitDiagnostics();
14150b57cec5SDimitry Andric }
1416