summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp712
1 files changed, 325 insertions, 387 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
index e5ec3e6..2b2da2c 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
@@ -17,20 +17,20 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
// TODO: Adjust states of args to constructors in the same way that arguments to
// function calls are handled.
@@ -57,11 +57,9 @@ ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
// Find the source location of the first statement in the block, if the block
// is not empty.
- for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
- BI != BE; ++BI) {
- if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ for (const auto &B : *Block)
+ if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
return CS->getStmt()->getLocStart();
- }
// Block is empty.
// If we have one successor, return the first statement in that block
@@ -115,14 +113,10 @@ static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
static bool isCallableInState(const CallableWhenAttr *CWAttr,
ConsumedState State) {
- CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
- E = CWAttr->callableState_end();
-
- for (; I != E; ++I) {
-
+ for (const auto &S : CWAttr->callableStates()) {
ConsumedState MappedAttrState = CS_None;
-
- switch (*I) {
+
+ switch (S) {
case CallableWhenAttr::Unknown:
MappedAttrState = CS_Unknown;
break;
@@ -143,6 +137,7 @@ static bool isCallableInState(const CallableWhenAttr *CWAttr,
return false;
}
+
static bool isConsumableType(const QualType &QT) {
if (QT->isPointerType() || QT->isReferenceType())
return false;
@@ -153,6 +148,23 @@ static bool isConsumableType(const QualType &QT) {
return false;
}
+static bool isAutoCastType(const QualType &QT) {
+ if (QT->isPointerType() || QT->isReferenceType())
+ return false;
+
+ if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
+ return RD->hasAttr<ConsumableAutoCastAttr>();
+
+ return false;
+}
+
+static bool isSetOnReadPtrType(const QualType &QT) {
+ if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
+ return RD->hasAttr<ConsumableSetOnReadAttr>();
+ return false;
+}
+
+
static bool isKnownState(ConsumedState State) {
switch (State) {
case CS_Unconsumed:
@@ -165,19 +177,16 @@ static bool isKnownState(ConsumedState State) {
llvm_unreachable("invalid enum");
}
-static bool isRValueRefish(QualType ParamType) {
- return ParamType->isRValueReferenceType() ||
- (ParamType->isLValueReferenceType() &&
- !cast<LValueReferenceType>(
- ParamType.getCanonicalType())->isSpelledAsLValue());
+static bool isRValueRef(QualType ParamType) {
+ return ParamType->isRValueReferenceType();
}
static bool isTestingFunction(const FunctionDecl *FunDecl) {
return FunDecl->hasAttr<TestTypestateAttr>();
}
-static bool isValueType(QualType ParamType) {
- return !(ParamType->isPointerType() || ParamType->isReferenceType());
+static bool isPointerOrRef(QualType ParamType) {
+ return ParamType->isPointerType() || ParamType->isReferenceType();
}
static ConsumedState mapConsumableAttrState(const QualType QT) {
@@ -455,15 +464,29 @@ class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
ConsumedAnalyzer &Analyzer;
ConsumedStateMap *StateMap;
MapType PropagationMap;
- void forwardInfo(const Stmt *From, const Stmt *To);
- bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
- void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
- QualType ReturnType);
+
+ InfoEntry findInfo(const Expr *E) {
+ return PropagationMap.find(E->IgnoreParens());
+ }
+ ConstInfoEntry findInfo(const Expr *E) const {
+ return PropagationMap.find(E->IgnoreParens());
+ }
+ void insertInfo(const Expr *E, const PropagationInfo &PI) {
+ PropagationMap.insert(PairType(E->IgnoreParens(), PI));
+ }
+
+ void forwardInfo(const Expr *From, const Expr *To);
+ void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
+ ConsumedState getInfo(const Expr *From);
+ void setInfo(const Expr *To, ConsumedState NS);
+ void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
public:
void checkCallability(const PropagationInfo &PInfo,
const FunctionDecl *FunDecl,
SourceLocation BlameLoc);
+ bool handleCall(const CallExpr *Call, const Expr *ObjArg,
+ const FunctionDecl *FunD);
void VisitBinaryOperator(const BinaryOperator *BinOp);
void VisitCallExpr(const CallExpr *Call);
@@ -485,8 +508,8 @@ public:
ConsumedStateMap *StateMap)
: AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
- PropagationInfo getInfo(const Stmt *StmtNode) const {
- ConstInfoEntry Entry = PropagationMap.find(StmtNode);
+ PropagationInfo getInfo(const Expr *StmtNode) const {
+ ConstInfoEntry Entry = findInfo(StmtNode);
if (Entry != PropagationMap.end())
return Entry->second;
@@ -499,76 +522,187 @@ public:
}
};
+
+void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
+ InfoEntry Entry = findInfo(From);
+ if (Entry != PropagationMap.end())
+ insertInfo(To, Entry->second);
+}
+
+
+// Create a new state for To, which is initialized to the state of From.
+// If NS is not CS_None, sets the state of From to NS.
+void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
+ ConsumedState NS) {
+ InfoEntry Entry = findInfo(From);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo& PInfo = Entry->second;
+ ConsumedState CS = PInfo.getAsState(StateMap);
+ if (CS != CS_None)
+ insertInfo(To, PropagationInfo(CS));
+ if (NS != CS_None && PInfo.isPointerToValue())
+ setStateForVarOrTmp(StateMap, PInfo, NS);
+ }
+}
+
+
+// Get the ConsumedState for From
+ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
+ InfoEntry Entry = findInfo(From);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo& PInfo = Entry->second;
+ return PInfo.getAsState(StateMap);
+ }
+ return CS_None;
+}
+
+
+// If we already have info for To then update it, otherwise create a new entry.
+void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
+ InfoEntry Entry = findInfo(To);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo& PInfo = Entry->second;
+ if (PInfo.isPointerToValue())
+ setStateForVarOrTmp(StateMap, PInfo, NS);
+ } else if (NS != CS_None) {
+ insertInfo(To, PropagationInfo(NS));
+ }
+}
+
+
+
void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
const FunctionDecl *FunDecl,
SourceLocation BlameLoc) {
assert(!PInfo.isTest());
-
- if (!FunDecl->hasAttr<CallableWhenAttr>())
- return;
-
+
const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
-
+ if (!CWAttr)
+ return;
+
if (PInfo.isVar()) {
ConsumedState VarState = StateMap->getState(PInfo.getVar());
-
+
if (VarState == CS_None || isCallableInState(CWAttr, VarState))
return;
-
+
Analyzer.WarningsHandler.warnUseInInvalidState(
FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
stateToString(VarState), BlameLoc);
-
+
} else {
ConsumedState TmpState = PInfo.getAsState(StateMap);
-
+
if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
return;
-
+
Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
}
}
-void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
- InfoEntry Entry = PropagationMap.find(From);
-
- if (Entry != PropagationMap.end())
- PropagationMap.insert(PairType(To, Entry->second));
-}
-bool ConsumedStmtVisitor::isLikeMoveAssignment(
- const CXXMethodDecl *MethodDecl) {
-
- return MethodDecl->isMoveAssignmentOperator() ||
- (MethodDecl->getOverloadedOperator() == OO_Equal &&
- MethodDecl->getNumParams() == 1 &&
- MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
+// Factors out common behavior for function, method, and operator calls.
+// Check parameters and set parameter state if necessary.
+// Returns true if the state of ObjArg is set, or false otherwise.
+bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
+ const FunctionDecl *FunD) {
+ unsigned Offset = 0;
+ if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
+ Offset = 1; // first argument is 'this'
+
+ // check explicit parameters
+ for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
+ // Skip variable argument lists.
+ if (Index - Offset >= FunD->getNumParams())
+ break;
+
+ const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
+ QualType ParamType = Param->getType();
+
+ InfoEntry Entry = findInfo(Call->getArg(Index));
+
+ if (Entry == PropagationMap.end() || Entry->second.isTest())
+ continue;
+ PropagationInfo PInfo = Entry->second;
+
+ // Check that the parameter is in the correct state.
+ if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
+ ConsumedState ParamState = PInfo.getAsState(StateMap);
+ ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
+
+ if (ParamState != ExpectedState)
+ Analyzer.WarningsHandler.warnParamTypestateMismatch(
+ Call->getArg(Index)->getExprLoc(),
+ stateToString(ExpectedState), stateToString(ParamState));
+ }
+
+ if (!(Entry->second.isVar() || Entry->second.isTmp()))
+ continue;
+
+ // Adjust state on the caller side.
+ if (isRValueRef(ParamType))
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
+ else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
+ setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
+ else if (isPointerOrRef(ParamType) &&
+ (!ParamType->getPointeeType().isConstQualified() ||
+ isSetOnReadPtrType(ParamType)))
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
+ }
+
+ if (!ObjArg)
+ return false;
+
+ // check implicit 'self' parameter, if present
+ InfoEntry Entry = findInfo(ObjArg);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo PInfo = Entry->second;
+ checkCallability(PInfo, FunD, Call->getExprLoc());
+
+ if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
+ if (PInfo.isVar()) {
+ StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
+ return true;
+ }
+ else if (PInfo.isTmp()) {
+ StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
+ return true;
+ }
+ }
+ else if (isTestingFunction(FunD) && PInfo.isVar()) {
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(PInfo.getVar(), testsFor(FunD))));
+ }
+ }
+ return false;
}
-void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
- const FunctionDecl *Fun,
- QualType ReturnType) {
- if (isConsumableType(ReturnType)) {
-
+
+void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
+ const FunctionDecl *Fun) {
+ QualType RetType = Fun->getCallResultType();
+ if (RetType->isReferenceType())
+ RetType = RetType->getPointeeType();
+
+ if (isConsumableType(RetType)) {
ConsumedState ReturnState;
-
- if (Fun->hasAttr<ReturnTypestateAttr>())
- ReturnState = mapReturnTypestateAttrState(
- Fun->getAttr<ReturnTypestateAttr>());
+ if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
+ ReturnState = mapReturnTypestateAttrState(RTA);
else
- ReturnState = mapConsumableAttrState(ReturnType);
+ ReturnState = mapConsumableAttrState(RetType);
PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
}
}
+
void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
switch (BinOp->getOpcode()) {
case BO_LAnd:
case BO_LOr : {
- InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
- REntry = PropagationMap.find(BinOp->getRHS());
+ InfoEntry LEntry = findInfo(BinOp->getLHS()),
+ REntry = findInfo(BinOp->getRHS());
VarTestResult LTest, RTest;
@@ -576,7 +710,7 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
LTest = LEntry->second.getVarTest();
} else {
- LTest.Var = NULL;
+ LTest.Var = nullptr;
LTest.TestsFor = CS_None;
}
@@ -584,11 +718,11 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
RTest = REntry->second.getVarTest();
} else {
- RTest.Var = NULL;
+ RTest.Var = nullptr;
RTest.TestsFor = CS_None;
}
-
- if (!(LTest.Var == NULL && RTest.Var == NULL))
+
+ if (!(LTest.Var == nullptr && RTest.Var == nullptr))
PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
@@ -605,81 +739,21 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
}
}
-static bool isStdNamespace(const DeclContext *DC) {
- if (!DC->isNamespace()) return false;
- while (DC->getParent()->isNamespace())
- DC = DC->getParent();
- const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
-
- return ND && ND->getName() == "std" &&
- ND->getDeclContext()->isTranslationUnit();
-}
-
void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
- if (const FunctionDecl *FunDecl =
- dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
-
- // Special case for the std::move function.
- // TODO: Make this more specific. (Deferred)
- if (Call->getNumArgs() == 1 &&
- FunDecl->getNameAsString() == "move" &&
- isStdNamespace(FunDecl->getDeclContext())) {
- forwardInfo(Call->getArg(0), Call);
- return;
- }
-
- unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
-
- for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
- const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
- QualType ParamType = Param->getType();
-
- InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
-
- if (Entry == PropagationMap.end() || Entry->second.isTest())
- continue;
-
- PropagationInfo PInfo = Entry->second;
-
- // Check that the parameter is in the correct state.
-
- if (Param->hasAttr<ParamTypestateAttr>()) {
- ConsumedState ParamState = PInfo.getAsState(StateMap);
-
- ConsumedState ExpectedState =
- mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
-
- if (ParamState != ExpectedState)
- Analyzer.WarningsHandler.warnParamTypestateMismatch(
- Call->getArg(Index - Offset)->getExprLoc(),
- stateToString(ExpectedState), stateToString(ParamState));
- }
-
- if (!(Entry->second.isVar() || Entry->second.isTmp()))
- continue;
-
- // Adjust state on the caller side.
-
- if (isRValueRefish(ParamType)) {
- setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
-
- } else if (Param->hasAttr<ReturnTypestateAttr>()) {
- setStateForVarOrTmp(StateMap, PInfo,
- mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
-
- } else if (!isValueType(ParamType) &&
- !ParamType->getPointeeType().isConstQualified()) {
-
- setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
- }
- }
-
- QualType RetType = FunDecl->getCallResultType();
- if (RetType->isReferenceType())
- RetType = RetType->getPointeeType();
-
- propagateReturnType(Call, FunDecl, RetType);
+ const FunctionDecl *FunDecl = Call->getDirectCallee();
+ if (!FunDecl)
+ return;
+
+ // Special case for the std::move function.
+ // TODO: Make this more specific. (Deferred)
+ if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" &&
+ FunDecl->isInStdNamespace()) {
+ copyInfo(Call->getArg(0), Call, CS_Consumed);
+ return;
}
+
+ handleCall(Call, nullptr, FunDecl);
+ propagateReturnType(Call, FunDecl);
}
void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
@@ -689,7 +763,7 @@ void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
const CXXBindTemporaryExpr *Temp) {
- InfoEntry Entry = PropagationMap.find(Temp->getSubExpr());
+ InfoEntry Entry = findInfo(Temp->getSubExpr());
if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
StateMap->setState(Temp, Entry->second.getAsState(StateMap));
@@ -707,168 +781,60 @@ void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
return;
// FIXME: What should happen if someone annotates the move constructor?
- if (Constructor->hasAttr<ReturnTypestateAttr>()) {
- // TODO: Adjust state of args appropriately.
-
- ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
- ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
+ if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
+ // TODO: Adjust state of args appropriately.
+ ConsumedState RetState = mapReturnTypestateAttrState(RTA);
PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
-
} else if (Constructor->isDefaultConstructor()) {
-
PropagationMap.insert(PairType(Call,
PropagationInfo(consumed::CS_Consumed)));
-
} else if (Constructor->isMoveConstructor()) {
-
- InfoEntry Entry = PropagationMap.find(Call->getArg(0));
-
- if (Entry != PropagationMap.end()) {
- PropagationInfo PInfo = Entry->second;
-
- if (PInfo.isVar()) {
- const VarDecl* Var = PInfo.getVar();
-
- PropagationMap.insert(PairType(Call,
- PropagationInfo(StateMap->getState(Var))));
-
- StateMap->setState(Var, consumed::CS_Consumed);
-
- } else if (PInfo.isTmp()) {
- const CXXBindTemporaryExpr *Tmp = PInfo.getTmp();
-
- PropagationMap.insert(PairType(Call,
- PropagationInfo(StateMap->getState(Tmp))));
-
- StateMap->setState(Tmp, consumed::CS_Consumed);
-
- } else {
- PropagationMap.insert(PairType(Call, PInfo));
- }
- }
+ copyInfo(Call->getArg(0), Call, CS_Consumed);
} else if (Constructor->isCopyConstructor()) {
- forwardInfo(Call->getArg(0), Call);
-
+ // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
+ ConsumedState NS =
+ isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ?
+ CS_Unknown : CS_None;
+ copyInfo(Call->getArg(0), Call, NS);
} else {
// TODO: Adjust state of args appropriately.
-
ConsumedState RetState = mapConsumableAttrState(ThisType);
PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
}
}
+
void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
- const CXXMemberCallExpr *Call) {
-
- VisitCallExpr(Call);
-
- InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
-
- if (Entry != PropagationMap.end()) {
- PropagationInfo PInfo = Entry->second;
- const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
-
- checkCallability(PInfo, MethodDecl, Call->getExprLoc());
-
- if (PInfo.isVar()) {
- if (isTestingFunction(MethodDecl))
- PropagationMap.insert(PairType(Call,
- PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
- else if (MethodDecl->hasAttr<SetTypestateAttr>())
- StateMap->setState(PInfo.getVar(),
- mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
- } else if (PInfo.isTmp() && MethodDecl->hasAttr<SetTypestateAttr>()) {
- StateMap->setState(PInfo.getTmp(),
- mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
- }
- }
+ const CXXMemberCallExpr *Call) {
+ CXXMethodDecl* MD = Call->getMethodDecl();
+ if (!MD)
+ return;
+
+ handleCall(Call, Call->getImplicitObjectArgument(), MD);
+ propagateReturnType(Call, MD);
}
+
void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
- const CXXOperatorCallExpr *Call) {
-
+ const CXXOperatorCallExpr *Call) {
+
const FunctionDecl *FunDecl =
dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
-
if (!FunDecl) return;
-
- if (isa<CXXMethodDecl>(FunDecl) &&
- isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
-
- InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
- InfoEntry REntry = PropagationMap.find(Call->getArg(1));
-
- PropagationInfo LPInfo, RPInfo;
-
- if (LEntry != PropagationMap.end() &&
- REntry != PropagationMap.end()) {
-
- LPInfo = LEntry->second;
- RPInfo = REntry->second;
-
- if (LPInfo.isPointerToValue() && RPInfo.isPointerToValue()) {
- setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getAsState(StateMap));
- PropagationMap.insert(PairType(Call, LPInfo));
- setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
-
- } else if (RPInfo.isState()) {
- setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getState());
- PropagationMap.insert(PairType(Call, LPInfo));
-
- } else {
- setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
- }
-
- } else if (LEntry != PropagationMap.end() &&
- REntry == PropagationMap.end()) {
-
- LPInfo = LEntry->second;
-
- assert(!LPInfo.isTest());
-
- if (LPInfo.isPointerToValue()) {
- setStateForVarOrTmp(StateMap, LPInfo, consumed::CS_Unknown);
- PropagationMap.insert(PairType(Call, LPInfo));
-
- } else {
- PropagationMap.insert(PairType(Call,
- PropagationInfo(consumed::CS_Unknown)));
- }
-
- } else if (LEntry == PropagationMap.end() &&
- REntry != PropagationMap.end()) {
-
- RPInfo = REntry->second;
-
- if (RPInfo.isPointerToValue())
- setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
- }
-
- } else {
-
- VisitCallExpr(Call);
-
- InfoEntry Entry = PropagationMap.find(Call->getArg(0));
-
- if (Entry != PropagationMap.end()) {
- PropagationInfo PInfo = Entry->second;
-
- checkCallability(PInfo, FunDecl, Call->getExprLoc());
-
- if (PInfo.isVar()) {
- if (isTestingFunction(FunDecl))
- PropagationMap.insert(PairType(Call,
- PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
- else if (FunDecl->hasAttr<SetTypestateAttr>())
- StateMap->setState(PInfo.getVar(),
- mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
-
- } else if (PInfo.isTmp() && FunDecl->hasAttr<SetTypestateAttr>()) {
- StateMap->setState(PInfo.getTmp(),
- mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
- }
- }
+
+ if (Call->getOperator() == OO_Equal) {
+ ConsumedState CS = getInfo(Call->getArg(1));
+ if (!handleCall(Call, Call->getArg(0), FunDecl))
+ setInfo(Call->getArg(0), CS);
+ return;
}
+
+ if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
+ handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
+ else
+ handleCall(Call, Call->getArg(0), FunDecl);
+
+ propagateReturnType(Call, FunDecl);
}
void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
@@ -878,11 +844,9 @@ void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
}
void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
- for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
- DE = DeclS->decl_end(); DI != DE; ++DI) {
-
- if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
- }
+ for (const auto *DI : DeclS->decls())
+ if (isa<VarDecl>(DI))
+ VisitVarDecl(cast<VarDecl>(DI));
if (DeclS->isSingleDecl())
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
@@ -904,22 +868,16 @@ void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
QualType ParamType = Param->getType();
ConsumedState ParamState = consumed::CS_None;
- if (Param->hasAttr<ParamTypestateAttr>()) {
- const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
- ParamState = mapParamTypestateAttrState(PTAttr);
-
- } else if (isConsumableType(ParamType)) {
- ParamState = mapConsumableAttrState(ParamType);
-
- } else if (isRValueRefish(ParamType) &&
- isConsumableType(ParamType->getPointeeType())) {
-
- ParamState = mapConsumableAttrState(ParamType->getPointeeType());
-
- } else if (ParamType->isReferenceType() &&
- isConsumableType(ParamType->getPointeeType())) {
+ if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
+ ParamState = mapParamTypestateAttrState(PTA);
+ else if (isConsumableType(ParamType))
+ ParamState = mapConsumableAttrState(ParamType);
+ else if (isRValueRef(ParamType) &&
+ isConsumableType(ParamType->getPointeeType()))
+ ParamState = mapConsumableAttrState(ParamType->getPointeeType());
+ else if (ParamType->isReferenceType() &&
+ isConsumableType(ParamType->getPointeeType()))
ParamState = consumed::CS_Unknown;
- }
if (ParamState != CS_None)
StateMap->setState(Param, ParamState);
@@ -929,7 +887,7 @@ void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
if (ExpectedState != CS_None) {
- InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
+ InfoEntry Entry = findInfo(Ret->getRetValue());
if (Entry != PropagationMap.end()) {
ConsumedState RetState = Entry->second.getAsState(StateMap);
@@ -946,7 +904,7 @@ void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
}
void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
- InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
+ InfoEntry Entry = findInfo(UOp->getSubExpr());
if (Entry == PropagationMap.end()) return;
switch (UOp->getOpcode()) {
@@ -968,8 +926,7 @@ void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
if (isConsumableType(Var->getType())) {
if (Var->hasInit()) {
- MapType::iterator VIT = PropagationMap.find(
- Var->getInit()->IgnoreImplicit());
+ MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
if (VIT != PropagationMap.end()) {
PropagationInfo PInfo = VIT->second;
ConsumedState St = PInfo.getAsState(StateMap);
@@ -1104,9 +1061,9 @@ void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
ConsumedStateMap *StateMap) {
-
- assert(Block != NULL && "Block pointer must not be NULL");
-
+
+ assert(Block && "Block pointer must not be NULL");
+
ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
if (Entry) {
@@ -1128,7 +1085,7 @@ ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
unsigned int BlockID = Block->getBlockID();
delete StateMapsArray[BlockID];
- StateMapsArray[BlockID] = NULL;
+ StateMapsArray[BlockID] = nullptr;
}
ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
@@ -1138,7 +1095,7 @@ ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
if (isBackEdgeTarget(Block)) {
return new ConsumedStateMap(*StateMap);
} else {
- StateMapsArray[Block->getBlockID()] = NULL;
+ StateMapsArray[Block->getBlockID()] = nullptr;
return StateMap;
}
}
@@ -1151,8 +1108,8 @@ bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
}
bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
- assert(Block != NULL && "Block pointer must not be NULL");
-
+ assert(Block && "Block pointer must not be NULL");
+
// Anything with less than two predecessors can't be the target of a back
// edge.
if (Block->pred_size() < 2)
@@ -1170,24 +1127,19 @@ bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
ConsumedWarningsHandlerBase &WarningsHandler) const {
- ConsumedState ExpectedState;
-
- for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
- DMI != DME; ++DMI) {
-
- if (isa<ParmVarDecl>(DMI->first)) {
- const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
+ for (const auto &DM : VarMap) {
+ if (isa<ParmVarDecl>(DM.first)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
+ const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
- if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
-
- ExpectedState =
- mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
+ if (!RTA)
+ continue;
- if (DMI->second != ExpectedState) {
+ ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
+ if (DM.second != ExpectedState)
WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
Param->getNameAsString(), stateToString(ExpectedState),
- stateToString(DMI->second));
- }
+ stateToString(DM.second));
}
}
}
@@ -1223,16 +1175,14 @@ void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
return;
}
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : Other->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second)
- VarMap[DMI->first] = CS_Unknown;
+ if (LocalState != DM.second)
+ VarMap[DM.first] = CS_Unknown;
}
}
@@ -1243,18 +1193,16 @@ void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
ConsumedState LocalState;
SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
- for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
- DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : LoopBackStates->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second) {
- VarMap[DMI->first] = CS_Unknown;
- WarningsHandler.warnLoopStateMismatch(
- BlameLoc, DMI->first->getNameAsString());
+ if (LocalState != DM.second) {
+ VarMap[DM.first] = CS_Unknown;
+ WarningsHandler.warnLoopStateMismatch(BlameLoc,
+ DM.first->getNameAsString());
}
}
}
@@ -1274,18 +1222,14 @@ void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
TmpMap[Tmp] = State;
}
-void ConsumedStateMap::remove(const VarDecl *Var) {
- VarMap.erase(Var);
+void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
+ TmpMap.erase(Tmp);
}
bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- if (this->getState(DMI->first) != DMI->second)
- return true;
- }
-
+ for (const auto &DM : Other->VarMap)
+ if (this->getState(DM.first) != DM.second)
+ return true;
return false;
}
@@ -1298,9 +1242,7 @@ void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
} else
ReturnType = D->getCallResultType();
- if (D->hasAttr<ReturnTypestateAttr>()) {
- const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
-
+ if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
if (!RD || !RD->hasAttr<ConsumableAttr>()) {
// FIXME: This should be removed when template instantiation propagates
@@ -1312,22 +1254,27 @@ void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
ExpectedReturnState = CS_None;
} else
ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
- } else if (isConsumableType(ReturnType))
- ExpectedReturnState = mapConsumableAttrState(ReturnType);
+ } else if (isConsumableType(ReturnType)) {
+ if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
+ ExpectedReturnState = CS_None; // expected state.
+ else
+ ExpectedReturnState = mapConsumableAttrState(ReturnType);
+ }
else
ExpectedReturnState = CS_None;
}
bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
const ConsumedStmtVisitor &Visitor) {
-
- OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates));
+
+ std::unique_ptr<ConsumedStateMap> FalseStates(
+ new ConsumedStateMap(*CurrStates));
PropagationInfo PInfo;
if (const IfStmt *IfNode =
dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
- const Stmt *Cond = IfNode->getCond();
+ const Expr *Cond = IfNode->getCond();
PInfo = Visitor.getInfo(Cond);
if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
@@ -1396,9 +1343,9 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
delete CurrStates;
if (*++SI)
- BlockInfo.addInfo(*SI, FalseStates.take());
-
- CurrStates = NULL;
+ BlockInfo.addInfo(*SI, FalseStates.release());
+
+ CurrStates = nullptr;
return true;
}
@@ -1422,18 +1369,12 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
// Add all trackable parameters to the state map.
- for (FunctionDecl::param_const_iterator PI = D->param_begin(),
- PE = D->param_end(); PI != PE; ++PI) {
- Visitor.VisitParmVarDecl(*PI);
- }
+ for (const auto *PI : D->params())
+ Visitor.VisitParmVarDecl(PI);
// Visit all of the function's basic blocks.
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I != E; ++I) {
-
- const CFGBlock *CurrBlock = *I;
-
- if (CurrStates == NULL)
+ for (const auto *CurrBlock : *SortedGraph) {
+ if (!CurrStates)
CurrStates = BlockInfo.getInfo(CurrBlock);
if (!CurrStates) {
@@ -1441,33 +1382,32 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
} else if (!CurrStates->isReachable()) {
delete CurrStates;
- CurrStates = NULL;
+ CurrStates = nullptr;
continue;
}
Visitor.reset(CurrStates);
// Visit all of the basic block's statements.
- for (CFGBlock::const_iterator BI = CurrBlock->begin(),
- BE = CurrBlock->end(); BI != BE; ++BI) {
-
- switch (BI->getKind()) {
+ for (const auto &B : *CurrBlock) {
+ switch (B.getKind()) {
case CFGElement::Statement:
- Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
+ Visitor.Visit(B.castAs<CFGStmt>().getStmt());
break;
case CFGElement::TemporaryDtor: {
- const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
+ const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
Visitor.checkCallability(PropagationInfo(BTE),
DTor.getDestructorDecl(AC.getASTContext()),
BTE->getExprLoc());
+ CurrStates->remove(BTE);
break;
}
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
+ const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
const VarDecl *Var = DTor.getVarDecl();
@@ -1482,13 +1422,11 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
}
}
- CurrStates->clearTemporaries();
-
// TODO: Handle other forms of branching with precision, including while-
// and for-loops. (Deferred)
if (!splitState(CurrBlock, Visitor)) {
- CurrStates->setSource(NULL);
-
+ CurrStates->setSource(nullptr);
+
if (CurrBlock->succ_size() > 1 ||
(CurrBlock->succ_size() == 1 &&
(*CurrBlock->succ_begin())->pred_size() > 1)) {
@@ -1497,9 +1435,9 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
-
- if (*SI == NULL) continue;
-
+
+ if (*SI == nullptr) continue;
+
if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
CurrStates,
@@ -1514,8 +1452,8 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
if (!OwnershipTaken)
delete CurrStates;
-
- CurrStates = NULL;
+
+ CurrStates = nullptr;
}
}
OpenPOWER on IntegriCloud