diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp | 712 |
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; } } |