clang API Documentation
00001 //===- Consumed.cpp --------------------------------------------*- C++ --*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // A intra-procedural analysis for checking consumed properties. This is based, 00011 // in part, on research on linear types. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "clang/AST/ASTContext.h" 00016 #include "clang/AST/Attr.h" 00017 #include "clang/AST/DeclCXX.h" 00018 #include "clang/AST/ExprCXX.h" 00019 #include "clang/AST/RecursiveASTVisitor.h" 00020 #include "clang/AST/StmtCXX.h" 00021 #include "clang/AST/StmtVisitor.h" 00022 #include "clang/AST/Type.h" 00023 #include "clang/Analysis/Analyses/Consumed.h" 00024 #include "clang/Analysis/Analyses/PostOrderCFGView.h" 00025 #include "clang/Analysis/AnalysisContext.h" 00026 #include "clang/Analysis/CFG.h" 00027 #include "clang/Basic/OperatorKinds.h" 00028 #include "clang/Basic/SourceLocation.h" 00029 #include "llvm/ADT/DenseMap.h" 00030 #include "llvm/ADT/SmallVector.h" 00031 #include "llvm/Support/Compiler.h" 00032 #include "llvm/Support/raw_ostream.h" 00033 #include <memory> 00034 00035 // TODO: Adjust states of args to constructors in the same way that arguments to 00036 // function calls are handled. 00037 // TODO: Use information from tests in for- and while-loop conditional. 00038 // TODO: Add notes about the actual and expected state for 00039 // TODO: Correctly identify unreachable blocks when chaining boolean operators. 00040 // TODO: Adjust the parser and AttributesList class to support lists of 00041 // identifiers. 00042 // TODO: Warn about unreachable code. 00043 // TODO: Switch to using a bitmap to track unreachable blocks. 00044 // TODO: Handle variable definitions, e.g. bool valid = x.isValid(); 00045 // if (valid) ...; (Deferred) 00046 // TODO: Take notes on state transitions to provide better warning messages. 00047 // (Deferred) 00048 // TODO: Test nested conditionals: A) Checking the same value multiple times, 00049 // and 2) Checking different values. (Deferred) 00050 00051 using namespace clang; 00052 using namespace consumed; 00053 00054 // Key method definition 00055 ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {} 00056 00057 static SourceLocation getFirstStmtLoc(const CFGBlock *Block) { 00058 // Find the source location of the first statement in the block, if the block 00059 // is not empty. 00060 for (const auto &B : *Block) 00061 if (Optional<CFGStmt> CS = B.getAs<CFGStmt>()) 00062 return CS->getStmt()->getLocStart(); 00063 00064 // Block is empty. 00065 // If we have one successor, return the first statement in that block 00066 if (Block->succ_size() == 1 && *Block->succ_begin()) 00067 return getFirstStmtLoc(*Block->succ_begin()); 00068 00069 return SourceLocation(); 00070 } 00071 00072 static SourceLocation getLastStmtLoc(const CFGBlock *Block) { 00073 // Find the source location of the last statement in the block, if the block 00074 // is not empty. 00075 if (const Stmt *StmtNode = Block->getTerminator()) { 00076 return StmtNode->getLocStart(); 00077 } else { 00078 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(), 00079 BE = Block->rend(); BI != BE; ++BI) { 00080 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) 00081 return CS->getStmt()->getLocStart(); 00082 } 00083 } 00084 00085 // If we have one successor, return the first statement in that block 00086 SourceLocation Loc; 00087 if (Block->succ_size() == 1 && *Block->succ_begin()) 00088 Loc = getFirstStmtLoc(*Block->succ_begin()); 00089 if (Loc.isValid()) 00090 return Loc; 00091 00092 // If we have one predecessor, return the last statement in that block 00093 if (Block->pred_size() == 1 && *Block->pred_begin()) 00094 return getLastStmtLoc(*Block->pred_begin()); 00095 00096 return Loc; 00097 } 00098 00099 static ConsumedState invertConsumedUnconsumed(ConsumedState State) { 00100 switch (State) { 00101 case CS_Unconsumed: 00102 return CS_Consumed; 00103 case CS_Consumed: 00104 return CS_Unconsumed; 00105 case CS_None: 00106 return CS_None; 00107 case CS_Unknown: 00108 return CS_Unknown; 00109 } 00110 llvm_unreachable("invalid enum"); 00111 } 00112 00113 static bool isCallableInState(const CallableWhenAttr *CWAttr, 00114 ConsumedState State) { 00115 00116 for (const auto &S : CWAttr->callableStates()) { 00117 ConsumedState MappedAttrState = CS_None; 00118 00119 switch (S) { 00120 case CallableWhenAttr::Unknown: 00121 MappedAttrState = CS_Unknown; 00122 break; 00123 00124 case CallableWhenAttr::Unconsumed: 00125 MappedAttrState = CS_Unconsumed; 00126 break; 00127 00128 case CallableWhenAttr::Consumed: 00129 MappedAttrState = CS_Consumed; 00130 break; 00131 } 00132 00133 if (MappedAttrState == State) 00134 return true; 00135 } 00136 00137 return false; 00138 } 00139 00140 00141 static bool isConsumableType(const QualType &QT) { 00142 if (QT->isPointerType() || QT->isReferenceType()) 00143 return false; 00144 00145 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) 00146 return RD->hasAttr<ConsumableAttr>(); 00147 00148 return false; 00149 } 00150 00151 static bool isAutoCastType(const QualType &QT) { 00152 if (QT->isPointerType() || QT->isReferenceType()) 00153 return false; 00154 00155 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) 00156 return RD->hasAttr<ConsumableAutoCastAttr>(); 00157 00158 return false; 00159 } 00160 00161 static bool isSetOnReadPtrType(const QualType &QT) { 00162 if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl()) 00163 return RD->hasAttr<ConsumableSetOnReadAttr>(); 00164 return false; 00165 } 00166 00167 00168 static bool isKnownState(ConsumedState State) { 00169 switch (State) { 00170 case CS_Unconsumed: 00171 case CS_Consumed: 00172 return true; 00173 case CS_None: 00174 case CS_Unknown: 00175 return false; 00176 } 00177 llvm_unreachable("invalid enum"); 00178 } 00179 00180 static bool isRValueRef(QualType ParamType) { 00181 return ParamType->isRValueReferenceType(); 00182 } 00183 00184 static bool isTestingFunction(const FunctionDecl *FunDecl) { 00185 return FunDecl->hasAttr<TestTypestateAttr>(); 00186 } 00187 00188 static bool isPointerOrRef(QualType ParamType) { 00189 return ParamType->isPointerType() || ParamType->isReferenceType(); 00190 } 00191 00192 static ConsumedState mapConsumableAttrState(const QualType QT) { 00193 assert(isConsumableType(QT)); 00194 00195 const ConsumableAttr *CAttr = 00196 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>(); 00197 00198 switch (CAttr->getDefaultState()) { 00199 case ConsumableAttr::Unknown: 00200 return CS_Unknown; 00201 case ConsumableAttr::Unconsumed: 00202 return CS_Unconsumed; 00203 case ConsumableAttr::Consumed: 00204 return CS_Consumed; 00205 } 00206 llvm_unreachable("invalid enum"); 00207 } 00208 00209 static ConsumedState 00210 mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) { 00211 switch (PTAttr->getParamState()) { 00212 case ParamTypestateAttr::Unknown: 00213 return CS_Unknown; 00214 case ParamTypestateAttr::Unconsumed: 00215 return CS_Unconsumed; 00216 case ParamTypestateAttr::Consumed: 00217 return CS_Consumed; 00218 } 00219 llvm_unreachable("invalid_enum"); 00220 } 00221 00222 static ConsumedState 00223 mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) { 00224 switch (RTSAttr->getState()) { 00225 case ReturnTypestateAttr::Unknown: 00226 return CS_Unknown; 00227 case ReturnTypestateAttr::Unconsumed: 00228 return CS_Unconsumed; 00229 case ReturnTypestateAttr::Consumed: 00230 return CS_Consumed; 00231 } 00232 llvm_unreachable("invalid enum"); 00233 } 00234 00235 static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) { 00236 switch (STAttr->getNewState()) { 00237 case SetTypestateAttr::Unknown: 00238 return CS_Unknown; 00239 case SetTypestateAttr::Unconsumed: 00240 return CS_Unconsumed; 00241 case SetTypestateAttr::Consumed: 00242 return CS_Consumed; 00243 } 00244 llvm_unreachable("invalid_enum"); 00245 } 00246 00247 static StringRef stateToString(ConsumedState State) { 00248 switch (State) { 00249 case consumed::CS_None: 00250 return "none"; 00251 00252 case consumed::CS_Unknown: 00253 return "unknown"; 00254 00255 case consumed::CS_Unconsumed: 00256 return "unconsumed"; 00257 00258 case consumed::CS_Consumed: 00259 return "consumed"; 00260 } 00261 llvm_unreachable("invalid enum"); 00262 } 00263 00264 static ConsumedState testsFor(const FunctionDecl *FunDecl) { 00265 assert(isTestingFunction(FunDecl)); 00266 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) { 00267 case TestTypestateAttr::Unconsumed: 00268 return CS_Unconsumed; 00269 case TestTypestateAttr::Consumed: 00270 return CS_Consumed; 00271 } 00272 llvm_unreachable("invalid enum"); 00273 } 00274 00275 namespace { 00276 struct VarTestResult { 00277 const VarDecl *Var; 00278 ConsumedState TestsFor; 00279 }; 00280 } // end anonymous::VarTestResult 00281 00282 namespace clang { 00283 namespace consumed { 00284 00285 enum EffectiveOp { 00286 EO_And, 00287 EO_Or 00288 }; 00289 00290 class PropagationInfo { 00291 enum { 00292 IT_None, 00293 IT_State, 00294 IT_VarTest, 00295 IT_BinTest, 00296 IT_Var, 00297 IT_Tmp 00298 } InfoType; 00299 00300 struct BinTestTy { 00301 const BinaryOperator *Source; 00302 EffectiveOp EOp; 00303 VarTestResult LTest; 00304 VarTestResult RTest; 00305 }; 00306 00307 union { 00308 ConsumedState State; 00309 VarTestResult VarTest; 00310 const VarDecl *Var; 00311 const CXXBindTemporaryExpr *Tmp; 00312 BinTestTy BinTest; 00313 }; 00314 00315 public: 00316 PropagationInfo() : InfoType(IT_None) {} 00317 00318 PropagationInfo(const VarTestResult &VarTest) 00319 : InfoType(IT_VarTest), VarTest(VarTest) {} 00320 00321 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor) 00322 : InfoType(IT_VarTest) { 00323 00324 VarTest.Var = Var; 00325 VarTest.TestsFor = TestsFor; 00326 } 00327 00328 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 00329 const VarTestResult <est, const VarTestResult &RTest) 00330 : InfoType(IT_BinTest) { 00331 00332 BinTest.Source = Source; 00333 BinTest.EOp = EOp; 00334 BinTest.LTest = LTest; 00335 BinTest.RTest = RTest; 00336 } 00337 00338 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 00339 const VarDecl *LVar, ConsumedState LTestsFor, 00340 const VarDecl *RVar, ConsumedState RTestsFor) 00341 : InfoType(IT_BinTest) { 00342 00343 BinTest.Source = Source; 00344 BinTest.EOp = EOp; 00345 BinTest.LTest.Var = LVar; 00346 BinTest.LTest.TestsFor = LTestsFor; 00347 BinTest.RTest.Var = RVar; 00348 BinTest.RTest.TestsFor = RTestsFor; 00349 } 00350 00351 PropagationInfo(ConsumedState State) 00352 : InfoType(IT_State), State(State) {} 00353 00354 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {} 00355 PropagationInfo(const CXXBindTemporaryExpr *Tmp) 00356 : InfoType(IT_Tmp), Tmp(Tmp) {} 00357 00358 const ConsumedState & getState() const { 00359 assert(InfoType == IT_State); 00360 return State; 00361 } 00362 00363 const VarTestResult & getVarTest() const { 00364 assert(InfoType == IT_VarTest); 00365 return VarTest; 00366 } 00367 00368 const VarTestResult & getLTest() const { 00369 assert(InfoType == IT_BinTest); 00370 return BinTest.LTest; 00371 } 00372 00373 const VarTestResult & getRTest() const { 00374 assert(InfoType == IT_BinTest); 00375 return BinTest.RTest; 00376 } 00377 00378 const VarDecl * getVar() const { 00379 assert(InfoType == IT_Var); 00380 return Var; 00381 } 00382 00383 const CXXBindTemporaryExpr * getTmp() const { 00384 assert(InfoType == IT_Tmp); 00385 return Tmp; 00386 } 00387 00388 ConsumedState getAsState(const ConsumedStateMap *StateMap) const { 00389 assert(isVar() || isTmp() || isState()); 00390 00391 if (isVar()) 00392 return StateMap->getState(Var); 00393 else if (isTmp()) 00394 return StateMap->getState(Tmp); 00395 else if (isState()) 00396 return State; 00397 else 00398 return CS_None; 00399 } 00400 00401 EffectiveOp testEffectiveOp() const { 00402 assert(InfoType == IT_BinTest); 00403 return BinTest.EOp; 00404 } 00405 00406 const BinaryOperator * testSourceNode() const { 00407 assert(InfoType == IT_BinTest); 00408 return BinTest.Source; 00409 } 00410 00411 inline bool isValid() const { return InfoType != IT_None; } 00412 inline bool isState() const { return InfoType == IT_State; } 00413 inline bool isVarTest() const { return InfoType == IT_VarTest; } 00414 inline bool isBinTest() const { return InfoType == IT_BinTest; } 00415 inline bool isVar() const { return InfoType == IT_Var; } 00416 inline bool isTmp() const { return InfoType == IT_Tmp; } 00417 00418 bool isTest() const { 00419 return InfoType == IT_VarTest || InfoType == IT_BinTest; 00420 } 00421 00422 bool isPointerToValue() const { 00423 return InfoType == IT_Var || InfoType == IT_Tmp; 00424 } 00425 00426 PropagationInfo invertTest() const { 00427 assert(InfoType == IT_VarTest || InfoType == IT_BinTest); 00428 00429 if (InfoType == IT_VarTest) { 00430 return PropagationInfo(VarTest.Var, 00431 invertConsumedUnconsumed(VarTest.TestsFor)); 00432 00433 } else if (InfoType == IT_BinTest) { 00434 return PropagationInfo(BinTest.Source, 00435 BinTest.EOp == EO_And ? EO_Or : EO_And, 00436 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor), 00437 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor)); 00438 } else { 00439 return PropagationInfo(); 00440 } 00441 } 00442 }; 00443 00444 static inline void 00445 setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo, 00446 ConsumedState State) { 00447 00448 assert(PInfo.isVar() || PInfo.isTmp()); 00449 00450 if (PInfo.isVar()) 00451 StateMap->setState(PInfo.getVar(), State); 00452 else 00453 StateMap->setState(PInfo.getTmp(), State); 00454 } 00455 00456 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> { 00457 00458 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType; 00459 typedef std::pair<const Stmt *, PropagationInfo> PairType; 00460 typedef MapType::iterator InfoEntry; 00461 typedef MapType::const_iterator ConstInfoEntry; 00462 00463 AnalysisDeclContext &AC; 00464 ConsumedAnalyzer &Analyzer; 00465 ConsumedStateMap *StateMap; 00466 MapType PropagationMap; 00467 00468 InfoEntry findInfo(const Expr *E) { 00469 return PropagationMap.find(E->IgnoreParens()); 00470 } 00471 ConstInfoEntry findInfo(const Expr *E) const { 00472 return PropagationMap.find(E->IgnoreParens()); 00473 } 00474 void insertInfo(const Expr *E, const PropagationInfo &PI) { 00475 PropagationMap.insert(PairType(E->IgnoreParens(), PI)); 00476 } 00477 00478 void forwardInfo(const Expr *From, const Expr *To); 00479 void copyInfo(const Expr *From, const Expr *To, ConsumedState CS); 00480 ConsumedState getInfo(const Expr *From); 00481 void setInfo(const Expr *To, ConsumedState NS); 00482 void propagateReturnType(const Expr *Call, const FunctionDecl *Fun); 00483 00484 public: 00485 void checkCallability(const PropagationInfo &PInfo, 00486 const FunctionDecl *FunDecl, 00487 SourceLocation BlameLoc); 00488 bool handleCall(const CallExpr *Call, const Expr *ObjArg, 00489 const FunctionDecl *FunD); 00490 00491 void VisitBinaryOperator(const BinaryOperator *BinOp); 00492 void VisitCallExpr(const CallExpr *Call); 00493 void VisitCastExpr(const CastExpr *Cast); 00494 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp); 00495 void VisitCXXConstructExpr(const CXXConstructExpr *Call); 00496 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call); 00497 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call); 00498 void VisitDeclRefExpr(const DeclRefExpr *DeclRef); 00499 void VisitDeclStmt(const DeclStmt *DelcS); 00500 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp); 00501 void VisitMemberExpr(const MemberExpr *MExpr); 00502 void VisitParmVarDecl(const ParmVarDecl *Param); 00503 void VisitReturnStmt(const ReturnStmt *Ret); 00504 void VisitUnaryOperator(const UnaryOperator *UOp); 00505 void VisitVarDecl(const VarDecl *Var); 00506 00507 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer, 00508 ConsumedStateMap *StateMap) 00509 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {} 00510 00511 PropagationInfo getInfo(const Expr *StmtNode) const { 00512 ConstInfoEntry Entry = findInfo(StmtNode); 00513 00514 if (Entry != PropagationMap.end()) 00515 return Entry->second; 00516 else 00517 return PropagationInfo(); 00518 } 00519 00520 void reset(ConsumedStateMap *NewStateMap) { 00521 StateMap = NewStateMap; 00522 } 00523 }; 00524 00525 00526 void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) { 00527 InfoEntry Entry = findInfo(From); 00528 if (Entry != PropagationMap.end()) 00529 insertInfo(To, Entry->second); 00530 } 00531 00532 00533 // Create a new state for To, which is initialized to the state of From. 00534 // If NS is not CS_None, sets the state of From to NS. 00535 void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To, 00536 ConsumedState NS) { 00537 InfoEntry Entry = findInfo(From); 00538 if (Entry != PropagationMap.end()) { 00539 PropagationInfo& PInfo = Entry->second; 00540 ConsumedState CS = PInfo.getAsState(StateMap); 00541 if (CS != CS_None) 00542 insertInfo(To, PropagationInfo(CS)); 00543 if (NS != CS_None && PInfo.isPointerToValue()) 00544 setStateForVarOrTmp(StateMap, PInfo, NS); 00545 } 00546 } 00547 00548 00549 // Get the ConsumedState for From 00550 ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) { 00551 InfoEntry Entry = findInfo(From); 00552 if (Entry != PropagationMap.end()) { 00553 PropagationInfo& PInfo = Entry->second; 00554 return PInfo.getAsState(StateMap); 00555 } 00556 return CS_None; 00557 } 00558 00559 00560 // If we already have info for To then update it, otherwise create a new entry. 00561 void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) { 00562 InfoEntry Entry = findInfo(To); 00563 if (Entry != PropagationMap.end()) { 00564 PropagationInfo& PInfo = Entry->second; 00565 if (PInfo.isPointerToValue()) 00566 setStateForVarOrTmp(StateMap, PInfo, NS); 00567 } else if (NS != CS_None) { 00568 insertInfo(To, PropagationInfo(NS)); 00569 } 00570 } 00571 00572 00573 00574 void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, 00575 const FunctionDecl *FunDecl, 00576 SourceLocation BlameLoc) { 00577 assert(!PInfo.isTest()); 00578 00579 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>(); 00580 if (!CWAttr) 00581 return; 00582 00583 if (PInfo.isVar()) { 00584 ConsumedState VarState = StateMap->getState(PInfo.getVar()); 00585 00586 if (VarState == CS_None || isCallableInState(CWAttr, VarState)) 00587 return; 00588 00589 Analyzer.WarningsHandler.warnUseInInvalidState( 00590 FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(), 00591 stateToString(VarState), BlameLoc); 00592 00593 } else { 00594 ConsumedState TmpState = PInfo.getAsState(StateMap); 00595 00596 if (TmpState == CS_None || isCallableInState(CWAttr, TmpState)) 00597 return; 00598 00599 Analyzer.WarningsHandler.warnUseOfTempInInvalidState( 00600 FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc); 00601 } 00602 } 00603 00604 00605 // Factors out common behavior for function, method, and operator calls. 00606 // Check parameters and set parameter state if necessary. 00607 // Returns true if the state of ObjArg is set, or false otherwise. 00608 bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg, 00609 const FunctionDecl *FunD) { 00610 unsigned Offset = 0; 00611 if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD)) 00612 Offset = 1; // first argument is 'this' 00613 00614 // check explicit parameters 00615 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) { 00616 // Skip variable argument lists. 00617 if (Index - Offset >= FunD->getNumParams()) 00618 break; 00619 00620 const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset); 00621 QualType ParamType = Param->getType(); 00622 00623 InfoEntry Entry = findInfo(Call->getArg(Index)); 00624 00625 if (Entry == PropagationMap.end() || Entry->second.isTest()) 00626 continue; 00627 PropagationInfo PInfo = Entry->second; 00628 00629 // Check that the parameter is in the correct state. 00630 if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) { 00631 ConsumedState ParamState = PInfo.getAsState(StateMap); 00632 ConsumedState ExpectedState = mapParamTypestateAttrState(PTA); 00633 00634 if (ParamState != ExpectedState) 00635 Analyzer.WarningsHandler.warnParamTypestateMismatch( 00636 Call->getArg(Index)->getExprLoc(), 00637 stateToString(ExpectedState), stateToString(ParamState)); 00638 } 00639 00640 if (!(Entry->second.isVar() || Entry->second.isTmp())) 00641 continue; 00642 00643 // Adjust state on the caller side. 00644 if (isRValueRef(ParamType)) 00645 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed); 00646 else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>()) 00647 setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT)); 00648 else if (isPointerOrRef(ParamType) && 00649 (!ParamType->getPointeeType().isConstQualified() || 00650 isSetOnReadPtrType(ParamType))) 00651 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown); 00652 } 00653 00654 if (!ObjArg) 00655 return false; 00656 00657 // check implicit 'self' parameter, if present 00658 InfoEntry Entry = findInfo(ObjArg); 00659 if (Entry != PropagationMap.end()) { 00660 PropagationInfo PInfo = Entry->second; 00661 checkCallability(PInfo, FunD, Call->getExprLoc()); 00662 00663 if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) { 00664 if (PInfo.isVar()) { 00665 StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA)); 00666 return true; 00667 } 00668 else if (PInfo.isTmp()) { 00669 StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA)); 00670 return true; 00671 } 00672 } 00673 else if (isTestingFunction(FunD) && PInfo.isVar()) { 00674 PropagationMap.insert(PairType(Call, 00675 PropagationInfo(PInfo.getVar(), testsFor(FunD)))); 00676 } 00677 } 00678 return false; 00679 } 00680 00681 00682 void ConsumedStmtVisitor::propagateReturnType(const Expr *Call, 00683 const FunctionDecl *Fun) { 00684 QualType RetType = Fun->getCallResultType(); 00685 if (RetType->isReferenceType()) 00686 RetType = RetType->getPointeeType(); 00687 00688 if (isConsumableType(RetType)) { 00689 ConsumedState ReturnState; 00690 if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>()) 00691 ReturnState = mapReturnTypestateAttrState(RTA); 00692 else 00693 ReturnState = mapConsumableAttrState(RetType); 00694 00695 PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState))); 00696 } 00697 } 00698 00699 00700 void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) { 00701 switch (BinOp->getOpcode()) { 00702 case BO_LAnd: 00703 case BO_LOr : { 00704 InfoEntry LEntry = findInfo(BinOp->getLHS()), 00705 REntry = findInfo(BinOp->getRHS()); 00706 00707 VarTestResult LTest, RTest; 00708 00709 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) { 00710 LTest = LEntry->second.getVarTest(); 00711 00712 } else { 00713 LTest.Var = nullptr; 00714 LTest.TestsFor = CS_None; 00715 } 00716 00717 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) { 00718 RTest = REntry->second.getVarTest(); 00719 00720 } else { 00721 RTest.Var = nullptr; 00722 RTest.TestsFor = CS_None; 00723 } 00724 00725 if (!(LTest.Var == nullptr && RTest.Var == nullptr)) 00726 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp, 00727 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest))); 00728 00729 break; 00730 } 00731 00732 case BO_PtrMemD: 00733 case BO_PtrMemI: 00734 forwardInfo(BinOp->getLHS(), BinOp); 00735 break; 00736 00737 default: 00738 break; 00739 } 00740 } 00741 00742 void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { 00743 const FunctionDecl *FunDecl = Call->getDirectCallee(); 00744 if (!FunDecl) 00745 return; 00746 00747 // Special case for the std::move function. 00748 // TODO: Make this more specific. (Deferred) 00749 if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" && 00750 FunDecl->isInStdNamespace()) { 00751 copyInfo(Call->getArg(0), Call, CS_Consumed); 00752 return; 00753 } 00754 00755 handleCall(Call, nullptr, FunDecl); 00756 propagateReturnType(Call, FunDecl); 00757 } 00758 00759 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) { 00760 forwardInfo(Cast->getSubExpr(), Cast); 00761 } 00762 00763 void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr( 00764 const CXXBindTemporaryExpr *Temp) { 00765 00766 InfoEntry Entry = findInfo(Temp->getSubExpr()); 00767 00768 if (Entry != PropagationMap.end() && !Entry->second.isTest()) { 00769 StateMap->setState(Temp, Entry->second.getAsState(StateMap)); 00770 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp))); 00771 } 00772 } 00773 00774 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { 00775 CXXConstructorDecl *Constructor = Call->getConstructor(); 00776 00777 ASTContext &CurrContext = AC.getASTContext(); 00778 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType(); 00779 00780 if (!isConsumableType(ThisType)) 00781 return; 00782 00783 // FIXME: What should happen if someone annotates the move constructor? 00784 if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) { 00785 // TODO: Adjust state of args appropriately. 00786 ConsumedState RetState = mapReturnTypestateAttrState(RTA); 00787 PropagationMap.insert(PairType(Call, PropagationInfo(RetState))); 00788 } else if (Constructor->isDefaultConstructor()) { 00789 PropagationMap.insert(PairType(Call, 00790 PropagationInfo(consumed::CS_Consumed))); 00791 } else if (Constructor->isMoveConstructor()) { 00792 copyInfo(Call->getArg(0), Call, CS_Consumed); 00793 } else if (Constructor->isCopyConstructor()) { 00794 // Copy state from arg. If setStateOnRead then set arg to CS_Unknown. 00795 ConsumedState NS = 00796 isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ? 00797 CS_Unknown : CS_None; 00798 copyInfo(Call->getArg(0), Call, NS); 00799 } else { 00800 // TODO: Adjust state of args appropriately. 00801 ConsumedState RetState = mapConsumableAttrState(ThisType); 00802 PropagationMap.insert(PairType(Call, PropagationInfo(RetState))); 00803 } 00804 } 00805 00806 00807 void ConsumedStmtVisitor::VisitCXXMemberCallExpr( 00808 const CXXMemberCallExpr *Call) { 00809 CXXMethodDecl* MD = Call->getMethodDecl(); 00810 if (!MD) 00811 return; 00812 00813 handleCall(Call, Call->getImplicitObjectArgument(), MD); 00814 propagateReturnType(Call, MD); 00815 } 00816 00817 00818 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr( 00819 const CXXOperatorCallExpr *Call) { 00820 00821 const FunctionDecl *FunDecl = 00822 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee()); 00823 if (!FunDecl) return; 00824 00825 if (Call->getOperator() == OO_Equal) { 00826 ConsumedState CS = getInfo(Call->getArg(1)); 00827 if (!handleCall(Call, Call->getArg(0), FunDecl)) 00828 setInfo(Call->getArg(0), CS); 00829 return; 00830 } 00831 00832 if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call)) 00833 handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl); 00834 else 00835 handleCall(Call, Call->getArg(0), FunDecl); 00836 00837 propagateReturnType(Call, FunDecl); 00838 } 00839 00840 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) { 00841 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) 00842 if (StateMap->getState(Var) != consumed::CS_None) 00843 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var))); 00844 } 00845 00846 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) { 00847 for (const auto *DI : DeclS->decls()) 00848 if (isa<VarDecl>(DI)) 00849 VisitVarDecl(cast<VarDecl>(DI)); 00850 00851 if (DeclS->isSingleDecl()) 00852 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl())) 00853 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var))); 00854 } 00855 00856 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr( 00857 const MaterializeTemporaryExpr *Temp) { 00858 00859 forwardInfo(Temp->GetTemporaryExpr(), Temp); 00860 } 00861 00862 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) { 00863 forwardInfo(MExpr->getBase(), MExpr); 00864 } 00865 00866 00867 void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { 00868 QualType ParamType = Param->getType(); 00869 ConsumedState ParamState = consumed::CS_None; 00870 00871 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) 00872 ParamState = mapParamTypestateAttrState(PTA); 00873 else if (isConsumableType(ParamType)) 00874 ParamState = mapConsumableAttrState(ParamType); 00875 else if (isRValueRef(ParamType) && 00876 isConsumableType(ParamType->getPointeeType())) 00877 ParamState = mapConsumableAttrState(ParamType->getPointeeType()); 00878 else if (ParamType->isReferenceType() && 00879 isConsumableType(ParamType->getPointeeType())) 00880 ParamState = consumed::CS_Unknown; 00881 00882 if (ParamState != CS_None) 00883 StateMap->setState(Param, ParamState); 00884 } 00885 00886 void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { 00887 ConsumedState ExpectedState = Analyzer.getExpectedReturnState(); 00888 00889 if (ExpectedState != CS_None) { 00890 InfoEntry Entry = findInfo(Ret->getRetValue()); 00891 00892 if (Entry != PropagationMap.end()) { 00893 ConsumedState RetState = Entry->second.getAsState(StateMap); 00894 00895 if (RetState != ExpectedState) 00896 Analyzer.WarningsHandler.warnReturnTypestateMismatch( 00897 Ret->getReturnLoc(), stateToString(ExpectedState), 00898 stateToString(RetState)); 00899 } 00900 } 00901 00902 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(), 00903 Analyzer.WarningsHandler); 00904 } 00905 00906 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) { 00907 InfoEntry Entry = findInfo(UOp->getSubExpr()); 00908 if (Entry == PropagationMap.end()) return; 00909 00910 switch (UOp->getOpcode()) { 00911 case UO_AddrOf: 00912 PropagationMap.insert(PairType(UOp, Entry->second)); 00913 break; 00914 00915 case UO_LNot: 00916 if (Entry->second.isTest()) 00917 PropagationMap.insert(PairType(UOp, Entry->second.invertTest())); 00918 break; 00919 00920 default: 00921 break; 00922 } 00923 } 00924 00925 // TODO: See if I need to check for reference types here. 00926 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { 00927 if (isConsumableType(Var->getType())) { 00928 if (Var->hasInit()) { 00929 MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit()); 00930 if (VIT != PropagationMap.end()) { 00931 PropagationInfo PInfo = VIT->second; 00932 ConsumedState St = PInfo.getAsState(StateMap); 00933 00934 if (St != consumed::CS_None) { 00935 StateMap->setState(Var, St); 00936 return; 00937 } 00938 } 00939 } 00940 // Otherwise 00941 StateMap->setState(Var, consumed::CS_Unknown); 00942 } 00943 } 00944 }} // end clang::consumed::ConsumedStmtVisitor 00945 00946 namespace clang { 00947 namespace consumed { 00948 00949 void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, 00950 ConsumedStateMap *ThenStates, 00951 ConsumedStateMap *ElseStates) { 00952 00953 ConsumedState VarState = ThenStates->getState(Test.Var); 00954 00955 if (VarState == CS_Unknown) { 00956 ThenStates->setState(Test.Var, Test.TestsFor); 00957 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 00958 00959 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) { 00960 ThenStates->markUnreachable(); 00961 00962 } else if (VarState == Test.TestsFor) { 00963 ElseStates->markUnreachable(); 00964 } 00965 } 00966 00967 void splitVarStateForIfBinOp(const PropagationInfo &PInfo, 00968 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { 00969 00970 const VarTestResult <est = PInfo.getLTest(), 00971 &RTest = PInfo.getRTest(); 00972 00973 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None, 00974 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None; 00975 00976 if (LTest.Var) { 00977 if (PInfo.testEffectiveOp() == EO_And) { 00978 if (LState == CS_Unknown) { 00979 ThenStates->setState(LTest.Var, LTest.TestsFor); 00980 00981 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) { 00982 ThenStates->markUnreachable(); 00983 00984 } else if (LState == LTest.TestsFor && isKnownState(RState)) { 00985 if (RState == RTest.TestsFor) 00986 ElseStates->markUnreachable(); 00987 else 00988 ThenStates->markUnreachable(); 00989 } 00990 00991 } else { 00992 if (LState == CS_Unknown) { 00993 ElseStates->setState(LTest.Var, 00994 invertConsumedUnconsumed(LTest.TestsFor)); 00995 00996 } else if (LState == LTest.TestsFor) { 00997 ElseStates->markUnreachable(); 00998 00999 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) && 01000 isKnownState(RState)) { 01001 01002 if (RState == RTest.TestsFor) 01003 ElseStates->markUnreachable(); 01004 else 01005 ThenStates->markUnreachable(); 01006 } 01007 } 01008 } 01009 01010 if (RTest.Var) { 01011 if (PInfo.testEffectiveOp() == EO_And) { 01012 if (RState == CS_Unknown) 01013 ThenStates->setState(RTest.Var, RTest.TestsFor); 01014 else if (RState == invertConsumedUnconsumed(RTest.TestsFor)) 01015 ThenStates->markUnreachable(); 01016 01017 } else { 01018 if (RState == CS_Unknown) 01019 ElseStates->setState(RTest.Var, 01020 invertConsumedUnconsumed(RTest.TestsFor)); 01021 else if (RState == RTest.TestsFor) 01022 ElseStates->markUnreachable(); 01023 } 01024 } 01025 } 01026 01027 bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock, 01028 const CFGBlock *TargetBlock) { 01029 01030 assert(CurrBlock && "Block pointer must not be NULL"); 01031 assert(TargetBlock && "TargetBlock pointer must not be NULL"); 01032 01033 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()]; 01034 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(), 01035 PE = TargetBlock->pred_end(); PI != PE; ++PI) { 01036 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] ) 01037 return false; 01038 } 01039 return true; 01040 } 01041 01042 void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 01043 ConsumedStateMap *StateMap, 01044 bool &AlreadyOwned) { 01045 01046 assert(Block && "Block pointer must not be NULL"); 01047 01048 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 01049 01050 if (Entry) { 01051 Entry->intersect(StateMap); 01052 01053 } else if (AlreadyOwned) { 01054 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap); 01055 01056 } else { 01057 StateMapsArray[Block->getBlockID()] = StateMap; 01058 AlreadyOwned = true; 01059 } 01060 } 01061 01062 void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 01063 ConsumedStateMap *StateMap) { 01064 01065 assert(Block && "Block pointer must not be NULL"); 01066 01067 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 01068 01069 if (Entry) { 01070 Entry->intersect(StateMap); 01071 delete StateMap; 01072 01073 } else { 01074 StateMapsArray[Block->getBlockID()] = StateMap; 01075 } 01076 } 01077 01078 ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) { 01079 assert(Block && "Block pointer must not be NULL"); 01080 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info"); 01081 01082 return StateMapsArray[Block->getBlockID()]; 01083 } 01084 01085 void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) { 01086 unsigned int BlockID = Block->getBlockID(); 01087 delete StateMapsArray[BlockID]; 01088 StateMapsArray[BlockID] = nullptr; 01089 } 01090 01091 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) { 01092 assert(Block && "Block pointer must not be NULL"); 01093 01094 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()]; 01095 if (isBackEdgeTarget(Block)) { 01096 return new ConsumedStateMap(*StateMap); 01097 } else { 01098 StateMapsArray[Block->getBlockID()] = nullptr; 01099 return StateMap; 01100 } 01101 } 01102 01103 bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) { 01104 assert(From && "From block must not be NULL"); 01105 assert(To && "From block must not be NULL"); 01106 01107 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()]; 01108 } 01109 01110 bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) { 01111 assert(Block && "Block pointer must not be NULL"); 01112 01113 // Anything with less than two predecessors can't be the target of a back 01114 // edge. 01115 if (Block->pred_size() < 2) 01116 return false; 01117 01118 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()]; 01119 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(), 01120 PE = Block->pred_end(); PI != PE; ++PI) { 01121 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]) 01122 return true; 01123 } 01124 return false; 01125 } 01126 01127 void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc, 01128 ConsumedWarningsHandlerBase &WarningsHandler) const { 01129 01130 for (const auto &DM : VarMap) { 01131 if (isa<ParmVarDecl>(DM.first)) { 01132 const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first); 01133 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>(); 01134 01135 if (!RTA) 01136 continue; 01137 01138 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA); 01139 if (DM.second != ExpectedState) 01140 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc, 01141 Param->getNameAsString(), stateToString(ExpectedState), 01142 stateToString(DM.second)); 01143 } 01144 } 01145 } 01146 01147 void ConsumedStateMap::clearTemporaries() { 01148 TmpMap.clear(); 01149 } 01150 01151 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const { 01152 VarMapType::const_iterator Entry = VarMap.find(Var); 01153 01154 if (Entry != VarMap.end()) 01155 return Entry->second; 01156 01157 return CS_None; 01158 } 01159 01160 ConsumedState 01161 ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const { 01162 TmpMapType::const_iterator Entry = TmpMap.find(Tmp); 01163 01164 if (Entry != TmpMap.end()) 01165 return Entry->second; 01166 01167 return CS_None; 01168 } 01169 01170 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) { 01171 ConsumedState LocalState; 01172 01173 if (this->From && this->From == Other->From && !Other->Reachable) { 01174 this->markUnreachable(); 01175 return; 01176 } 01177 01178 for (const auto &DM : Other->VarMap) { 01179 LocalState = this->getState(DM.first); 01180 01181 if (LocalState == CS_None) 01182 continue; 01183 01184 if (LocalState != DM.second) 01185 VarMap[DM.first] = CS_Unknown; 01186 } 01187 } 01188 01189 void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead, 01190 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, 01191 ConsumedWarningsHandlerBase &WarningsHandler) { 01192 01193 ConsumedState LocalState; 01194 SourceLocation BlameLoc = getLastStmtLoc(LoopBack); 01195 01196 for (const auto &DM : LoopBackStates->VarMap) { 01197 LocalState = this->getState(DM.first); 01198 01199 if (LocalState == CS_None) 01200 continue; 01201 01202 if (LocalState != DM.second) { 01203 VarMap[DM.first] = CS_Unknown; 01204 WarningsHandler.warnLoopStateMismatch(BlameLoc, 01205 DM.first->getNameAsString()); 01206 } 01207 } 01208 } 01209 01210 void ConsumedStateMap::markUnreachable() { 01211 this->Reachable = false; 01212 VarMap.clear(); 01213 TmpMap.clear(); 01214 } 01215 01216 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) { 01217 VarMap[Var] = State; 01218 } 01219 01220 void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp, 01221 ConsumedState State) { 01222 TmpMap[Tmp] = State; 01223 } 01224 01225 void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) { 01226 TmpMap.erase(Tmp); 01227 } 01228 01229 bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const { 01230 for (const auto &DM : Other->VarMap) 01231 if (this->getState(DM.first) != DM.second) 01232 return true; 01233 return false; 01234 } 01235 01236 void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC, 01237 const FunctionDecl *D) { 01238 QualType ReturnType; 01239 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { 01240 ASTContext &CurrContext = AC.getASTContext(); 01241 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType(); 01242 } else 01243 ReturnType = D->getCallResultType(); 01244 01245 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) { 01246 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); 01247 if (!RD || !RD->hasAttr<ConsumableAttr>()) { 01248 // FIXME: This should be removed when template instantiation propagates 01249 // attributes at template specialization definition, not 01250 // declaration. When it is removed the test needs to be enabled 01251 // in SemaDeclAttr.cpp. 01252 WarningsHandler.warnReturnTypestateForUnconsumableType( 01253 RTSAttr->getLocation(), ReturnType.getAsString()); 01254 ExpectedReturnState = CS_None; 01255 } else 01256 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr); 01257 } else if (isConsumableType(ReturnType)) { 01258 if (isAutoCastType(ReturnType)) // We can auto-cast the state to the 01259 ExpectedReturnState = CS_None; // expected state. 01260 else 01261 ExpectedReturnState = mapConsumableAttrState(ReturnType); 01262 } 01263 else 01264 ExpectedReturnState = CS_None; 01265 } 01266 01267 bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock, 01268 const ConsumedStmtVisitor &Visitor) { 01269 01270 std::unique_ptr<ConsumedStateMap> FalseStates( 01271 new ConsumedStateMap(*CurrStates)); 01272 PropagationInfo PInfo; 01273 01274 if (const IfStmt *IfNode = 01275 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) { 01276 01277 const Expr *Cond = IfNode->getCond(); 01278 01279 PInfo = Visitor.getInfo(Cond); 01280 if (!PInfo.isValid() && isa<BinaryOperator>(Cond)) 01281 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS()); 01282 01283 if (PInfo.isVarTest()) { 01284 CurrStates->setSource(Cond); 01285 FalseStates->setSource(Cond); 01286 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates, 01287 FalseStates.get()); 01288 01289 } else if (PInfo.isBinTest()) { 01290 CurrStates->setSource(PInfo.testSourceNode()); 01291 FalseStates->setSource(PInfo.testSourceNode()); 01292 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get()); 01293 01294 } else { 01295 return false; 01296 } 01297 01298 } else if (const BinaryOperator *BinOp = 01299 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) { 01300 01301 PInfo = Visitor.getInfo(BinOp->getLHS()); 01302 if (!PInfo.isVarTest()) { 01303 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) { 01304 PInfo = Visitor.getInfo(BinOp->getRHS()); 01305 01306 if (!PInfo.isVarTest()) 01307 return false; 01308 01309 } else { 01310 return false; 01311 } 01312 } 01313 01314 CurrStates->setSource(BinOp); 01315 FalseStates->setSource(BinOp); 01316 01317 const VarTestResult &Test = PInfo.getVarTest(); 01318 ConsumedState VarState = CurrStates->getState(Test.Var); 01319 01320 if (BinOp->getOpcode() == BO_LAnd) { 01321 if (VarState == CS_Unknown) 01322 CurrStates->setState(Test.Var, Test.TestsFor); 01323 else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) 01324 CurrStates->markUnreachable(); 01325 01326 } else if (BinOp->getOpcode() == BO_LOr) { 01327 if (VarState == CS_Unknown) 01328 FalseStates->setState(Test.Var, 01329 invertConsumedUnconsumed(Test.TestsFor)); 01330 else if (VarState == Test.TestsFor) 01331 FalseStates->markUnreachable(); 01332 } 01333 01334 } else { 01335 return false; 01336 } 01337 01338 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(); 01339 01340 if (*SI) 01341 BlockInfo.addInfo(*SI, CurrStates); 01342 else 01343 delete CurrStates; 01344 01345 if (*++SI) 01346 BlockInfo.addInfo(*SI, FalseStates.release()); 01347 01348 CurrStates = nullptr; 01349 return true; 01350 } 01351 01352 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { 01353 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl()); 01354 if (!D) 01355 return; 01356 01357 CFG *CFGraph = AC.getCFG(); 01358 if (!CFGraph) 01359 return; 01360 01361 determineExpectedReturnState(AC, D); 01362 01363 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); 01364 // AC.getCFG()->viewCFG(LangOptions()); 01365 01366 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph); 01367 01368 CurrStates = new ConsumedStateMap(); 01369 ConsumedStmtVisitor Visitor(AC, *this, CurrStates); 01370 01371 // Add all trackable parameters to the state map. 01372 for (const auto *PI : D->params()) 01373 Visitor.VisitParmVarDecl(PI); 01374 01375 // Visit all of the function's basic blocks. 01376 for (const auto *CurrBlock : *SortedGraph) { 01377 if (!CurrStates) 01378 CurrStates = BlockInfo.getInfo(CurrBlock); 01379 01380 if (!CurrStates) { 01381 continue; 01382 01383 } else if (!CurrStates->isReachable()) { 01384 delete CurrStates; 01385 CurrStates = nullptr; 01386 continue; 01387 } 01388 01389 Visitor.reset(CurrStates); 01390 01391 // Visit all of the basic block's statements. 01392 for (const auto &B : *CurrBlock) { 01393 switch (B.getKind()) { 01394 case CFGElement::Statement: 01395 Visitor.Visit(B.castAs<CFGStmt>().getStmt()); 01396 break; 01397 01398 case CFGElement::TemporaryDtor: { 01399 const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>(); 01400 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr(); 01401 01402 Visitor.checkCallability(PropagationInfo(BTE), 01403 DTor.getDestructorDecl(AC.getASTContext()), 01404 BTE->getExprLoc()); 01405 CurrStates->remove(BTE); 01406 break; 01407 } 01408 01409 case CFGElement::AutomaticObjectDtor: { 01410 const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>(); 01411 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd(); 01412 const VarDecl *Var = DTor.getVarDecl(); 01413 01414 Visitor.checkCallability(PropagationInfo(Var), 01415 DTor.getDestructorDecl(AC.getASTContext()), 01416 Loc); 01417 break; 01418 } 01419 01420 default: 01421 break; 01422 } 01423 } 01424 01425 // TODO: Handle other forms of branching with precision, including while- 01426 // and for-loops. (Deferred) 01427 if (!splitState(CurrBlock, Visitor)) { 01428 CurrStates->setSource(nullptr); 01429 01430 if (CurrBlock->succ_size() > 1 || 01431 (CurrBlock->succ_size() == 1 && 01432 (*CurrBlock->succ_begin())->pred_size() > 1)) { 01433 01434 bool OwnershipTaken = false; 01435 01436 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), 01437 SE = CurrBlock->succ_end(); SI != SE; ++SI) { 01438 01439 if (*SI == nullptr) continue; 01440 01441 if (BlockInfo.isBackEdge(CurrBlock, *SI)) { 01442 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock, 01443 CurrStates, 01444 WarningsHandler); 01445 01446 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) 01447 BlockInfo.discardInfo(*SI); 01448 } else { 01449 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); 01450 } 01451 } 01452 01453 if (!OwnershipTaken) 01454 delete CurrStates; 01455 01456 CurrStates = nullptr; 01457 } 01458 } 01459 01460 if (CurrBlock == &AC.getCFG()->getExit() && 01461 D->getCallResultType()->isVoidType()) 01462 CurrStates->checkParamsForReturnTypestate(D->getLocation(), 01463 WarningsHandler); 01464 } // End of block iterator. 01465 01466 // Delete the last existing state map. 01467 delete CurrStates; 01468 01469 WarningsHandler.emitDiagnostics(); 01470 } 01471 }} // end namespace clang::consumed