AnalysisBasedWarnings.cpp revision 341825
1205408Srdivacky//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// 2205408Srdivacky// 3205408Srdivacky// The LLVM Compiler Infrastructure 4205408Srdivacky// 5205408Srdivacky// This file is distributed under the University of Illinois Open Source 6205408Srdivacky// License. See LICENSE.TXT for details. 7205408Srdivacky// 8205408Srdivacky//===----------------------------------------------------------------------===// 9205408Srdivacky// 10205408Srdivacky// This file defines analysis_warnings::[Policy,Executor]. 11205408Srdivacky// Together they are used by Sema to issue warnings based on inexpensive 12205408Srdivacky// static analysis algorithms in libAnalysis. 13205408Srdivacky// 14205408Srdivacky//===----------------------------------------------------------------------===// 15205408Srdivacky 16212904Sdim#include "clang/Sema/AnalysisBasedWarnings.h" 17249423Sdim#include "clang/AST/DeclCXX.h" 18212904Sdim#include "clang/AST/DeclObjC.h" 19249423Sdim#include "clang/AST/EvaluatedExprVisitor.h" 20249423Sdim#include "clang/AST/ExprCXX.h" 21205408Srdivacky#include "clang/AST/ExprObjC.h" 22249423Sdim#include "clang/AST/ParentMap.h" 23249423Sdim#include "clang/AST/RecursiveASTVisitor.h" 24249423Sdim#include "clang/AST/StmtCXX.h" 25205408Srdivacky#include "clang/AST/StmtObjC.h" 26226633Sdim#include "clang/AST/StmtVisitor.h" 27249423Sdim#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" 28261991Sdim#include "clang/Analysis/Analyses/Consumed.h" 29249423Sdim#include "clang/Analysis/Analyses/ReachableCode.h" 30249423Sdim#include "clang/Analysis/Analyses/ThreadSafety.h" 31249423Sdim#include "clang/Analysis/Analyses/UninitializedValues.h" 32327952Sdim#include "clang/Analysis/AnalysisDeclContext.h" 33205408Srdivacky#include "clang/Analysis/CFG.h" 34219077Sdim#include "clang/Analysis/CFGStmtMap.h" 35249423Sdim#include "clang/Basic/SourceLocation.h" 36249423Sdim#include "clang/Basic/SourceManager.h" 37249423Sdim#include "clang/Lex/Preprocessor.h" 38249423Sdim#include "clang/Sema/ScopeInfo.h" 39249423Sdim#include "clang/Sema/SemaInternal.h" 40205408Srdivacky#include "llvm/ADT/BitVector.h" 41249423Sdim#include "llvm/ADT/MapVector.h" 42243830Sdim#include "llvm/ADT/SmallString.h" 43226633Sdim#include "llvm/ADT/SmallVector.h" 44226633Sdim#include "llvm/ADT/StringRef.h" 45205408Srdivacky#include "llvm/Support/Casting.h" 46226633Sdim#include <algorithm> 47249423Sdim#include <deque> 48239462Sdim#include <iterator> 49205408Srdivacky 50205408Srdivackyusing namespace clang; 51205408Srdivacky 52205408Srdivacky//===----------------------------------------------------------------------===// 53205408Srdivacky// Unreachable code analysis. 54205408Srdivacky//===----------------------------------------------------------------------===// 55205408Srdivacky 56205408Srdivackynamespace { 57205408Srdivacky class UnreachableCodeHandler : public reachable_code::Callback { 58205408Srdivacky Sema &S; 59314564Sdim SourceRange PreviousSilenceableCondVal; 60314564Sdim 61205408Srdivacky public: 62205408Srdivacky UnreachableCodeHandler(Sema &s) : S(s) {} 63205408Srdivacky 64276479Sdim void HandleUnreachable(reachable_code::UnreachableKind UK, 65276479Sdim SourceLocation L, 66276479Sdim SourceRange SilenceableCondVal, 67276479Sdim SourceRange R1, 68276479Sdim SourceRange R2) override { 69314564Sdim // Avoid reporting multiple unreachable code diagnostics that are 70314564Sdim // triggered by the same conditional value. 71314564Sdim if (PreviousSilenceableCondVal.isValid() && 72314564Sdim SilenceableCondVal.isValid() && 73314564Sdim PreviousSilenceableCondVal == SilenceableCondVal) 74314564Sdim return; 75314564Sdim PreviousSilenceableCondVal = SilenceableCondVal; 76314564Sdim 77276479Sdim unsigned diag = diag::warn_unreachable; 78276479Sdim switch (UK) { 79276479Sdim case reachable_code::UK_Break: 80276479Sdim diag = diag::warn_unreachable_break; 81276479Sdim break; 82276479Sdim case reachable_code::UK_Return: 83276479Sdim diag = diag::warn_unreachable_return; 84276479Sdim break; 85276479Sdim case reachable_code::UK_Loop_Increment: 86276479Sdim diag = diag::warn_unreachable_loop_increment; 87276479Sdim break; 88276479Sdim case reachable_code::UK_Other: 89276479Sdim break; 90276479Sdim } 91276479Sdim 92276479Sdim S.Diag(L, diag) << R1 << R2; 93341825Sdim 94276479Sdim SourceLocation Open = SilenceableCondVal.getBegin(); 95276479Sdim if (Open.isValid()) { 96276479Sdim SourceLocation Close = SilenceableCondVal.getEnd(); 97276479Sdim Close = S.getLocForEndOfToken(Close); 98276479Sdim if (Close.isValid()) { 99276479Sdim S.Diag(Open, diag::note_unreachable_silence) 100276479Sdim << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (") 101276479Sdim << FixItHint::CreateInsertion(Close, ")"); 102276479Sdim } 103276479Sdim } 104205408Srdivacky } 105205408Srdivacky }; 106296417Sdim} // anonymous namespace 107205408Srdivacky 108205408Srdivacky/// CheckUnreachable - Check for unreachable code. 109234353Sdimstatic void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) { 110276479Sdim // As a heuristic prune all diagnostics not in the main file. Currently 111276479Sdim // the majority of warnings in headers are false positives. These 112276479Sdim // are largely caused by configuration state, e.g. preprocessor 113276479Sdim // defined code, etc. 114276479Sdim // 115276479Sdim // Note that this is also a performance optimization. Analyzing 116276479Sdim // headers many times can be expensive. 117276479Sdim if (!S.getSourceManager().isInMainFile(AC.getDecl()->getLocStart())) 118276479Sdim return; 119276479Sdim 120205408Srdivacky UnreachableCodeHandler UC(S); 121276479Sdim reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC); 122205408Srdivacky} 123205408Srdivacky 124288943Sdimnamespace { 125341825Sdim/// Warn on logical operator errors in CFGBuilder 126276479Sdimclass LogicalErrorHandler : public CFGCallback { 127276479Sdim Sema &S; 128276479Sdim 129276479Sdimpublic: 130276479Sdim LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {} 131276479Sdim 132276479Sdim static bool HasMacroID(const Expr *E) { 133276479Sdim if (E->getExprLoc().isMacroID()) 134276479Sdim return true; 135276479Sdim 136276479Sdim // Recurse to children. 137288943Sdim for (const Stmt *SubStmt : E->children()) 138288943Sdim if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt)) 139288943Sdim if (HasMacroID(SubExpr)) 140288943Sdim return true; 141276479Sdim 142276479Sdim return false; 143276479Sdim } 144276479Sdim 145288943Sdim void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override { 146276479Sdim if (HasMacroID(B)) 147276479Sdim return; 148276479Sdim 149276479Sdim SourceRange DiagRange = B->getSourceRange(); 150276479Sdim S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison) 151276479Sdim << DiagRange << isAlwaysTrue; 152276479Sdim } 153276479Sdim 154288943Sdim void compareBitwiseEquality(const BinaryOperator *B, 155288943Sdim bool isAlwaysTrue) override { 156276479Sdim if (HasMacroID(B)) 157276479Sdim return; 158276479Sdim 159276479Sdim SourceRange DiagRange = B->getSourceRange(); 160276479Sdim S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always) 161276479Sdim << DiagRange << isAlwaysTrue; 162276479Sdim } 163276479Sdim}; 164296417Sdim} // anonymous namespace 165276479Sdim 166205408Srdivacky//===----------------------------------------------------------------------===// 167276479Sdim// Check for infinite self-recursion in functions 168276479Sdim//===----------------------------------------------------------------------===// 169276479Sdim 170296417Sdim// Returns true if the function is called anywhere within the CFGBlock. 171296417Sdim// For member functions, the additional condition of being call from the 172296417Sdim// this pointer is required. 173296417Sdimstatic bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { 174296417Sdim // Process all the Stmt's in this block to find any calls to FD. 175296417Sdim for (const auto &B : Block) { 176296417Sdim if (B.getKind() != CFGElement::Statement) 177296417Sdim continue; 178296417Sdim 179296417Sdim const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt()); 180296417Sdim if (!CE || !CE->getCalleeDecl() || 181296417Sdim CE->getCalleeDecl()->getCanonicalDecl() != FD) 182296417Sdim continue; 183296417Sdim 184296417Sdim // Skip function calls which are qualified with a templated class. 185296417Sdim if (const DeclRefExpr *DRE = 186296417Sdim dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts())) { 187296417Sdim if (NestedNameSpecifier *NNS = DRE->getQualifier()) { 188296417Sdim if (NNS->getKind() == NestedNameSpecifier::TypeSpec && 189296417Sdim isa<TemplateSpecializationType>(NNS->getAsType())) { 190296417Sdim continue; 191296417Sdim } 192296417Sdim } 193296417Sdim } 194296417Sdim 195296417Sdim const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE); 196296417Sdim if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) || 197296417Sdim !MCE->getMethodDecl()->isVirtual()) 198296417Sdim return true; 199296417Sdim } 200296417Sdim return false; 201296417Sdim} 202296417Sdim 203341825Sdim// Returns true if every path from the entry block passes through a call to FD. 204296417Sdimstatic bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { 205341825Sdim llvm::SmallPtrSet<CFGBlock *, 16> Visited; 206341825Sdim llvm::SmallVector<CFGBlock *, 16> WorkList; 207341825Sdim // Keep track of whether we found at least one recursive path. 208341825Sdim bool foundRecursion = false; 209276479Sdim 210296417Sdim const unsigned ExitID = cfg->getExit().getBlockID(); 211276479Sdim 212341825Sdim // Seed the work list with the entry block. 213341825Sdim WorkList.push_back(&cfg->getEntry()); 214276479Sdim 215341825Sdim while (!WorkList.empty()) { 216341825Sdim CFGBlock *Block = WorkList.pop_back_val(); 217276479Sdim 218341825Sdim for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) { 219341825Sdim if (CFGBlock *SuccBlock = *I) { 220341825Sdim if (!Visited.insert(SuccBlock).second) 221341825Sdim continue; 222276479Sdim 223341825Sdim // Found a path to the exit node without a recursive call. 224341825Sdim if (ExitID == SuccBlock->getBlockID()) 225341825Sdim return false; 226276479Sdim 227341825Sdim // If the successor block contains a recursive call, end analysis there. 228341825Sdim if (hasRecursiveCallInPath(FD, *SuccBlock)) { 229341825Sdim foundRecursion = true; 230341825Sdim continue; 231341825Sdim } 232276479Sdim 233341825Sdim WorkList.push_back(SuccBlock); 234341825Sdim } 235296417Sdim } 236276479Sdim } 237341825Sdim return foundRecursion; 238276479Sdim} 239276479Sdim 240276479Sdimstatic void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, 241296417Sdim const Stmt *Body, AnalysisDeclContext &AC) { 242276479Sdim FD = FD->getCanonicalDecl(); 243276479Sdim 244276479Sdim // Only run on non-templated functions and non-templated members of 245276479Sdim // templated classes. 246276479Sdim if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate && 247276479Sdim FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization) 248276479Sdim return; 249276479Sdim 250276479Sdim CFG *cfg = AC.getCFG(); 251276479Sdim if (!cfg) return; 252276479Sdim 253296417Sdim // Emit diagnostic if a recursive function call is detected for all paths. 254296417Sdim if (checkForRecursiveFunctionCall(FD, cfg)) 255276479Sdim S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function); 256276479Sdim} 257276479Sdim 258276479Sdim//===----------------------------------------------------------------------===// 259321369Sdim// Check for throw in a non-throwing function. 260321369Sdim//===----------------------------------------------------------------------===// 261321369Sdim 262341825Sdim/// Determine whether an exception thrown by E, unwinding from ThrowBlock, 263341825Sdim/// can reach ExitBlock. 264341825Sdimstatic bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, 265341825Sdim CFG *Body) { 266341825Sdim SmallVector<CFGBlock *, 16> Stack; 267341825Sdim llvm::BitVector Queued(Body->getNumBlockIDs()); 268321369Sdim 269341825Sdim Stack.push_back(&ThrowBlock); 270341825Sdim Queued[ThrowBlock.getBlockID()] = true; 271321369Sdim 272341825Sdim while (!Stack.empty()) { 273341825Sdim CFGBlock &UnwindBlock = *Stack.back(); 274341825Sdim Stack.pop_back(); 275321369Sdim 276341825Sdim for (auto &Succ : UnwindBlock.succs()) { 277341825Sdim if (!Succ.isReachable() || Queued[Succ->getBlockID()]) 278321369Sdim continue; 279341825Sdim 280341825Sdim if (Succ->getBlockID() == Body->getExit().getBlockID()) 281341825Sdim return true; 282341825Sdim 283341825Sdim if (auto *Catch = 284341825Sdim dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) { 285341825Sdim QualType Caught = Catch->getCaughtType(); 286341825Sdim if (Caught.isNull() || // catch (...) catches everything 287341825Sdim !E->getSubExpr() || // throw; is considered cuaght by any handler 288341825Sdim S.handlerCanCatch(Caught, E->getSubExpr()->getType())) 289341825Sdim // Exception doesn't escape via this path. 290341825Sdim break; 291341825Sdim } else { 292341825Sdim Stack.push_back(Succ); 293341825Sdim Queued[Succ->getBlockID()] = true; 294341825Sdim } 295321369Sdim } 296321369Sdim } 297341825Sdim 298321369Sdim return false; 299321369Sdim} 300321369Sdim 301341825Sdimstatic void visitReachableThrows( 302341825Sdim CFG *BodyCFG, 303341825Sdim llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) { 304341825Sdim llvm::BitVector Reachable(BodyCFG->getNumBlockIDs()); 305341825Sdim clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable); 306341825Sdim for (CFGBlock *B : *BodyCFG) { 307341825Sdim if (!Reachable[B->getBlockID()]) 308341825Sdim continue; 309341825Sdim for (CFGElement &E : *B) { 310341825Sdim Optional<CFGStmt> S = E.getAs<CFGStmt>(); 311341825Sdim if (!S) 312321369Sdim continue; 313341825Sdim if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) 314341825Sdim Visit(Throw, *B); 315321369Sdim } 316321369Sdim } 317321369Sdim} 318321369Sdim 319321369Sdimstatic void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, 320321369Sdim const FunctionDecl *FD) { 321321369Sdim if (!S.getSourceManager().isInSystemHeader(OpLoc) && 322321369Sdim FD->getTypeSourceInfo()) { 323321369Sdim S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; 324321369Sdim if (S.getLangOpts().CPlusPlus11 && 325321369Sdim (isa<CXXDestructorDecl>(FD) || 326321369Sdim FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || 327321369Sdim FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { 328321369Sdim if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> 329321369Sdim getAs<FunctionProtoType>()) 330321369Sdim S.Diag(FD->getLocation(), diag::note_throw_in_dtor) 331321369Sdim << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() 332321369Sdim << FD->getExceptionSpecSourceRange(); 333341825Sdim } else 334321369Sdim S.Diag(FD->getLocation(), diag::note_throw_in_function) 335321369Sdim << FD->getExceptionSpecSourceRange(); 336321369Sdim } 337321369Sdim} 338321369Sdim 339321369Sdimstatic void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, 340321369Sdim AnalysisDeclContext &AC) { 341321369Sdim CFG *BodyCFG = AC.getCFG(); 342321369Sdim if (!BodyCFG) 343321369Sdim return; 344321369Sdim if (BodyCFG->getExit().pred_empty()) 345321369Sdim return; 346341825Sdim visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { 347341825Sdim if (throwEscapes(S, Throw, Block, BodyCFG)) 348341825Sdim EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); 349341825Sdim }); 350321369Sdim} 351321369Sdim 352321369Sdimstatic bool isNoexcept(const FunctionDecl *FD) { 353321369Sdim const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); 354341825Sdim if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>()) 355321369Sdim return true; 356321369Sdim return false; 357321369Sdim} 358321369Sdim 359321369Sdim//===----------------------------------------------------------------------===// 360205408Srdivacky// Check for missing return value. 361205408Srdivacky//===----------------------------------------------------------------------===// 362205408Srdivacky 363208600Srdivackyenum ControlFlowKind { 364208600Srdivacky UnknownFallThrough, 365208600Srdivacky NeverFallThrough, 366208600Srdivacky MaybeFallThrough, 367208600Srdivacky AlwaysFallThrough, 368208600Srdivacky NeverFallThroughOrReturn 369208600Srdivacky}; 370205408Srdivacky 371205408Srdivacky/// CheckFallThrough - Check that we don't fall off the end of a 372205408Srdivacky/// Statement that should return a value. 373205408Srdivacky/// 374205408Srdivacky/// \returns AlwaysFallThrough iff we always fall off the end of the statement, 375205408Srdivacky/// MaybeFallThrough iff we might or might not fall off the end, 376205408Srdivacky/// NeverFallThroughOrReturn iff we never fall off the end of the statement or 377205408Srdivacky/// return. We assume NeverFallThrough iff we never fall off the end of the 378205408Srdivacky/// statement but we may return. We assume that functions not marked noreturn 379205408Srdivacky/// will return. 380234353Sdimstatic ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { 381205408Srdivacky CFG *cfg = AC.getCFG(); 382276479Sdim if (!cfg) return UnknownFallThrough; 383205408Srdivacky 384205408Srdivacky // The CFG leaves in dead things, and we don't want the dead code paths to 385205408Srdivacky // confuse us, so we mark all live things first. 386205408Srdivacky llvm::BitVector live(cfg->getNumBlockIDs()); 387226633Sdim unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), 388205408Srdivacky live); 389205408Srdivacky 390205408Srdivacky bool AddEHEdges = AC.getAddEHEdges(); 391205408Srdivacky if (!AddEHEdges && count != cfg->getNumBlockIDs()) 392205408Srdivacky // When there are things remaining dead, and we didn't add EH edges 393205408Srdivacky // from CallExprs to the catch clauses, we have to go back and 394205408Srdivacky // mark them as live. 395276479Sdim for (const auto *B : *cfg) { 396276479Sdim if (!live[B->getBlockID()]) { 397276479Sdim if (B->pred_begin() == B->pred_end()) { 398276479Sdim if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator())) 399205408Srdivacky // When not adding EH edges from calls, catch clauses 400205408Srdivacky // can otherwise seem dead. Avoid noting them as dead. 401276479Sdim count += reachable_code::ScanReachableFromBlock(B, live); 402205408Srdivacky continue; 403205408Srdivacky } 404205408Srdivacky } 405205408Srdivacky } 406205408Srdivacky 407205408Srdivacky // Now we know what is live, we check the live precessors of the exit block 408205408Srdivacky // and look for fall through paths, being careful to ignore normal returns, 409205408Srdivacky // and exceptional paths. 410205408Srdivacky bool HasLiveReturn = false; 411205408Srdivacky bool HasFakeEdge = false; 412205408Srdivacky bool HasPlainEdge = false; 413205408Srdivacky bool HasAbnormalEdge = false; 414218893Sdim 415218893Sdim // Ignore default cases that aren't likely to be reachable because all 416218893Sdim // enums in a switch(X) have explicit case statements. 417218893Sdim CFGBlock::FilterOptions FO; 418218893Sdim FO.IgnoreDefaultsWithCoveredEnums = 1; 419218893Sdim 420341825Sdim for (CFGBlock::filtered_pred_iterator I = 421341825Sdim cfg->getExit().filtered_pred_start_end(FO); 422341825Sdim I.hasMore(); ++I) { 423341825Sdim const CFGBlock &B = **I; 424205408Srdivacky if (!live[B.getBlockID()]) 425205408Srdivacky continue; 426218893Sdim 427226633Sdim // Skip blocks which contain an element marked as no-return. They don't 428226633Sdim // represent actually viable edges into the exit block, so mark them as 429226633Sdim // abnormal. 430226633Sdim if (B.hasNoReturnElement()) { 431226633Sdim HasAbnormalEdge = true; 432226633Sdim continue; 433226633Sdim } 434226633Sdim 435218893Sdim // Destructors can appear after the 'return' in the CFG. This is 436218893Sdim // normal. We need to look pass the destructors for the return 437218893Sdim // statement (if it exists). 438218893Sdim CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); 439221345Sdim 440226633Sdim for ( ; ri != re ; ++ri) 441249423Sdim if (ri->getAs<CFGStmt>()) 442218893Sdim break; 443226633Sdim 444218893Sdim // No more CFGElements in the block? 445218893Sdim if (ri == re) { 446205408Srdivacky if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { 447205408Srdivacky HasAbnormalEdge = true; 448205408Srdivacky continue; 449205408Srdivacky } 450205408Srdivacky // A labeled empty statement, or the entry block... 451205408Srdivacky HasPlainEdge = true; 452205408Srdivacky continue; 453205408Srdivacky } 454218893Sdim 455249423Sdim CFGStmt CS = ri->castAs<CFGStmt>(); 456226633Sdim const Stmt *S = CS.getStmt(); 457314564Sdim if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) { 458205408Srdivacky HasLiveReturn = true; 459205408Srdivacky continue; 460205408Srdivacky } 461205408Srdivacky if (isa<ObjCAtThrowStmt>(S)) { 462205408Srdivacky HasFakeEdge = true; 463205408Srdivacky continue; 464205408Srdivacky } 465205408Srdivacky if (isa<CXXThrowExpr>(S)) { 466205408Srdivacky HasFakeEdge = true; 467205408Srdivacky continue; 468205408Srdivacky } 469239462Sdim if (isa<MSAsmStmt>(S)) { 470239462Sdim // TODO: Verify this is correct. 471239462Sdim HasFakeEdge = true; 472239462Sdim HasLiveReturn = true; 473239462Sdim continue; 474239462Sdim } 475205408Srdivacky if (isa<CXXTryStmt>(S)) { 476205408Srdivacky HasAbnormalEdge = true; 477205408Srdivacky continue; 478205408Srdivacky } 479226633Sdim if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) 480226633Sdim == B.succ_end()) { 481226633Sdim HasAbnormalEdge = true; 482226633Sdim continue; 483226633Sdim } 484205408Srdivacky 485226633Sdim HasPlainEdge = true; 486205408Srdivacky } 487205408Srdivacky if (!HasPlainEdge) { 488205408Srdivacky if (HasLiveReturn) 489205408Srdivacky return NeverFallThrough; 490205408Srdivacky return NeverFallThroughOrReturn; 491205408Srdivacky } 492205408Srdivacky if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) 493205408Srdivacky return MaybeFallThrough; 494205408Srdivacky // This says AlwaysFallThrough for calls to functions that are not marked 495205408Srdivacky // noreturn, that don't return. If people would like this warning to be more 496205408Srdivacky // accurate, such functions should be marked as noreturn. 497205408Srdivacky return AlwaysFallThrough; 498205408Srdivacky} 499205408Srdivacky 500212904Sdimnamespace { 501212904Sdim 502205408Srdivackystruct CheckFallThroughDiagnostics { 503205408Srdivacky unsigned diag_MaybeFallThrough_HasNoReturn; 504205408Srdivacky unsigned diag_MaybeFallThrough_ReturnsNonVoid; 505205408Srdivacky unsigned diag_AlwaysFallThrough_HasNoReturn; 506205408Srdivacky unsigned diag_AlwaysFallThrough_ReturnsNonVoid; 507205408Srdivacky unsigned diag_NeverFallThroughOrReturn; 508314564Sdim enum { Function, Block, Lambda, Coroutine } funMode; 509218893Sdim SourceLocation FuncLoc; 510206084Srdivacky 511207619Srdivacky static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { 512205408Srdivacky CheckFallThroughDiagnostics D; 513218893Sdim D.FuncLoc = Func->getLocation(); 514205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 515205408Srdivacky diag::warn_falloff_noreturn_function; 516205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 517205408Srdivacky diag::warn_maybe_falloff_nonvoid_function; 518205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 519205408Srdivacky diag::warn_falloff_noreturn_function; 520205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 521205408Srdivacky diag::warn_falloff_nonvoid_function; 522207619Srdivacky 523207619Srdivacky // Don't suggest that virtual functions be marked "noreturn", since they 524207619Srdivacky // might be overridden by non-noreturn functions. 525207619Srdivacky bool isVirtualMethod = false; 526207619Srdivacky if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) 527207619Srdivacky isVirtualMethod = Method->isVirtual(); 528341825Sdim 529226633Sdim // Don't suggest that template instantiations be marked "noreturn" 530226633Sdim bool isTemplateInstantiation = false; 531234353Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) 532234353Sdim isTemplateInstantiation = Function->isTemplateInstantiation(); 533341825Sdim 534226633Sdim if (!isVirtualMethod && !isTemplateInstantiation) 535207619Srdivacky D.diag_NeverFallThroughOrReturn = 536207619Srdivacky diag::warn_suggest_noreturn_function; 537207619Srdivacky else 538207619Srdivacky D.diag_NeverFallThroughOrReturn = 0; 539341825Sdim 540234353Sdim D.funMode = Function; 541205408Srdivacky return D; 542205408Srdivacky } 543206084Srdivacky 544314564Sdim static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) { 545314564Sdim CheckFallThroughDiagnostics D; 546314564Sdim D.FuncLoc = Func->getLocation(); 547314564Sdim D.diag_MaybeFallThrough_HasNoReturn = 0; 548314564Sdim D.diag_MaybeFallThrough_ReturnsNonVoid = 549314564Sdim diag::warn_maybe_falloff_nonvoid_coroutine; 550314564Sdim D.diag_AlwaysFallThrough_HasNoReturn = 0; 551314564Sdim D.diag_AlwaysFallThrough_ReturnsNonVoid = 552314564Sdim diag::warn_falloff_nonvoid_coroutine; 553314564Sdim D.funMode = Coroutine; 554314564Sdim return D; 555314564Sdim } 556314564Sdim 557205408Srdivacky static CheckFallThroughDiagnostics MakeForBlock() { 558205408Srdivacky CheckFallThroughDiagnostics D; 559205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 560205408Srdivacky diag::err_noreturn_block_has_return_expr; 561205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 562205408Srdivacky diag::err_maybe_falloff_nonvoid_block; 563205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 564205408Srdivacky diag::err_noreturn_block_has_return_expr; 565205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 566205408Srdivacky diag::err_falloff_nonvoid_block; 567276479Sdim D.diag_NeverFallThroughOrReturn = 0; 568234353Sdim D.funMode = Block; 569205408Srdivacky return D; 570205408Srdivacky } 571206084Srdivacky 572234353Sdim static CheckFallThroughDiagnostics MakeForLambda() { 573234353Sdim CheckFallThroughDiagnostics D; 574234353Sdim D.diag_MaybeFallThrough_HasNoReturn = 575234353Sdim diag::err_noreturn_lambda_has_return_expr; 576234353Sdim D.diag_MaybeFallThrough_ReturnsNonVoid = 577234353Sdim diag::warn_maybe_falloff_nonvoid_lambda; 578234353Sdim D.diag_AlwaysFallThrough_HasNoReturn = 579234353Sdim diag::err_noreturn_lambda_has_return_expr; 580234353Sdim D.diag_AlwaysFallThrough_ReturnsNonVoid = 581234353Sdim diag::warn_falloff_nonvoid_lambda; 582234353Sdim D.diag_NeverFallThroughOrReturn = 0; 583234353Sdim D.funMode = Lambda; 584234353Sdim return D; 585234353Sdim } 586234353Sdim 587226633Sdim bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, 588205408Srdivacky bool HasNoReturn) const { 589234353Sdim if (funMode == Function) { 590218893Sdim return (ReturnsVoid || 591276479Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, 592276479Sdim FuncLoc)) && 593276479Sdim (!HasNoReturn || 594276479Sdim D.isIgnored(diag::warn_noreturn_function_has_return_expr, 595276479Sdim FuncLoc)) && 596276479Sdim (!ReturnsVoid || 597276479Sdim D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc)); 598205408Srdivacky } 599314564Sdim if (funMode == Coroutine) { 600314564Sdim return (ReturnsVoid || 601314564Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) || 602314564Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine, 603314564Sdim FuncLoc)) && 604314564Sdim (!HasNoReturn); 605314564Sdim } 606234353Sdim // For blocks / lambdas. 607276479Sdim return ReturnsVoid && !HasNoReturn; 608205408Srdivacky } 609205408Srdivacky}; 610205408Srdivacky 611296417Sdim} // anonymous namespace 612212904Sdim 613341825Sdim/// CheckFallThroughForBody - Check that we don't fall off the end of a 614205408Srdivacky/// function that should return a value. Check that we don't fall off the end 615205408Srdivacky/// of a noreturn function. We assume that functions and blocks not marked 616205408Srdivacky/// noreturn will return. 617205408Srdivackystatic void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, 618219077Sdim const BlockExpr *blkExpr, 619341825Sdim const CheckFallThroughDiagnostics &CD, 620341825Sdim AnalysisDeclContext &AC, 621341825Sdim sema::FunctionScopeInfo *FSI) { 622205408Srdivacky 623205408Srdivacky bool ReturnsVoid = false; 624205408Srdivacky bool HasNoReturn = false; 625341825Sdim bool IsCoroutine = FSI->isCoroutine(); 626205408Srdivacky 627314564Sdim if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 628314564Sdim if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) 629314564Sdim ReturnsVoid = CBody->getFallthroughHandler() != nullptr; 630314564Sdim else 631314564Sdim ReturnsVoid = FD->getReturnType()->isVoidType(); 632249423Sdim HasNoReturn = FD->isNoReturn(); 633205408Srdivacky } 634314564Sdim else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 635276479Sdim ReturnsVoid = MD->getReturnType()->isVoidType(); 636205408Srdivacky HasNoReturn = MD->hasAttr<NoReturnAttr>(); 637205408Srdivacky } 638205408Srdivacky else if (isa<BlockDecl>(D)) { 639219077Sdim QualType BlockTy = blkExpr->getType(); 640206084Srdivacky if (const FunctionType *FT = 641205408Srdivacky BlockTy->getPointeeType()->getAs<FunctionType>()) { 642276479Sdim if (FT->getReturnType()->isVoidType()) 643205408Srdivacky ReturnsVoid = true; 644205408Srdivacky if (FT->getNoReturnAttr()) 645205408Srdivacky HasNoReturn = true; 646205408Srdivacky } 647205408Srdivacky } 648205408Srdivacky 649226633Sdim DiagnosticsEngine &Diags = S.getDiagnostics(); 650205408Srdivacky 651205408Srdivacky // Short circuit for compilation speed. 652205408Srdivacky if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) 653205408Srdivacky return; 654280031Sdim SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); 655321369Sdim auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { 656321369Sdim if (IsCoroutine) 657341825Sdim S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); 658321369Sdim else 659321369Sdim S.Diag(Loc, DiagID); 660321369Sdim }; 661341825Sdim 662341825Sdim // cpu_dispatch functions permit empty function bodies for ICC compatibility. 663341825Sdim if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion()) 664341825Sdim return; 665341825Sdim 666280031Sdim // Either in a function body compound statement, or a function-try-block. 667280031Sdim switch (CheckFallThrough(AC)) { 668280031Sdim case UnknownFallThrough: 669280031Sdim break; 670208600Srdivacky 671280031Sdim case MaybeFallThrough: 672280031Sdim if (HasNoReturn) 673321369Sdim EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); 674280031Sdim else if (!ReturnsVoid) 675321369Sdim EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); 676280031Sdim break; 677280031Sdim case AlwaysFallThrough: 678280031Sdim if (HasNoReturn) 679321369Sdim EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); 680280031Sdim else if (!ReturnsVoid) 681321369Sdim EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); 682280031Sdim break; 683280031Sdim case NeverFallThroughOrReturn: 684280031Sdim if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { 685280031Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 686280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; 687280031Sdim } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 688280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; 689280031Sdim } else { 690280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); 691226633Sdim } 692280031Sdim } 693280031Sdim break; 694280031Sdim case NeverFallThrough: 695280031Sdim break; 696205408Srdivacky } 697205408Srdivacky} 698205408Srdivacky 699205408Srdivacky//===----------------------------------------------------------------------===// 700218893Sdim// -Wuninitialized 701218893Sdim//===----------------------------------------------------------------------===// 702218893Sdim 703218893Sdimnamespace { 704221345Sdim/// ContainsReference - A visitor class to search for references to 705221345Sdim/// a particular declaration (the needle) within any evaluated component of an 706221345Sdim/// expression (recursively). 707288943Sdimclass ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> { 708221345Sdim bool FoundReference; 709221345Sdim const DeclRefExpr *Needle; 710221345Sdim 711221345Sdimpublic: 712288943Sdim typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited; 713288943Sdim 714221345Sdim ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) 715288943Sdim : Inherited(Context), FoundReference(false), Needle(Needle) {} 716221345Sdim 717288943Sdim void VisitExpr(const Expr *E) { 718221345Sdim // Stop evaluating if we already have a reference. 719221345Sdim if (FoundReference) 720221345Sdim return; 721221345Sdim 722288943Sdim Inherited::VisitExpr(E); 723221345Sdim } 724221345Sdim 725288943Sdim void VisitDeclRefExpr(const DeclRefExpr *E) { 726221345Sdim if (E == Needle) 727221345Sdim FoundReference = true; 728221345Sdim else 729288943Sdim Inherited::VisitDeclRefExpr(E); 730221345Sdim } 731221345Sdim 732221345Sdim bool doesContainReference() const { return FoundReference; } 733221345Sdim}; 734296417Sdim} // anonymous namespace 735221345Sdim 736226633Sdimstatic bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { 737234353Sdim QualType VariableTy = VD->getType().getCanonicalType(); 738234353Sdim if (VariableTy->isBlockPointerType() && 739234353Sdim !VD->hasAttr<BlocksAttr>()) { 740276479Sdim S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) 741276479Sdim << VD->getDeclName() 742276479Sdim << FixItHint::CreateInsertion(VD->getLocation(), "__block "); 743234353Sdim return true; 744234353Sdim } 745261991Sdim 746226633Sdim // Don't issue a fixit if there is already an initializer. 747226633Sdim if (VD->getInit()) 748226633Sdim return false; 749239462Sdim 750239462Sdim // Don't suggest a fixit inside macros. 751239462Sdim if (VD->getLocEnd().isMacroID()) 752239462Sdim return false; 753239462Sdim 754276479Sdim SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd()); 755261991Sdim 756261991Sdim // Suggest possible initialization (if any). 757261991Sdim std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); 758261991Sdim if (Init.empty()) 759261991Sdim return false; 760261991Sdim 761234353Sdim S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() 762234353Sdim << FixItHint::CreateInsertion(Loc, Init); 763234353Sdim return true; 764226633Sdim} 765226633Sdim 766239462Sdim/// Create a fixit to remove an if-like statement, on the assumption that its 767239462Sdim/// condition is CondVal. 768239462Sdimstatic void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, 769239462Sdim const Stmt *Else, bool CondVal, 770239462Sdim FixItHint &Fixit1, FixItHint &Fixit2) { 771239462Sdim if (CondVal) { 772239462Sdim // If condition is always true, remove all but the 'then'. 773239462Sdim Fixit1 = FixItHint::CreateRemoval( 774239462Sdim CharSourceRange::getCharRange(If->getLocStart(), 775239462Sdim Then->getLocStart())); 776239462Sdim if (Else) { 777296417Sdim SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getLocEnd()); 778239462Sdim Fixit2 = FixItHint::CreateRemoval( 779239462Sdim SourceRange(ElseKwLoc, Else->getLocEnd())); 780239462Sdim } 781239462Sdim } else { 782239462Sdim // If condition is always false, remove all but the 'else'. 783239462Sdim if (Else) 784239462Sdim Fixit1 = FixItHint::CreateRemoval( 785239462Sdim CharSourceRange::getCharRange(If->getLocStart(), 786239462Sdim Else->getLocStart())); 787239462Sdim else 788239462Sdim Fixit1 = FixItHint::CreateRemoval(If->getSourceRange()); 789239462Sdim } 790239462Sdim} 791239462Sdim 792239462Sdim/// DiagUninitUse -- Helper function to produce a diagnostic for an 793239462Sdim/// uninitialized use of a variable. 794239462Sdimstatic void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, 795239462Sdim bool IsCapturedByBlock) { 796239462Sdim bool Diagnosed = false; 797239462Sdim 798261991Sdim switch (Use.getKind()) { 799261991Sdim case UninitUse::Always: 800261991Sdim S.Diag(Use.getUser()->getLocStart(), diag::warn_uninit_var) 801261991Sdim << VD->getDeclName() << IsCapturedByBlock 802261991Sdim << Use.getUser()->getSourceRange(); 803261991Sdim return; 804261991Sdim 805261991Sdim case UninitUse::AfterDecl: 806261991Sdim case UninitUse::AfterCall: 807261991Sdim S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var) 808261991Sdim << VD->getDeclName() << IsCapturedByBlock 809261991Sdim << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5) 810261991Sdim << const_cast<DeclContext*>(VD->getLexicalDeclContext()) 811261991Sdim << VD->getSourceRange(); 812261991Sdim S.Diag(Use.getUser()->getLocStart(), diag::note_uninit_var_use) 813261991Sdim << IsCapturedByBlock << Use.getUser()->getSourceRange(); 814261991Sdim return; 815261991Sdim 816261991Sdim case UninitUse::Maybe: 817261991Sdim case UninitUse::Sometimes: 818261991Sdim // Carry on to report sometimes-uninitialized branches, if possible, 819261991Sdim // or a 'may be used uninitialized' diagnostic otherwise. 820261991Sdim break; 821261991Sdim } 822261991Sdim 823239462Sdim // Diagnose each branch which leads to a sometimes-uninitialized use. 824239462Sdim for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end(); 825239462Sdim I != E; ++I) { 826239462Sdim assert(Use.getKind() == UninitUse::Sometimes); 827239462Sdim 828239462Sdim const Expr *User = Use.getUser(); 829239462Sdim const Stmt *Term = I->Terminator; 830239462Sdim 831239462Sdim // Information used when building the diagnostic. 832239462Sdim unsigned DiagKind; 833243830Sdim StringRef Str; 834239462Sdim SourceRange Range; 835239462Sdim 836249423Sdim // FixIts to suppress the diagnostic by removing the dead condition. 837239462Sdim // For all binary terminators, branch 0 is taken if the condition is true, 838239462Sdim // and branch 1 is taken if the condition is false. 839239462Sdim int RemoveDiagKind = -1; 840239462Sdim const char *FixitStr = 841239462Sdim S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false") 842239462Sdim : (I->Output ? "1" : "0"); 843239462Sdim FixItHint Fixit1, Fixit2; 844239462Sdim 845261991Sdim switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) { 846239462Sdim default: 847239462Sdim // Don't know how to report this. Just fall back to 'may be used 848261991Sdim // uninitialized'. FIXME: Can this happen? 849239462Sdim continue; 850239462Sdim 851239462Sdim // "condition is true / condition is false". 852239462Sdim case Stmt::IfStmtClass: { 853239462Sdim const IfStmt *IS = cast<IfStmt>(Term); 854239462Sdim DiagKind = 0; 855239462Sdim Str = "if"; 856239462Sdim Range = IS->getCond()->getSourceRange(); 857239462Sdim RemoveDiagKind = 0; 858239462Sdim CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), 859239462Sdim I->Output, Fixit1, Fixit2); 860239462Sdim break; 861239462Sdim } 862239462Sdim case Stmt::ConditionalOperatorClass: { 863239462Sdim const ConditionalOperator *CO = cast<ConditionalOperator>(Term); 864239462Sdim DiagKind = 0; 865239462Sdim Str = "?:"; 866239462Sdim Range = CO->getCond()->getSourceRange(); 867239462Sdim RemoveDiagKind = 0; 868239462Sdim CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), 869239462Sdim I->Output, Fixit1, Fixit2); 870239462Sdim break; 871239462Sdim } 872239462Sdim case Stmt::BinaryOperatorClass: { 873239462Sdim const BinaryOperator *BO = cast<BinaryOperator>(Term); 874239462Sdim if (!BO->isLogicalOp()) 875239462Sdim continue; 876239462Sdim DiagKind = 0; 877239462Sdim Str = BO->getOpcodeStr(); 878239462Sdim Range = BO->getLHS()->getSourceRange(); 879239462Sdim RemoveDiagKind = 0; 880239462Sdim if ((BO->getOpcode() == BO_LAnd && I->Output) || 881239462Sdim (BO->getOpcode() == BO_LOr && !I->Output)) 882239462Sdim // true && y -> y, false || y -> y. 883239462Sdim Fixit1 = FixItHint::CreateRemoval(SourceRange(BO->getLocStart(), 884239462Sdim BO->getOperatorLoc())); 885239462Sdim else 886239462Sdim // false && y -> false, true || y -> true. 887239462Sdim Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr); 888239462Sdim break; 889239462Sdim } 890239462Sdim 891239462Sdim // "loop is entered / loop is exited". 892239462Sdim case Stmt::WhileStmtClass: 893239462Sdim DiagKind = 1; 894239462Sdim Str = "while"; 895239462Sdim Range = cast<WhileStmt>(Term)->getCond()->getSourceRange(); 896239462Sdim RemoveDiagKind = 1; 897239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 898239462Sdim break; 899239462Sdim case Stmt::ForStmtClass: 900239462Sdim DiagKind = 1; 901239462Sdim Str = "for"; 902239462Sdim Range = cast<ForStmt>(Term)->getCond()->getSourceRange(); 903239462Sdim RemoveDiagKind = 1; 904239462Sdim if (I->Output) 905239462Sdim Fixit1 = FixItHint::CreateRemoval(Range); 906239462Sdim else 907239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 908239462Sdim break; 909261991Sdim case Stmt::CXXForRangeStmtClass: 910261991Sdim if (I->Output == 1) { 911261991Sdim // The use occurs if a range-based for loop's body never executes. 912261991Sdim // That may be impossible, and there's no syntactic fix for this, 913261991Sdim // so treat it as a 'may be uninitialized' case. 914261991Sdim continue; 915261991Sdim } 916261991Sdim DiagKind = 1; 917261991Sdim Str = "for"; 918261991Sdim Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange(); 919261991Sdim break; 920239462Sdim 921239462Sdim // "condition is true / loop is exited". 922239462Sdim case Stmt::DoStmtClass: 923239462Sdim DiagKind = 2; 924239462Sdim Str = "do"; 925239462Sdim Range = cast<DoStmt>(Term)->getCond()->getSourceRange(); 926239462Sdim RemoveDiagKind = 1; 927239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 928239462Sdim break; 929239462Sdim 930239462Sdim // "switch case is taken". 931239462Sdim case Stmt::CaseStmtClass: 932239462Sdim DiagKind = 3; 933239462Sdim Str = "case"; 934239462Sdim Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange(); 935239462Sdim break; 936239462Sdim case Stmt::DefaultStmtClass: 937239462Sdim DiagKind = 3; 938239462Sdim Str = "default"; 939239462Sdim Range = cast<DefaultStmt>(Term)->getDefaultLoc(); 940239462Sdim break; 941239462Sdim } 942239462Sdim 943239462Sdim S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var) 944239462Sdim << VD->getDeclName() << IsCapturedByBlock << DiagKind 945239462Sdim << Str << I->Output << Range; 946239462Sdim S.Diag(User->getLocStart(), diag::note_uninit_var_use) 947239462Sdim << IsCapturedByBlock << User->getSourceRange(); 948239462Sdim if (RemoveDiagKind != -1) 949239462Sdim S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond) 950239462Sdim << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2; 951239462Sdim 952239462Sdim Diagnosed = true; 953239462Sdim } 954239462Sdim 955239462Sdim if (!Diagnosed) 956261991Sdim S.Diag(Use.getUser()->getLocStart(), diag::warn_maybe_uninit_var) 957239462Sdim << VD->getDeclName() << IsCapturedByBlock 958239462Sdim << Use.getUser()->getSourceRange(); 959239462Sdim} 960239462Sdim 961221345Sdim/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an 962221345Sdim/// uninitialized variable. This manages the different forms of diagnostic 963221345Sdim/// emitted for particular types of uses. Returns true if the use was diagnosed 964239462Sdim/// as a warning. If a particular use is one we omit warnings for, returns 965221345Sdim/// false. 966221345Sdimstatic bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, 967239462Sdim const UninitUse &Use, 968226633Sdim bool alwaysReportSelfInit = false) { 969239462Sdim if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) { 970239462Sdim // Inspect the initializer of the variable declaration which is 971239462Sdim // being referenced prior to its initialization. We emit 972239462Sdim // specialized diagnostics for self-initialization, and we 973239462Sdim // specifically avoid warning about self references which take the 974239462Sdim // form of: 975239462Sdim // 976239462Sdim // int x = x; 977239462Sdim // 978239462Sdim // This is used to indicate to GCC that 'x' is intentionally left 979239462Sdim // uninitialized. Proven code paths which access 'x' in 980239462Sdim // an uninitialized state after this will still warn. 981239462Sdim if (const Expr *Initializer = VD->getInit()) { 982239462Sdim if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) 983239462Sdim return false; 984221345Sdim 985239462Sdim ContainsReference CR(S.Context, DRE); 986288943Sdim CR.Visit(Initializer); 987239462Sdim if (CR.doesContainReference()) { 988221345Sdim S.Diag(DRE->getLocStart(), 989221345Sdim diag::warn_uninit_self_reference_in_init) 990239462Sdim << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); 991239462Sdim return true; 992221345Sdim } 993221345Sdim } 994239462Sdim 995239462Sdim DiagUninitUse(S, VD, Use, false); 996221345Sdim } else { 997239462Sdim const BlockExpr *BE = cast<BlockExpr>(Use.getUser()); 998239462Sdim if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) 999239462Sdim S.Diag(BE->getLocStart(), 1000239462Sdim diag::warn_uninit_byref_blockvar_captured_by_block) 1001234353Sdim << VD->getDeclName(); 1002234353Sdim else 1003239462Sdim DiagUninitUse(S, VD, Use, true); 1004221345Sdim } 1005221345Sdim 1006221345Sdim // Report where the variable was declared when the use wasn't within 1007226633Sdim // the initializer of that declaration & we didn't already suggest 1008226633Sdim // an initialization fixit. 1009239462Sdim if (!SuggestInitializationFixit(S, VD)) 1010309124Sdim S.Diag(VD->getLocStart(), diag::note_var_declared_here) 1011221345Sdim << VD->getDeclName(); 1012221345Sdim 1013221345Sdim return true; 1014221345Sdim} 1015221345Sdim 1016239462Sdimnamespace { 1017239462Sdim class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> { 1018239462Sdim public: 1019239462Sdim FallthroughMapper(Sema &S) 1020239462Sdim : FoundSwitchStatements(false), 1021239462Sdim S(S) { 1022239462Sdim } 1023221345Sdim 1024239462Sdim bool foundSwitchStatements() const { return FoundSwitchStatements; } 1025239462Sdim 1026239462Sdim void markFallthroughVisited(const AttributedStmt *Stmt) { 1027239462Sdim bool Found = FallthroughStmts.erase(Stmt); 1028239462Sdim assert(Found); 1029239462Sdim (void)Found; 1030239462Sdim } 1031239462Sdim 1032239462Sdim typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts; 1033239462Sdim 1034239462Sdim const AttrStmts &getFallthroughStmts() const { 1035239462Sdim return FallthroughStmts; 1036239462Sdim } 1037239462Sdim 1038249423Sdim void fillReachableBlocks(CFG *Cfg) { 1039249423Sdim assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); 1040249423Sdim std::deque<const CFGBlock *> BlockQueue; 1041249423Sdim 1042249423Sdim ReachableBlocks.insert(&Cfg->getEntry()); 1043249423Sdim BlockQueue.push_back(&Cfg->getEntry()); 1044249423Sdim // Mark all case blocks reachable to avoid problems with switching on 1045249423Sdim // constants, covered enums, etc. 1046249423Sdim // These blocks can contain fall-through annotations, and we don't want to 1047249423Sdim // issue a warn_fallthrough_attr_unreachable for them. 1048276479Sdim for (const auto *B : *Cfg) { 1049249423Sdim const Stmt *L = B->getLabel(); 1050280031Sdim if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second) 1051249423Sdim BlockQueue.push_back(B); 1052249423Sdim } 1053249423Sdim 1054249423Sdim while (!BlockQueue.empty()) { 1055249423Sdim const CFGBlock *P = BlockQueue.front(); 1056249423Sdim BlockQueue.pop_front(); 1057249423Sdim for (CFGBlock::const_succ_iterator I = P->succ_begin(), 1058249423Sdim E = P->succ_end(); 1059249423Sdim I != E; ++I) { 1060280031Sdim if (*I && ReachableBlocks.insert(*I).second) 1061249423Sdim BlockQueue.push_back(*I); 1062249423Sdim } 1063249423Sdim } 1064249423Sdim } 1065249423Sdim 1066321369Sdim bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt, 1067321369Sdim bool IsTemplateInstantiation) { 1068249423Sdim assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); 1069249423Sdim 1070239462Sdim int UnannotatedCnt = 0; 1071239462Sdim AnnotatedCnt = 0; 1072239462Sdim 1073276479Sdim std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end()); 1074239462Sdim while (!BlockQueue.empty()) { 1075239462Sdim const CFGBlock *P = BlockQueue.front(); 1076239462Sdim BlockQueue.pop_front(); 1077276479Sdim if (!P) continue; 1078239462Sdim 1079239462Sdim const Stmt *Term = P->getTerminator(); 1080239462Sdim if (Term && isa<SwitchStmt>(Term)) 1081239462Sdim continue; // Switch statement, good. 1082239462Sdim 1083239462Sdim const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel()); 1084239462Sdim if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) 1085239462Sdim continue; // Previous case label has no statements, good. 1086239462Sdim 1087249423Sdim const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel()); 1088249423Sdim if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) 1089249423Sdim continue; // Case label is preceded with a normal label, good. 1090249423Sdim 1091249423Sdim if (!ReachableBlocks.count(P)) { 1092249423Sdim for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(), 1093249423Sdim ElemEnd = P->rend(); 1094249423Sdim ElemIt != ElemEnd; ++ElemIt) { 1095249423Sdim if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) { 1096239462Sdim if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { 1097321369Sdim // Don't issue a warning for an unreachable fallthrough 1098321369Sdim // attribute in template instantiations as it may not be 1099321369Sdim // unreachable in all instantiations of the template. 1100321369Sdim if (!IsTemplateInstantiation) 1101321369Sdim S.Diag(AS->getLocStart(), 1102321369Sdim diag::warn_fallthrough_attr_unreachable); 1103239462Sdim markFallthroughVisited(AS); 1104239462Sdim ++AnnotatedCnt; 1105249423Sdim break; 1106239462Sdim } 1107239462Sdim // Don't care about other unreachable statements. 1108239462Sdim } 1109239462Sdim } 1110239462Sdim // If there are no unreachable statements, this may be a special 1111239462Sdim // case in CFG: 1112239462Sdim // case X: { 1113239462Sdim // A a; // A has a destructor. 1114239462Sdim // break; 1115239462Sdim // } 1116239462Sdim // // <<<< This place is represented by a 'hanging' CFG block. 1117239462Sdim // case Y: 1118239462Sdim continue; 1119239462Sdim } 1120239462Sdim 1121239462Sdim const Stmt *LastStmt = getLastStmt(*P); 1122239462Sdim if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) { 1123239462Sdim markFallthroughVisited(AS); 1124239462Sdim ++AnnotatedCnt; 1125239462Sdim continue; // Fallthrough annotation, good. 1126239462Sdim } 1127239462Sdim 1128239462Sdim if (!LastStmt) { // This block contains no executable statements. 1129239462Sdim // Traverse its predecessors. 1130239462Sdim std::copy(P->pred_begin(), P->pred_end(), 1131239462Sdim std::back_inserter(BlockQueue)); 1132239462Sdim continue; 1133239462Sdim } 1134239462Sdim 1135239462Sdim ++UnannotatedCnt; 1136239462Sdim } 1137239462Sdim return !!UnannotatedCnt; 1138239462Sdim } 1139239462Sdim 1140239462Sdim // RecursiveASTVisitor setup. 1141239462Sdim bool shouldWalkTypesOfTypeLocs() const { return false; } 1142239462Sdim 1143239462Sdim bool VisitAttributedStmt(AttributedStmt *S) { 1144239462Sdim if (asFallThroughAttr(S)) 1145239462Sdim FallthroughStmts.insert(S); 1146239462Sdim return true; 1147239462Sdim } 1148239462Sdim 1149239462Sdim bool VisitSwitchStmt(SwitchStmt *S) { 1150239462Sdim FoundSwitchStatements = true; 1151239462Sdim return true; 1152239462Sdim } 1153239462Sdim 1154249423Sdim // We don't want to traverse local type declarations. We analyze their 1155249423Sdim // methods separately. 1156249423Sdim bool TraverseDecl(Decl *D) { return true; } 1157249423Sdim 1158276479Sdim // We analyze lambda bodies separately. Skip them here. 1159276479Sdim bool TraverseLambdaBody(LambdaExpr *LE) { return true; } 1160276479Sdim 1161239462Sdim private: 1162239462Sdim 1163239462Sdim static const AttributedStmt *asFallThroughAttr(const Stmt *S) { 1164239462Sdim if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) { 1165239462Sdim if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs())) 1166239462Sdim return AS; 1167239462Sdim } 1168276479Sdim return nullptr; 1169239462Sdim } 1170239462Sdim 1171239462Sdim static const Stmt *getLastStmt(const CFGBlock &B) { 1172239462Sdim if (const Stmt *Term = B.getTerminator()) 1173239462Sdim return Term; 1174239462Sdim for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(), 1175239462Sdim ElemEnd = B.rend(); 1176239462Sdim ElemIt != ElemEnd; ++ElemIt) { 1177249423Sdim if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) 1178239462Sdim return CS->getStmt(); 1179239462Sdim } 1180239462Sdim // Workaround to detect a statement thrown out by CFGBuilder: 1181239462Sdim // case X: {} case Y: 1182239462Sdim // case X: ; case Y: 1183239462Sdim if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel())) 1184239462Sdim if (!isa<SwitchCase>(SW->getSubStmt())) 1185239462Sdim return SW->getSubStmt(); 1186239462Sdim 1187276479Sdim return nullptr; 1188239462Sdim } 1189239462Sdim 1190239462Sdim bool FoundSwitchStatements; 1191239462Sdim AttrStmts FallthroughStmts; 1192239462Sdim Sema &S; 1193249423Sdim llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks; 1194239462Sdim }; 1195296417Sdim} // anonymous namespace 1196239462Sdim 1197309124Sdimstatic StringRef getFallthroughAttrSpelling(Preprocessor &PP, 1198309124Sdim SourceLocation Loc) { 1199309124Sdim TokenValue FallthroughTokens[] = { 1200309124Sdim tok::l_square, tok::l_square, 1201309124Sdim PP.getIdentifierInfo("fallthrough"), 1202309124Sdim tok::r_square, tok::r_square 1203309124Sdim }; 1204309124Sdim 1205309124Sdim TokenValue ClangFallthroughTokens[] = { 1206309124Sdim tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), 1207309124Sdim tok::coloncolon, PP.getIdentifierInfo("fallthrough"), 1208309124Sdim tok::r_square, tok::r_square 1209309124Sdim }; 1210309124Sdim 1211327952Sdim bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17; 1212309124Sdim 1213309124Sdim StringRef MacroName; 1214309124Sdim if (PreferClangAttr) 1215309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1216309124Sdim if (MacroName.empty()) 1217309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); 1218309124Sdim if (MacroName.empty() && !PreferClangAttr) 1219309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1220309124Sdim if (MacroName.empty()) 1221309124Sdim MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]"; 1222309124Sdim return MacroName; 1223309124Sdim} 1224309124Sdim 1225239462Sdimstatic void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, 1226239462Sdim bool PerFunction) { 1227327952Sdim // Only perform this analysis when using [[]] attributes. There is no good 1228327952Sdim // workflow for this warning when not using C++11. There is no good way to 1229341825Sdim // silence the warning (no attribute is available) unless we are using 1230327952Sdim // [[]] attributes. One could use pragmas to silence the warning, but as a 1231327952Sdim // general solution that is gross and not in the spirit of this warning. 1232243830Sdim // 1233327952Sdim // NOTE: This an intermediate solution. There are on-going discussions on 1234243830Sdim // how to properly support this warning outside of C++11 with an annotation. 1235327952Sdim if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes) 1236243830Sdim return; 1237243830Sdim 1238239462Sdim FallthroughMapper FM(S); 1239239462Sdim FM.TraverseStmt(AC.getBody()); 1240239462Sdim 1241239462Sdim if (!FM.foundSwitchStatements()) 1242239462Sdim return; 1243239462Sdim 1244239462Sdim if (PerFunction && FM.getFallthroughStmts().empty()) 1245239462Sdim return; 1246239462Sdim 1247239462Sdim CFG *Cfg = AC.getCFG(); 1248239462Sdim 1249239462Sdim if (!Cfg) 1250239462Sdim return; 1251239462Sdim 1252249423Sdim FM.fillReachableBlocks(Cfg); 1253239462Sdim 1254296417Sdim for (const CFGBlock *B : llvm::reverse(*Cfg)) { 1255249423Sdim const Stmt *Label = B->getLabel(); 1256239462Sdim 1257239462Sdim if (!Label || !isa<SwitchCase>(Label)) 1258239462Sdim continue; 1259239462Sdim 1260249423Sdim int AnnotatedCnt; 1261249423Sdim 1262321369Sdim bool IsTemplateInstantiation = false; 1263321369Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl())) 1264321369Sdim IsTemplateInstantiation = Function->isTemplateInstantiation(); 1265321369Sdim if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt, 1266321369Sdim IsTemplateInstantiation)) 1267239462Sdim continue; 1268239462Sdim 1269239462Sdim S.Diag(Label->getLocStart(), 1270239462Sdim PerFunction ? diag::warn_unannotated_fallthrough_per_function 1271239462Sdim : diag::warn_unannotated_fallthrough); 1272239462Sdim 1273239462Sdim if (!AnnotatedCnt) { 1274239462Sdim SourceLocation L = Label->getLocStart(); 1275239462Sdim if (L.isMacroID()) 1276239462Sdim continue; 1277249423Sdim if (S.getLangOpts().CPlusPlus11) { 1278249423Sdim const Stmt *Term = B->getTerminator(); 1279249423Sdim // Skip empty cases. 1280249423Sdim while (B->empty() && !Term && B->succ_size() == 1) { 1281249423Sdim B = *B->succ_begin(); 1282249423Sdim Term = B->getTerminator(); 1283249423Sdim } 1284249423Sdim if (!(B->empty() && Term && isa<BreakStmt>(Term))) { 1285243830Sdim Preprocessor &PP = S.getPreprocessor(); 1286309124Sdim StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); 1287243830Sdim SmallString<64> TextToInsert(AnnotationSpelling); 1288243830Sdim TextToInsert += "; "; 1289239462Sdim S.Diag(L, diag::note_insert_fallthrough_fixit) << 1290243830Sdim AnnotationSpelling << 1291243830Sdim FixItHint::CreateInsertion(L, TextToInsert); 1292239462Sdim } 1293239462Sdim } 1294239462Sdim S.Diag(L, diag::note_insert_break_fixit) << 1295239462Sdim FixItHint::CreateInsertion(L, "break; "); 1296239462Sdim } 1297239462Sdim } 1298239462Sdim 1299276479Sdim for (const auto *F : FM.getFallthroughStmts()) 1300309124Sdim S.Diag(F->getLocStart(), diag::err_fallthrough_attr_invalid_placement); 1301239462Sdim} 1302239462Sdim 1303243830Sdimstatic bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, 1304243830Sdim const Stmt *S) { 1305243830Sdim assert(S); 1306243830Sdim 1307243830Sdim do { 1308243830Sdim switch (S->getStmtClass()) { 1309243830Sdim case Stmt::ForStmtClass: 1310243830Sdim case Stmt::WhileStmtClass: 1311243830Sdim case Stmt::CXXForRangeStmtClass: 1312243830Sdim case Stmt::ObjCForCollectionStmtClass: 1313243830Sdim return true; 1314243830Sdim case Stmt::DoStmtClass: { 1315243830Sdim const Expr *Cond = cast<DoStmt>(S)->getCond(); 1316243830Sdim llvm::APSInt Val; 1317243830Sdim if (!Cond->EvaluateAsInt(Val, Ctx)) 1318243830Sdim return true; 1319243830Sdim return Val.getBoolValue(); 1320243830Sdim } 1321243830Sdim default: 1322243830Sdim break; 1323243830Sdim } 1324243830Sdim } while ((S = PM.getParent(S))); 1325243830Sdim 1326243830Sdim return false; 1327243830Sdim} 1328243830Sdim 1329243830Sdimstatic void diagnoseRepeatedUseOfWeak(Sema &S, 1330243830Sdim const sema::FunctionScopeInfo *CurFn, 1331243830Sdim const Decl *D, 1332243830Sdim const ParentMap &PM) { 1333243830Sdim typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy; 1334243830Sdim typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap; 1335243830Sdim typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector; 1336276479Sdim typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator> 1337276479Sdim StmtUsesPair; 1338243830Sdim 1339243830Sdim ASTContext &Ctx = S.getASTContext(); 1340243830Sdim 1341243830Sdim const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses(); 1342243830Sdim 1343243830Sdim // Extract all weak objects that are referenced more than once. 1344243830Sdim SmallVector<StmtUsesPair, 8> UsesByStmt; 1345243830Sdim for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end(); 1346243830Sdim I != E; ++I) { 1347243830Sdim const WeakUseVector &Uses = I->second; 1348243830Sdim 1349243830Sdim // Find the first read of the weak object. 1350243830Sdim WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); 1351243830Sdim for ( ; UI != UE; ++UI) { 1352243830Sdim if (UI->isUnsafe()) 1353243830Sdim break; 1354243830Sdim } 1355243830Sdim 1356243830Sdim // If there were only writes to this object, don't warn. 1357243830Sdim if (UI == UE) 1358243830Sdim continue; 1359243830Sdim 1360243830Sdim // If there was only one read, followed by any number of writes, and the 1361243830Sdim // read is not within a loop, don't warn. Additionally, don't warn in a 1362243830Sdim // loop if the base object is a local variable -- local variables are often 1363243830Sdim // changed in loops. 1364243830Sdim if (UI == Uses.begin()) { 1365243830Sdim WeakUseVector::const_iterator UI2 = UI; 1366243830Sdim for (++UI2; UI2 != UE; ++UI2) 1367243830Sdim if (UI2->isUnsafe()) 1368243830Sdim break; 1369243830Sdim 1370243830Sdim if (UI2 == UE) { 1371243830Sdim if (!isInLoop(Ctx, PM, UI->getUseExpr())) 1372243830Sdim continue; 1373243830Sdim 1374243830Sdim const WeakObjectProfileTy &Profile = I->first; 1375243830Sdim if (!Profile.isExactProfile()) 1376243830Sdim continue; 1377243830Sdim 1378243830Sdim const NamedDecl *Base = Profile.getBase(); 1379243830Sdim if (!Base) 1380243830Sdim Base = Profile.getProperty(); 1381243830Sdim assert(Base && "A profile always has a base or property."); 1382243830Sdim 1383243830Sdim if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base)) 1384243830Sdim if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base)) 1385243830Sdim continue; 1386243830Sdim } 1387243830Sdim } 1388243830Sdim 1389243830Sdim UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I)); 1390243830Sdim } 1391243830Sdim 1392243830Sdim if (UsesByStmt.empty()) 1393243830Sdim return; 1394243830Sdim 1395243830Sdim // Sort by first use so that we emit the warnings in a deterministic order. 1396276479Sdim SourceManager &SM = S.getSourceManager(); 1397341825Sdim llvm::sort(UsesByStmt.begin(), UsesByStmt.end(), 1398341825Sdim [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { 1399276479Sdim return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(), 1400276479Sdim RHS.first->getLocStart()); 1401276479Sdim }); 1402243830Sdim 1403243830Sdim // Classify the current code body for better warning text. 1404243830Sdim // This enum should stay in sync with the cases in 1405243830Sdim // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 1406243830Sdim // FIXME: Should we use a common classification enum and the same set of 1407243830Sdim // possibilities all throughout Sema? 1408243830Sdim enum { 1409243830Sdim Function, 1410243830Sdim Method, 1411243830Sdim Block, 1412243830Sdim Lambda 1413243830Sdim } FunctionKind; 1414243830Sdim 1415243830Sdim if (isa<sema::BlockScopeInfo>(CurFn)) 1416243830Sdim FunctionKind = Block; 1417243830Sdim else if (isa<sema::LambdaScopeInfo>(CurFn)) 1418243830Sdim FunctionKind = Lambda; 1419243830Sdim else if (isa<ObjCMethodDecl>(D)) 1420243830Sdim FunctionKind = Method; 1421243830Sdim else 1422243830Sdim FunctionKind = Function; 1423243830Sdim 1424243830Sdim // Iterate through the sorted problems and emit warnings for each. 1425276479Sdim for (const auto &P : UsesByStmt) { 1426276479Sdim const Stmt *FirstRead = P.first; 1427276479Sdim const WeakObjectProfileTy &Key = P.second->first; 1428276479Sdim const WeakUseVector &Uses = P.second->second; 1429243830Sdim 1430243830Sdim // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy 1431243830Sdim // may not contain enough information to determine that these are different 1432243830Sdim // properties. We can only be 100% sure of a repeated use in certain cases, 1433243830Sdim // and we adjust the diagnostic kind accordingly so that the less certain 1434243830Sdim // case can be turned off if it is too noisy. 1435243830Sdim unsigned DiagKind; 1436243830Sdim if (Key.isExactProfile()) 1437243830Sdim DiagKind = diag::warn_arc_repeated_use_of_weak; 1438243830Sdim else 1439243830Sdim DiagKind = diag::warn_arc_possible_repeated_use_of_weak; 1440243830Sdim 1441243830Sdim // Classify the weak object being accessed for better warning text. 1442243830Sdim // This enum should stay in sync with the cases in 1443243830Sdim // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 1444243830Sdim enum { 1445243830Sdim Variable, 1446243830Sdim Property, 1447243830Sdim ImplicitProperty, 1448243830Sdim Ivar 1449243830Sdim } ObjectKind; 1450243830Sdim 1451309124Sdim const NamedDecl *KeyProp = Key.getProperty(); 1452309124Sdim if (isa<VarDecl>(KeyProp)) 1453243830Sdim ObjectKind = Variable; 1454309124Sdim else if (isa<ObjCPropertyDecl>(KeyProp)) 1455243830Sdim ObjectKind = Property; 1456309124Sdim else if (isa<ObjCMethodDecl>(KeyProp)) 1457243830Sdim ObjectKind = ImplicitProperty; 1458309124Sdim else if (isa<ObjCIvarDecl>(KeyProp)) 1459243830Sdim ObjectKind = Ivar; 1460243830Sdim else 1461243830Sdim llvm_unreachable("Unexpected weak object kind!"); 1462243830Sdim 1463309124Sdim // Do not warn about IBOutlet weak property receivers being set to null 1464309124Sdim // since they are typically only used from the main thread. 1465309124Sdim if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp)) 1466309124Sdim if (Prop->hasAttr<IBOutletAttr>()) 1467309124Sdim continue; 1468309124Sdim 1469243830Sdim // Show the first time the object was read. 1470243830Sdim S.Diag(FirstRead->getLocStart(), DiagKind) 1471309124Sdim << int(ObjectKind) << KeyProp << int(FunctionKind) 1472243830Sdim << FirstRead->getSourceRange(); 1473243830Sdim 1474243830Sdim // Print all the other accesses as notes. 1475276479Sdim for (const auto &Use : Uses) { 1476276479Sdim if (Use.getUseExpr() == FirstRead) 1477243830Sdim continue; 1478276479Sdim S.Diag(Use.getUseExpr()->getLocStart(), 1479243830Sdim diag::note_arc_weak_also_accessed_here) 1480276479Sdim << Use.getUseExpr()->getSourceRange(); 1481243830Sdim } 1482243830Sdim } 1483243830Sdim} 1484243830Sdim 1485243830Sdimnamespace { 1486218893Sdimclass UninitValsDiagReporter : public UninitVariablesHandler { 1487218893Sdim Sema &S; 1488226633Sdim typedef SmallVector<UninitUse, 2> UsesVec; 1489261991Sdim typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType; 1490249423Sdim // Prefer using MapVector to DenseMap, so that iteration order will be 1491249423Sdim // the same as insertion order. This is needed to obtain a deterministic 1492249423Sdim // order of diagnostics when calling flushDiagnostics(). 1493249423Sdim typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; 1494296417Sdim UsesMap uses; 1495341825Sdim 1496218893Sdimpublic: 1497296417Sdim UninitValsDiagReporter(Sema &S) : S(S) {} 1498288943Sdim ~UninitValsDiagReporter() override { flushDiagnostics(); } 1499226633Sdim 1500249423Sdim MappedType &getUses(const VarDecl *vd) { 1501296417Sdim MappedType &V = uses[vd]; 1502261991Sdim if (!V.getPointer()) 1503261991Sdim V.setPointer(new UsesVec()); 1504226633Sdim return V; 1505218893Sdim } 1506276479Sdim 1507276479Sdim void handleUseOfUninitVariable(const VarDecl *vd, 1508276479Sdim const UninitUse &use) override { 1509261991Sdim getUses(vd).getPointer()->push_back(use); 1510226633Sdim } 1511341825Sdim 1512276479Sdim void handleSelfInit(const VarDecl *vd) override { 1513261991Sdim getUses(vd).setInt(true); 1514226633Sdim } 1515341825Sdim 1516218893Sdim void flushDiagnostics() { 1517296417Sdim for (const auto &P : uses) { 1518276479Sdim const VarDecl *vd = P.first; 1519276479Sdim const MappedType &V = P.second; 1520218893Sdim 1521261991Sdim UsesVec *vec = V.getPointer(); 1522261991Sdim bool hasSelfInit = V.getInt(); 1523218893Sdim 1524341825Sdim // Specially handle the case where we have uses of an uninitialized 1525226633Sdim // variable, but the root cause is an idiomatic self-init. We want 1526226633Sdim // to report the diagnostic at the self-init since that is the root cause. 1527234353Sdim if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) 1528239462Sdim DiagnoseUninitializedUse(S, vd, 1529239462Sdim UninitUse(vd->getInit()->IgnoreParenCasts(), 1530239462Sdim /* isAlwaysUninit */ true), 1531234353Sdim /* alwaysReportSelfInit */ true); 1532226633Sdim else { 1533226633Sdim // Sort the uses by their SourceLocations. While not strictly 1534226633Sdim // guaranteed to produce them in line/column order, this will provide 1535226633Sdim // a stable ordering. 1536341825Sdim llvm::sort(vec->begin(), vec->end(), 1537341825Sdim [](const UninitUse &a, const UninitUse &b) { 1538276479Sdim // Prefer a more confident report over a less confident one. 1539276479Sdim if (a.getKind() != b.getKind()) 1540276479Sdim return a.getKind() > b.getKind(); 1541276479Sdim return a.getUser()->getLocStart() < b.getUser()->getLocStart(); 1542276479Sdim }); 1543276479Sdim 1544276479Sdim for (const auto &U : *vec) { 1545239462Sdim // If we have self-init, downgrade all uses to 'may be uninitialized'. 1546276479Sdim UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U; 1547239462Sdim 1548239462Sdim if (DiagnoseUninitializedUse(S, vd, Use)) 1549226633Sdim // Skip further diagnostics for this variable. We try to warn only 1550226633Sdim // on the first point at which a variable is used uninitialized. 1551226633Sdim break; 1552218893Sdim } 1553218893Sdim } 1554341825Sdim 1555226633Sdim // Release the uses vector. 1556218893Sdim delete vec; 1557218893Sdim } 1558296417Sdim 1559296417Sdim uses.clear(); 1560218893Sdim } 1561234353Sdim 1562234353Sdimprivate: 1563234353Sdim static bool hasAlwaysUninitializedUse(const UsesVec* vec) { 1564276479Sdim return std::any_of(vec->begin(), vec->end(), [](const UninitUse &U) { 1565276479Sdim return U.getKind() == UninitUse::Always || 1566276479Sdim U.getKind() == UninitUse::AfterCall || 1567276479Sdim U.getKind() == UninitUse::AfterDecl; 1568276479Sdim }); 1569234353Sdim } 1570218893Sdim}; 1571296417Sdim} // anonymous namespace 1572218893Sdim 1573226633Sdimnamespace clang { 1574261991Sdimnamespace { 1575249423Sdimtypedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; 1576234353Sdimtypedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; 1577234353Sdimtypedef std::list<DelayedDiag> DiagList; 1578226633Sdim 1579226633Sdimstruct SortDiagBySourceLocation { 1580234353Sdim SourceManager &SM; 1581234353Sdim SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {} 1582226633Sdim 1583226633Sdim bool operator()(const DelayedDiag &left, const DelayedDiag &right) { 1584226633Sdim // Although this call will be slow, this is only called when outputting 1585226633Sdim // multiple warnings. 1586234353Sdim return SM.isBeforeInTranslationUnit(left.first.first, right.first.first); 1587226633Sdim } 1588226633Sdim}; 1589296417Sdim} // anonymous namespace 1590296417Sdim} // namespace clang 1591226633Sdim 1592261991Sdim//===----------------------------------------------------------------------===// 1593261991Sdim// -Wthread-safety 1594261991Sdim//===----------------------------------------------------------------------===// 1595261991Sdimnamespace clang { 1596280031Sdimnamespace threadSafety { 1597288943Sdimnamespace { 1598280031Sdimclass ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { 1599226633Sdim Sema &S; 1600226633Sdim DiagList Warnings; 1601234353Sdim SourceLocation FunLocation, FunEndLocation; 1602226633Sdim 1603280031Sdim const FunctionDecl *CurrentFunction; 1604280031Sdim bool Verbose; 1605280031Sdim 1606280031Sdim OptionalNotes getNotes() const { 1607280031Sdim if (Verbose && CurrentFunction) { 1608280031Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), 1609280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1610341825Sdim << CurrentFunction); 1611280031Sdim return OptionalNotes(1, FNote); 1612280031Sdim } 1613280031Sdim return OptionalNotes(); 1614280031Sdim } 1615280031Sdim 1616280031Sdim OptionalNotes getNotes(const PartialDiagnosticAt &Note) const { 1617280031Sdim OptionalNotes ONS(1, Note); 1618280031Sdim if (Verbose && CurrentFunction) { 1619280031Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), 1620280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1621341825Sdim << CurrentFunction); 1622288943Sdim ONS.push_back(std::move(FNote)); 1623280031Sdim } 1624280031Sdim return ONS; 1625280031Sdim } 1626280031Sdim 1627280031Sdim OptionalNotes getNotes(const PartialDiagnosticAt &Note1, 1628280031Sdim const PartialDiagnosticAt &Note2) const { 1629280031Sdim OptionalNotes ONS; 1630280031Sdim ONS.push_back(Note1); 1631280031Sdim ONS.push_back(Note2); 1632280031Sdim if (Verbose && CurrentFunction) { 1633280031Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), 1634280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1635341825Sdim << CurrentFunction); 1636288943Sdim ONS.push_back(std::move(FNote)); 1637280031Sdim } 1638280031Sdim return ONS; 1639280031Sdim } 1640280031Sdim 1641226633Sdim // Helper functions 1642276479Sdim void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName, 1643276479Sdim SourceLocation Loc) { 1644234353Sdim // Gracefully handle rare cases when the analysis can't get a more 1645234353Sdim // precise source location. 1646234353Sdim if (!Loc.isValid()) 1647234353Sdim Loc = FunLocation; 1648276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName); 1649288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1650226633Sdim } 1651226633Sdim 1652226633Sdim public: 1653234353Sdim ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) 1654280031Sdim : S(S), FunLocation(FL), FunEndLocation(FEL), 1655280031Sdim CurrentFunction(nullptr), Verbose(false) {} 1656226633Sdim 1657280031Sdim void setVerbose(bool b) { Verbose = b; } 1658280031Sdim 1659341825Sdim /// Emit all buffered diagnostics in order of sourcelocation. 1660226633Sdim /// We need to output diagnostics produced while iterating through 1661226633Sdim /// the lockset in deterministic order, so this function orders diagnostics 1662226633Sdim /// and outputs them. 1663226633Sdim void emitDiagnostics() { 1664234353Sdim Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 1665276479Sdim for (const auto &Diag : Warnings) { 1666276479Sdim S.Diag(Diag.first.first, Diag.first.second); 1667276479Sdim for (const auto &Note : Diag.second) 1668276479Sdim S.Diag(Note.first, Note.second); 1669234353Sdim } 1670226633Sdim } 1671226633Sdim 1672276479Sdim void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override { 1673276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock) 1674276479Sdim << Loc); 1675288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1676226633Sdim } 1677280031Sdim 1678276479Sdim void handleUnmatchedUnlock(StringRef Kind, Name LockName, 1679276479Sdim SourceLocation Loc) override { 1680276479Sdim warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc); 1681226633Sdim } 1682280031Sdim 1683276479Sdim void handleIncorrectUnlockKind(StringRef Kind, Name LockName, 1684276479Sdim LockKind Expected, LockKind Received, 1685276479Sdim SourceLocation Loc) override { 1686276479Sdim if (Loc.isInvalid()) 1687276479Sdim Loc = FunLocation; 1688276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch) 1689276479Sdim << Kind << LockName << Received 1690276479Sdim << Expected); 1691288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1692226633Sdim } 1693280031Sdim 1694276479Sdim void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override { 1695276479Sdim warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc); 1696276479Sdim } 1697226633Sdim 1698276479Sdim void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, 1699276479Sdim SourceLocation LocLocked, 1700234353Sdim SourceLocation LocEndOfScope, 1701276479Sdim LockErrorKind LEK) override { 1702226633Sdim unsigned DiagID = 0; 1703226633Sdim switch (LEK) { 1704226633Sdim case LEK_LockedSomePredecessors: 1705234353Sdim DiagID = diag::warn_lock_some_predecessors; 1706226633Sdim break; 1707226633Sdim case LEK_LockedSomeLoopIterations: 1708226633Sdim DiagID = diag::warn_expecting_lock_held_on_loop; 1709226633Sdim break; 1710226633Sdim case LEK_LockedAtEndOfFunction: 1711226633Sdim DiagID = diag::warn_no_unlock; 1712226633Sdim break; 1713239462Sdim case LEK_NotLockedAtEndOfFunction: 1714239462Sdim DiagID = diag::warn_expecting_locked; 1715239462Sdim break; 1716226633Sdim } 1717234353Sdim if (LocEndOfScope.isInvalid()) 1718234353Sdim LocEndOfScope = FunEndLocation; 1719234353Sdim 1720276479Sdim PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind 1721276479Sdim << LockName); 1722251662Sdim if (LocLocked.isValid()) { 1723276479Sdim PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here) 1724276479Sdim << Kind); 1725288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1726251662Sdim return; 1727251662Sdim } 1728288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1729226633Sdim } 1730226633Sdim 1731276479Sdim void handleExclusiveAndShared(StringRef Kind, Name LockName, 1732276479Sdim SourceLocation Loc1, 1733276479Sdim SourceLocation Loc2) override { 1734276479Sdim PartialDiagnosticAt Warning(Loc1, 1735276479Sdim S.PDiag(diag::warn_lock_exclusive_and_shared) 1736276479Sdim << Kind << LockName); 1737276479Sdim PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) 1738276479Sdim << Kind << LockName); 1739288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1740226633Sdim } 1741226633Sdim 1742276479Sdim void handleNoMutexHeld(StringRef Kind, const NamedDecl *D, 1743276479Sdim ProtectedOperationKind POK, AccessKind AK, 1744276479Sdim SourceLocation Loc) override { 1745276479Sdim assert((POK == POK_VarAccess || POK == POK_VarDereference) && 1746276479Sdim "Only works for variables"); 1747226633Sdim unsigned DiagID = POK == POK_VarAccess? 1748226633Sdim diag::warn_variable_requires_any_lock: 1749226633Sdim diag::warn_var_deref_requires_any_lock; 1750234353Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) 1751341825Sdim << D << getLockKindFromAccessKind(AK)); 1752288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1753226633Sdim } 1754226633Sdim 1755276479Sdim void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, 1756276479Sdim ProtectedOperationKind POK, Name LockName, 1757276479Sdim LockKind LK, SourceLocation Loc, 1758276479Sdim Name *PossibleMatch) override { 1759226633Sdim unsigned DiagID = 0; 1760243830Sdim if (PossibleMatch) { 1761243830Sdim switch (POK) { 1762243830Sdim case POK_VarAccess: 1763243830Sdim DiagID = diag::warn_variable_requires_lock_precise; 1764243830Sdim break; 1765243830Sdim case POK_VarDereference: 1766243830Sdim DiagID = diag::warn_var_deref_requires_lock_precise; 1767243830Sdim break; 1768243830Sdim case POK_FunctionCall: 1769243830Sdim DiagID = diag::warn_fun_requires_lock_precise; 1770243830Sdim break; 1771280031Sdim case POK_PassByRef: 1772280031Sdim DiagID = diag::warn_guarded_pass_by_reference; 1773280031Sdim break; 1774280031Sdim case POK_PtPassByRef: 1775280031Sdim DiagID = diag::warn_pt_guarded_pass_by_reference; 1776280031Sdim break; 1777243830Sdim } 1778276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 1779341825Sdim << D 1780276479Sdim << LockName << LK); 1781243830Sdim PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) 1782276479Sdim << *PossibleMatch); 1783280031Sdim if (Verbose && POK == POK_VarAccess) { 1784280031Sdim PartialDiagnosticAt VNote(D->getLocation(), 1785280031Sdim S.PDiag(diag::note_guarded_by_declared_here) 1786280031Sdim << D->getNameAsString()); 1787288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote)); 1788280031Sdim } else 1789288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1790243830Sdim } else { 1791243830Sdim switch (POK) { 1792243830Sdim case POK_VarAccess: 1793243830Sdim DiagID = diag::warn_variable_requires_lock; 1794243830Sdim break; 1795243830Sdim case POK_VarDereference: 1796243830Sdim DiagID = diag::warn_var_deref_requires_lock; 1797243830Sdim break; 1798243830Sdim case POK_FunctionCall: 1799243830Sdim DiagID = diag::warn_fun_requires_lock; 1800243830Sdim break; 1801280031Sdim case POK_PassByRef: 1802280031Sdim DiagID = diag::warn_guarded_pass_by_reference; 1803280031Sdim break; 1804280031Sdim case POK_PtPassByRef: 1805280031Sdim DiagID = diag::warn_pt_guarded_pass_by_reference; 1806280031Sdim break; 1807243830Sdim } 1808276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 1809341825Sdim << D 1810276479Sdim << LockName << LK); 1811280031Sdim if (Verbose && POK == POK_VarAccess) { 1812280031Sdim PartialDiagnosticAt Note(D->getLocation(), 1813341825Sdim S.PDiag(diag::note_guarded_by_declared_here)); 1814288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1815280031Sdim } else 1816288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1817226633Sdim } 1818226633Sdim } 1819226633Sdim 1820288943Sdim void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, 1821288943Sdim SourceLocation Loc) override { 1822280031Sdim PartialDiagnosticAt Warning(Loc, 1823280031Sdim S.PDiag(diag::warn_acquire_requires_negative_cap) 1824280031Sdim << Kind << LockName << Neg); 1825288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1826280031Sdim } 1827280031Sdim 1828276479Sdim void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, 1829276479Sdim SourceLocation Loc) override { 1830276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex) 1831276479Sdim << Kind << FunName << LockName); 1832288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1833226633Sdim } 1834280031Sdim 1835288943Sdim void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name, 1836288943Sdim SourceLocation Loc) override { 1837288943Sdim PartialDiagnosticAt Warning(Loc, 1838288943Sdim S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name); 1839288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1840288943Sdim } 1841288943Sdim 1842288943Sdim void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override { 1843288943Sdim PartialDiagnosticAt Warning(Loc, 1844288943Sdim S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); 1845288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1846288943Sdim } 1847288943Sdim 1848280031Sdim void enterFunction(const FunctionDecl* FD) override { 1849280031Sdim CurrentFunction = FD; 1850280031Sdim } 1851280031Sdim 1852280031Sdim void leaveFunction(const FunctionDecl* FD) override { 1853296417Sdim CurrentFunction = nullptr; 1854280031Sdim } 1855226633Sdim}; 1856296417Sdim} // anonymous namespace 1857288943Sdim} // namespace threadSafety 1858288943Sdim} // namespace clang 1859280031Sdim 1860226633Sdim//===----------------------------------------------------------------------===// 1861261991Sdim// -Wconsumed 1862261991Sdim//===----------------------------------------------------------------------===// 1863261991Sdim 1864261991Sdimnamespace clang { 1865261991Sdimnamespace consumed { 1866261991Sdimnamespace { 1867261991Sdimclass ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { 1868341825Sdim 1869261991Sdim Sema &S; 1870261991Sdim DiagList Warnings; 1871341825Sdim 1872261991Sdimpublic: 1873288943Sdim 1874261991Sdim ConsumedWarningsHandler(Sema &S) : S(S) {} 1875276479Sdim 1876276479Sdim void emitDiagnostics() override { 1877261991Sdim Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 1878276479Sdim for (const auto &Diag : Warnings) { 1879276479Sdim S.Diag(Diag.first.first, Diag.first.second); 1880276479Sdim for (const auto &Note : Diag.second) 1881276479Sdim S.Diag(Note.first, Note.second); 1882261991Sdim } 1883261991Sdim } 1884276479Sdim 1885276479Sdim void warnLoopStateMismatch(SourceLocation Loc, 1886276479Sdim StringRef VariableName) override { 1887261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) << 1888261991Sdim VariableName); 1889288943Sdim 1890288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1891261991Sdim } 1892341825Sdim 1893261991Sdim void warnParamReturnTypestateMismatch(SourceLocation Loc, 1894261991Sdim StringRef VariableName, 1895261991Sdim StringRef ExpectedState, 1896276479Sdim StringRef ObservedState) override { 1897341825Sdim 1898261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1899261991Sdim diag::warn_param_return_typestate_mismatch) << VariableName << 1900261991Sdim ExpectedState << ObservedState); 1901288943Sdim 1902288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1903261991Sdim } 1904341825Sdim 1905261991Sdim void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 1906276479Sdim StringRef ObservedState) override { 1907341825Sdim 1908261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1909261991Sdim diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState); 1910288943Sdim 1911288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1912261991Sdim } 1913341825Sdim 1914261991Sdim void warnReturnTypestateForUnconsumableType(SourceLocation Loc, 1915276479Sdim StringRef TypeName) override { 1916261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1917261991Sdim diag::warn_return_typestate_for_unconsumable_type) << TypeName); 1918288943Sdim 1919288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1920261991Sdim } 1921341825Sdim 1922261991Sdim void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 1923276479Sdim StringRef ObservedState) override { 1924341825Sdim 1925261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1926261991Sdim diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState); 1927288943Sdim 1928288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1929261991Sdim } 1930341825Sdim 1931261991Sdim void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, 1932276479Sdim SourceLocation Loc) override { 1933341825Sdim 1934261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1935261991Sdim diag::warn_use_of_temp_in_invalid_state) << MethodName << State); 1936288943Sdim 1937288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1938261991Sdim } 1939341825Sdim 1940261991Sdim void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, 1941276479Sdim StringRef State, SourceLocation Loc) override { 1942341825Sdim 1943261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) << 1944261991Sdim MethodName << VariableName << State); 1945288943Sdim 1946288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1947261991Sdim } 1948261991Sdim}; 1949296417Sdim} // anonymous namespace 1950296417Sdim} // namespace consumed 1951296417Sdim} // namespace clang 1952261991Sdim 1953261991Sdim//===----------------------------------------------------------------------===// 1954205408Srdivacky// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based 1955205408Srdivacky// warnings on a function, method, or block. 1956205408Srdivacky//===----------------------------------------------------------------------===// 1957205408Srdivacky 1958206084Srdivackyclang::sema::AnalysisBasedWarnings::Policy::Policy() { 1959206084Srdivacky enableCheckFallThrough = 1; 1960206084Srdivacky enableCheckUnreachable = 0; 1961226633Sdim enableThreadSafetyAnalysis = 0; 1962261991Sdim enableConsumedAnalysis = 0; 1963206084Srdivacky} 1964206084Srdivacky 1965276479Sdimstatic unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) { 1966276479Sdim return (unsigned)!D.isIgnored(diag, SourceLocation()); 1967276479Sdim} 1968276479Sdim 1969224145Sdimclang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) 1970224145Sdim : S(s), 1971224145Sdim NumFunctionsAnalyzed(0), 1972224145Sdim NumFunctionsWithBadCFGs(0), 1973224145Sdim NumCFGBlocks(0), 1974224145Sdim MaxCFGBlocksPerFunction(0), 1975224145Sdim NumUninitAnalysisFunctions(0), 1976224145Sdim NumUninitAnalysisVariables(0), 1977224145Sdim MaxUninitAnalysisVariablesPerFunction(0), 1978224145Sdim NumUninitAnalysisBlockVisits(0), 1979224145Sdim MaxUninitAnalysisBlockVisitsPerFunction(0) { 1980276479Sdim 1981276479Sdim using namespace diag; 1982226633Sdim DiagnosticsEngine &D = S.getDiagnostics(); 1983276479Sdim 1984276479Sdim DefaultPolicy.enableCheckUnreachable = 1985276479Sdim isEnabled(D, warn_unreachable) || 1986276479Sdim isEnabled(D, warn_unreachable_break) || 1987276479Sdim isEnabled(D, warn_unreachable_return) || 1988276479Sdim isEnabled(D, warn_unreachable_loop_increment); 1989276479Sdim 1990276479Sdim DefaultPolicy.enableThreadSafetyAnalysis = 1991276479Sdim isEnabled(D, warn_double_lock); 1992276479Sdim 1993276479Sdim DefaultPolicy.enableConsumedAnalysis = 1994276479Sdim isEnabled(D, warn_use_in_invalid_state); 1995205408Srdivacky} 1996205408Srdivacky 1997276479Sdimstatic void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { 1998276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) 1999219077Sdim S.Diag(D.Loc, D.PD); 2000219077Sdim} 2001219077Sdim 2002206084Srdivackyvoid clang::sema:: 2003206084SrdivackyAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 2004219077Sdim sema::FunctionScopeInfo *fscope, 2005219077Sdim const Decl *D, const BlockExpr *blkExpr) { 2006206084Srdivacky 2007205408Srdivacky // We avoid doing analysis-based warnings when there are errors for 2008205408Srdivacky // two reasons: 2009205408Srdivacky // (1) The CFGs often can't be constructed (if the body is invalid), so 2010205408Srdivacky // don't bother trying. 2011205408Srdivacky // (2) The code already has problems; running the analysis just takes more 2012205408Srdivacky // time. 2013226633Sdim DiagnosticsEngine &Diags = S.getDiagnostics(); 2014207619Srdivacky 2015327952Sdim // Do not do any analysis if we are going to just ignore them. 2016327952Sdim if (Diags.getIgnoreAllWarnings() || 2017327952Sdim (Diags.getSuppressSystemWarnings() && 2018327952Sdim S.SourceMgr.isInSystemHeader(D->getLocation()))) 2019206084Srdivacky return; 2020206084Srdivacky 2021212904Sdim // For code in dependent contexts, we'll do this at instantiation time. 2022212904Sdim if (cast<DeclContext>(D)->isDependentContext()) 2023212904Sdim return; 2024205408Srdivacky 2025309124Sdim if (Diags.hasUncompilableErrorOccurred()) { 2026219077Sdim // Flush out any possibly unreachable diagnostics. 2027219077Sdim flushDiagnostics(S, fscope); 2028219077Sdim return; 2029219077Sdim } 2030341825Sdim 2031205408Srdivacky const Stmt *Body = D->getBody(); 2032205408Srdivacky assert(Body); 2033205408Srdivacky 2034261991Sdim // Construct the analysis context with the specified CFG build options. 2035276479Sdim AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D); 2036226633Sdim 2037205408Srdivacky // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 2038261991Sdim // explosion for destructors that can result and the compile time hit. 2039226633Sdim AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; 2040226633Sdim AC.getCFGBuildOptions().AddEHEdges = false; 2041226633Sdim AC.getCFGBuildOptions().AddInitializers = true; 2042226633Sdim AC.getCFGBuildOptions().AddImplicitDtors = true; 2043243830Sdim AC.getCFGBuildOptions().AddTemporaryDtors = true; 2044276479Sdim AC.getCFGBuildOptions().AddCXXNewAllocator = false; 2045288943Sdim AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; 2046243830Sdim 2047226633Sdim // Force that certain expressions appear as CFGElements in the CFG. This 2048226633Sdim // is used to speed up various analyses. 2049226633Sdim // FIXME: This isn't the right factoring. This is here for initial 2050226633Sdim // prototyping, but we need a way for analyses to say what expressions they 2051226633Sdim // expect to always be CFGElements and then fill in the BuildOptions 2052226633Sdim // appropriately. This is essentially a layering violation. 2053261991Sdim if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis || 2054261991Sdim P.enableConsumedAnalysis) { 2055234353Sdim // Unreachable code analysis and thread safety require a linearized CFG. 2056226633Sdim AC.getCFGBuildOptions().setAllAlwaysAdd(); 2057226633Sdim } 2058226633Sdim else { 2059226633Sdim AC.getCFGBuildOptions() 2060226633Sdim .setAlwaysAdd(Stmt::BinaryOperatorClass) 2061239462Sdim .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) 2062226633Sdim .setAlwaysAdd(Stmt::BlockExprClass) 2063226633Sdim .setAlwaysAdd(Stmt::CStyleCastExprClass) 2064226633Sdim .setAlwaysAdd(Stmt::DeclRefExprClass) 2065226633Sdim .setAlwaysAdd(Stmt::ImplicitCastExprClass) 2066239462Sdim .setAlwaysAdd(Stmt::UnaryOperatorClass) 2067239462Sdim .setAlwaysAdd(Stmt::AttributedStmtClass); 2068226633Sdim } 2069205408Srdivacky 2070276479Sdim // Install the logical handler for -Wtautological-overlap-compare 2071276479Sdim std::unique_ptr<LogicalErrorHandler> LEH; 2072276479Sdim if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, 2073276479Sdim D->getLocStart())) { 2074276479Sdim LEH.reset(new LogicalErrorHandler(S)); 2075276479Sdim AC.getCFGBuildOptions().Observer = LEH.get(); 2076276479Sdim } 2077261991Sdim 2078219077Sdim // Emit delayed diagnostics. 2079219077Sdim if (!fscope->PossiblyUnreachableDiags.empty()) { 2080219077Sdim bool analyzed = false; 2081221345Sdim 2082221345Sdim // Register the expressions with the CFGBuilder. 2083276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) { 2084276479Sdim if (D.stmt) 2085276479Sdim AC.registerForcedBlockExpression(D.stmt); 2086221345Sdim } 2087221345Sdim 2088221345Sdim if (AC.getCFG()) { 2089221345Sdim analyzed = true; 2090276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) { 2091221345Sdim bool processed = false; 2092276479Sdim if (D.stmt) { 2093276479Sdim const CFGBlock *block = AC.getBlockForRegisteredExpression(D.stmt); 2094234353Sdim CFGReverseBlockReachabilityAnalysis *cra = 2095234353Sdim AC.getCFGReachablityAnalysis(); 2096234353Sdim // FIXME: We should be able to assert that block is non-null, but 2097234353Sdim // the CFG analysis can skip potentially-evaluated expressions in 2098234353Sdim // edge cases; see test/Sema/vla-2.c. 2099234353Sdim if (block && cra) { 2100219077Sdim // Can this block be reached from the entrance? 2101221345Sdim if (cra->isReachable(&AC.getCFG()->getEntry(), block)) 2102219077Sdim S.Diag(D.Loc, D.PD); 2103221345Sdim processed = true; 2104219077Sdim } 2105219077Sdim } 2106221345Sdim if (!processed) { 2107221345Sdim // Emit the warning anyway if we cannot map to a basic block. 2108221345Sdim S.Diag(D.Loc, D.PD); 2109221345Sdim } 2110219077Sdim } 2111221345Sdim } 2112219077Sdim 2113219077Sdim if (!analyzed) 2114219077Sdim flushDiagnostics(S, fscope); 2115219077Sdim } 2116341825Sdim 2117205408Srdivacky // Warning: check missing 'return' 2118206084Srdivacky if (P.enableCheckFallThrough) { 2119205408Srdivacky const CheckFallThroughDiagnostics &CD = 2120314564Sdim (isa<BlockDecl>(D) 2121314564Sdim ? CheckFallThroughDiagnostics::MakeForBlock() 2122314564Sdim : (isa<CXXMethodDecl>(D) && 2123314564Sdim cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && 2124314564Sdim cast<CXXMethodDecl>(D)->getParent()->isLambda()) 2125314564Sdim ? CheckFallThroughDiagnostics::MakeForLambda() 2126321369Sdim : (fscope->isCoroutine() 2127314564Sdim ? CheckFallThroughDiagnostics::MakeForCoroutine(D) 2128314564Sdim : CheckFallThroughDiagnostics::MakeForFunction(D))); 2129341825Sdim CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC, fscope); 2130205408Srdivacky } 2131205408Srdivacky 2132205408Srdivacky // Warning: check for unreachable code 2133234353Sdim if (P.enableCheckUnreachable) { 2134234353Sdim // Only check for unreachable code on non-template instantiations. 2135234353Sdim // Different template instantiations can effectively change the control-flow 2136234353Sdim // and it is very difficult to prove that a snippet of code in a template 2137234353Sdim // is unreachable for all instantiations. 2138234353Sdim bool isTemplateInstantiation = false; 2139234353Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) 2140234353Sdim isTemplateInstantiation = Function->isTemplateInstantiation(); 2141234353Sdim if (!isTemplateInstantiation) 2142234353Sdim CheckUnreachable(S, AC); 2143234353Sdim } 2144226633Sdim 2145226633Sdim // Check for thread safety violations 2146226633Sdim if (P.enableThreadSafetyAnalysis) { 2147234353Sdim SourceLocation FL = AC.getDecl()->getLocation(); 2148234353Sdim SourceLocation FEL = AC.getDecl()->getLocEnd(); 2149280031Sdim threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL); 2150276479Sdim if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getLocStart())) 2151249423Sdim Reporter.setIssueBetaWarnings(true); 2152280031Sdim if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart())) 2153280031Sdim Reporter.setVerbose(true); 2154249423Sdim 2155288943Sdim threadSafety::runThreadSafetyAnalysis(AC, Reporter, 2156288943Sdim &S.ThreadSafetyDeclCache); 2157226633Sdim Reporter.emitDiagnostics(); 2158226633Sdim } 2159226633Sdim 2160261991Sdim // Check for violations of consumed properties. 2161261991Sdim if (P.enableConsumedAnalysis) { 2162261991Sdim consumed::ConsumedWarningsHandler WarningHandler(S); 2163261991Sdim consumed::ConsumedAnalyzer Analyzer(WarningHandler); 2164261991Sdim Analyzer.run(AC); 2165261991Sdim } 2166261991Sdim 2167276479Sdim if (!Diags.isIgnored(diag::warn_uninit_var, D->getLocStart()) || 2168276479Sdim !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getLocStart()) || 2169276479Sdim !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getLocStart())) { 2170221345Sdim if (CFG *cfg = AC.getCFG()) { 2171218893Sdim UninitValsDiagReporter reporter(S); 2172224145Sdim UninitVariablesAnalysisStats stats; 2173224145Sdim std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats)); 2174218893Sdim runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, 2175224145Sdim reporter, stats); 2176224145Sdim 2177224145Sdim if (S.CollectStats && stats.NumVariablesAnalyzed > 0) { 2178224145Sdim ++NumUninitAnalysisFunctions; 2179224145Sdim NumUninitAnalysisVariables += stats.NumVariablesAnalyzed; 2180224145Sdim NumUninitAnalysisBlockVisits += stats.NumBlockVisits; 2181224145Sdim MaxUninitAnalysisVariablesPerFunction = 2182224145Sdim std::max(MaxUninitAnalysisVariablesPerFunction, 2183224145Sdim stats.NumVariablesAnalyzed); 2184224145Sdim MaxUninitAnalysisBlockVisitsPerFunction = 2185224145Sdim std::max(MaxUninitAnalysisBlockVisitsPerFunction, 2186224145Sdim stats.NumBlockVisits); 2187224145Sdim } 2188218893Sdim } 2189218893Sdim } 2190224145Sdim 2191239462Sdim bool FallThroughDiagFull = 2192276479Sdim !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getLocStart()); 2193276479Sdim bool FallThroughDiagPerFunction = !Diags.isIgnored( 2194276479Sdim diag::warn_unannotated_fallthrough_per_function, D->getLocStart()); 2195309124Sdim if (FallThroughDiagFull || FallThroughDiagPerFunction || 2196309124Sdim fscope->HasFallthroughStmt) { 2197239462Sdim DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); 2198239462Sdim } 2199239462Sdim 2200296417Sdim if (S.getLangOpts().ObjCWeak && 2201276479Sdim !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getLocStart())) 2202243830Sdim diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); 2203243830Sdim 2204276479Sdim 2205276479Sdim // Check for infinite self-recursion in functions 2206276479Sdim if (!Diags.isIgnored(diag::warn_infinite_recursive_function, 2207276479Sdim D->getLocStart())) { 2208276479Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 2209276479Sdim checkRecursiveFunction(S, FD, Body, AC); 2210276479Sdim } 2211276479Sdim } 2212276479Sdim 2213321369Sdim // Check for throw out of non-throwing function. 2214321369Sdim if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getLocStart())) 2215321369Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 2216321369Sdim if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) 2217321369Sdim checkThrowInNonThrowingFunc(S, FD, AC); 2218321369Sdim 2219276479Sdim // If none of the previous checks caused a CFG build, trigger one here 2220276479Sdim // for -Wtautological-overlap-compare 2221276479Sdim if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, 2222276479Sdim D->getLocStart())) { 2223276479Sdim AC.getCFG(); 2224276479Sdim } 2225276479Sdim 2226224145Sdim // Collect statistics about the CFG if it was built. 2227224145Sdim if (S.CollectStats && AC.isCFGBuilt()) { 2228224145Sdim ++NumFunctionsAnalyzed; 2229224145Sdim if (CFG *cfg = AC.getCFG()) { 2230224145Sdim // If we successfully built a CFG for this context, record some more 2231224145Sdim // detail information about it. 2232224145Sdim NumCFGBlocks += cfg->getNumBlockIDs(); 2233224145Sdim MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction, 2234224145Sdim cfg->getNumBlockIDs()); 2235224145Sdim } else { 2236224145Sdim ++NumFunctionsWithBadCFGs; 2237224145Sdim } 2238224145Sdim } 2239205408Srdivacky} 2240224145Sdim 2241224145Sdimvoid clang::sema::AnalysisBasedWarnings::PrintStats() const { 2242224145Sdim llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; 2243224145Sdim 2244224145Sdim unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; 2245224145Sdim unsigned AvgCFGBlocksPerFunction = 2246224145Sdim !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; 2247224145Sdim llvm::errs() << NumFunctionsAnalyzed << " functions analyzed (" 2248224145Sdim << NumFunctionsWithBadCFGs << " w/o CFGs).\n" 2249224145Sdim << " " << NumCFGBlocks << " CFG blocks built.\n" 2250224145Sdim << " " << AvgCFGBlocksPerFunction 2251224145Sdim << " average CFG blocks per function.\n" 2252224145Sdim << " " << MaxCFGBlocksPerFunction 2253224145Sdim << " max CFG blocks per function.\n"; 2254224145Sdim 2255224145Sdim unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0 2256224145Sdim : NumUninitAnalysisVariables/NumUninitAnalysisFunctions; 2257224145Sdim unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0 2258224145Sdim : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions; 2259224145Sdim llvm::errs() << NumUninitAnalysisFunctions 2260224145Sdim << " functions analyzed for uninitialiazed variables\n" 2261224145Sdim << " " << NumUninitAnalysisVariables << " variables analyzed.\n" 2262224145Sdim << " " << AvgUninitVariablesPerFunction 2263224145Sdim << " average variables per function.\n" 2264224145Sdim << " " << MaxUninitAnalysisVariablesPerFunction 2265224145Sdim << " max variables per function.\n" 2266224145Sdim << " " << NumUninitAnalysisBlockVisits << " block visits.\n" 2267224145Sdim << " " << AvgUninitBlockVisitsPerFunction 2268224145Sdim << " average block visits per function.\n" 2269224145Sdim << " " << MaxUninitAnalysisBlockVisitsPerFunction 2270224145Sdim << " max block visits per function.\n"; 2271224145Sdim} 2272