1205408Srdivacky//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// 2205408Srdivacky// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6205408Srdivacky// 7205408Srdivacky//===----------------------------------------------------------------------===// 8205408Srdivacky// 9205408Srdivacky// This file defines analysis_warnings::[Policy,Executor]. 10205408Srdivacky// Together they are used by Sema to issue warnings based on inexpensive 11205408Srdivacky// static analysis algorithms in libAnalysis. 12205408Srdivacky// 13205408Srdivacky//===----------------------------------------------------------------------===// 14205408Srdivacky 15212904Sdim#include "clang/Sema/AnalysisBasedWarnings.h" 16249423Sdim#include "clang/AST/DeclCXX.h" 17212904Sdim#include "clang/AST/DeclObjC.h" 18249423Sdim#include "clang/AST/EvaluatedExprVisitor.h" 19249423Sdim#include "clang/AST/ExprCXX.h" 20205408Srdivacky#include "clang/AST/ExprObjC.h" 21249423Sdim#include "clang/AST/ParentMap.h" 22249423Sdim#include "clang/AST/RecursiveASTVisitor.h" 23249423Sdim#include "clang/AST/StmtCXX.h" 24205408Srdivacky#include "clang/AST/StmtObjC.h" 25226633Sdim#include "clang/AST/StmtVisitor.h" 26249423Sdim#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" 27261991Sdim#include "clang/Analysis/Analyses/Consumed.h" 28249423Sdim#include "clang/Analysis/Analyses/ReachableCode.h" 29249423Sdim#include "clang/Analysis/Analyses/ThreadSafety.h" 30249423Sdim#include "clang/Analysis/Analyses/UninitializedValues.h" 31327952Sdim#include "clang/Analysis/AnalysisDeclContext.h" 32205408Srdivacky#include "clang/Analysis/CFG.h" 33219077Sdim#include "clang/Analysis/CFGStmtMap.h" 34249423Sdim#include "clang/Basic/SourceLocation.h" 35249423Sdim#include "clang/Basic/SourceManager.h" 36249423Sdim#include "clang/Lex/Preprocessor.h" 37249423Sdim#include "clang/Sema/ScopeInfo.h" 38249423Sdim#include "clang/Sema/SemaInternal.h" 39205408Srdivacky#include "llvm/ADT/BitVector.h" 40249423Sdim#include "llvm/ADT/MapVector.h" 41243830Sdim#include "llvm/ADT/SmallString.h" 42226633Sdim#include "llvm/ADT/SmallVector.h" 43226633Sdim#include "llvm/ADT/StringRef.h" 44205408Srdivacky#include "llvm/Support/Casting.h" 45226633Sdim#include <algorithm> 46249423Sdim#include <deque> 47239462Sdim#include <iterator> 48205408Srdivacky 49205408Srdivackyusing namespace clang; 50205408Srdivacky 51205408Srdivacky//===----------------------------------------------------------------------===// 52205408Srdivacky// Unreachable code analysis. 53205408Srdivacky//===----------------------------------------------------------------------===// 54205408Srdivacky 55205408Srdivackynamespace { 56205408Srdivacky class UnreachableCodeHandler : public reachable_code::Callback { 57205408Srdivacky Sema &S; 58314564Sdim SourceRange PreviousSilenceableCondVal; 59314564Sdim 60205408Srdivacky public: 61205408Srdivacky UnreachableCodeHandler(Sema &s) : S(s) {} 62205408Srdivacky 63276479Sdim void HandleUnreachable(reachable_code::UnreachableKind UK, 64276479Sdim SourceLocation L, 65276479Sdim SourceRange SilenceableCondVal, 66276479Sdim SourceRange R1, 67276479Sdim SourceRange R2) override { 68314564Sdim // Avoid reporting multiple unreachable code diagnostics that are 69314564Sdim // triggered by the same conditional value. 70314564Sdim if (PreviousSilenceableCondVal.isValid() && 71314564Sdim SilenceableCondVal.isValid() && 72314564Sdim PreviousSilenceableCondVal == SilenceableCondVal) 73314564Sdim return; 74314564Sdim PreviousSilenceableCondVal = SilenceableCondVal; 75314564Sdim 76276479Sdim unsigned diag = diag::warn_unreachable; 77276479Sdim switch (UK) { 78276479Sdim case reachable_code::UK_Break: 79276479Sdim diag = diag::warn_unreachable_break; 80276479Sdim break; 81276479Sdim case reachable_code::UK_Return: 82276479Sdim diag = diag::warn_unreachable_return; 83276479Sdim break; 84276479Sdim case reachable_code::UK_Loop_Increment: 85276479Sdim diag = diag::warn_unreachable_loop_increment; 86276479Sdim break; 87276479Sdim case reachable_code::UK_Other: 88276479Sdim break; 89276479Sdim } 90276479Sdim 91276479Sdim S.Diag(L, diag) << R1 << R2; 92341825Sdim 93276479Sdim SourceLocation Open = SilenceableCondVal.getBegin(); 94276479Sdim if (Open.isValid()) { 95276479Sdim SourceLocation Close = SilenceableCondVal.getEnd(); 96276479Sdim Close = S.getLocForEndOfToken(Close); 97276479Sdim if (Close.isValid()) { 98276479Sdim S.Diag(Open, diag::note_unreachable_silence) 99276479Sdim << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (") 100276479Sdim << FixItHint::CreateInsertion(Close, ")"); 101276479Sdim } 102276479Sdim } 103205408Srdivacky } 104205408Srdivacky }; 105296417Sdim} // anonymous namespace 106205408Srdivacky 107205408Srdivacky/// CheckUnreachable - Check for unreachable code. 108234353Sdimstatic void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) { 109276479Sdim // As a heuristic prune all diagnostics not in the main file. Currently 110276479Sdim // the majority of warnings in headers are false positives. These 111276479Sdim // are largely caused by configuration state, e.g. preprocessor 112276479Sdim // defined code, etc. 113276479Sdim // 114276479Sdim // Note that this is also a performance optimization. Analyzing 115276479Sdim // headers many times can be expensive. 116344779Sdim if (!S.getSourceManager().isInMainFile(AC.getDecl()->getBeginLoc())) 117276479Sdim return; 118276479Sdim 119205408Srdivacky UnreachableCodeHandler UC(S); 120276479Sdim reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC); 121205408Srdivacky} 122205408Srdivacky 123288943Sdimnamespace { 124341825Sdim/// Warn on logical operator errors in CFGBuilder 125276479Sdimclass LogicalErrorHandler : public CFGCallback { 126276479Sdim Sema &S; 127276479Sdim 128276479Sdimpublic: 129276479Sdim LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {} 130276479Sdim 131276479Sdim static bool HasMacroID(const Expr *E) { 132276479Sdim if (E->getExprLoc().isMacroID()) 133276479Sdim return true; 134276479Sdim 135276479Sdim // Recurse to children. 136288943Sdim for (const Stmt *SubStmt : E->children()) 137288943Sdim if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt)) 138288943Sdim if (HasMacroID(SubExpr)) 139288943Sdim return true; 140276479Sdim 141276479Sdim return false; 142276479Sdim } 143276479Sdim 144288943Sdim void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override { 145276479Sdim if (HasMacroID(B)) 146276479Sdim return; 147276479Sdim 148276479Sdim SourceRange DiagRange = B->getSourceRange(); 149276479Sdim S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison) 150276479Sdim << DiagRange << isAlwaysTrue; 151276479Sdim } 152276479Sdim 153288943Sdim void compareBitwiseEquality(const BinaryOperator *B, 154288943Sdim bool isAlwaysTrue) override { 155276479Sdim if (HasMacroID(B)) 156276479Sdim return; 157276479Sdim 158276479Sdim SourceRange DiagRange = B->getSourceRange(); 159276479Sdim S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always) 160276479Sdim << DiagRange << isAlwaysTrue; 161276479Sdim } 162360784Sdim 163360784Sdim void compareBitwiseOr(const BinaryOperator *B) override { 164360784Sdim if (HasMacroID(B)) 165360784Sdim return; 166360784Sdim 167360784Sdim SourceRange DiagRange = B->getSourceRange(); 168360784Sdim S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange; 169360784Sdim } 170360784Sdim 171360784Sdim static bool hasActiveDiagnostics(DiagnosticsEngine &Diags, 172360784Sdim SourceLocation Loc) { 173360784Sdim return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) || 174360784Sdim !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc); 175360784Sdim } 176276479Sdim}; 177296417Sdim} // anonymous namespace 178276479Sdim 179205408Srdivacky//===----------------------------------------------------------------------===// 180276479Sdim// Check for infinite self-recursion in functions 181276479Sdim//===----------------------------------------------------------------------===// 182276479Sdim 183296417Sdim// Returns true if the function is called anywhere within the CFGBlock. 184296417Sdim// For member functions, the additional condition of being call from the 185296417Sdim// this pointer is required. 186296417Sdimstatic bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { 187296417Sdim // Process all the Stmt's in this block to find any calls to FD. 188296417Sdim for (const auto &B : Block) { 189296417Sdim if (B.getKind() != CFGElement::Statement) 190296417Sdim continue; 191296417Sdim 192296417Sdim const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt()); 193296417Sdim if (!CE || !CE->getCalleeDecl() || 194296417Sdim CE->getCalleeDecl()->getCanonicalDecl() != FD) 195296417Sdim continue; 196296417Sdim 197296417Sdim // Skip function calls which are qualified with a templated class. 198296417Sdim if (const DeclRefExpr *DRE = 199296417Sdim dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts())) { 200296417Sdim if (NestedNameSpecifier *NNS = DRE->getQualifier()) { 201296417Sdim if (NNS->getKind() == NestedNameSpecifier::TypeSpec && 202296417Sdim isa<TemplateSpecializationType>(NNS->getAsType())) { 203296417Sdim continue; 204296417Sdim } 205296417Sdim } 206296417Sdim } 207296417Sdim 208296417Sdim const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE); 209296417Sdim if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) || 210296417Sdim !MCE->getMethodDecl()->isVirtual()) 211296417Sdim return true; 212296417Sdim } 213296417Sdim return false; 214296417Sdim} 215296417Sdim 216341825Sdim// Returns true if every path from the entry block passes through a call to FD. 217296417Sdimstatic bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { 218341825Sdim llvm::SmallPtrSet<CFGBlock *, 16> Visited; 219341825Sdim llvm::SmallVector<CFGBlock *, 16> WorkList; 220341825Sdim // Keep track of whether we found at least one recursive path. 221341825Sdim bool foundRecursion = false; 222276479Sdim 223296417Sdim const unsigned ExitID = cfg->getExit().getBlockID(); 224276479Sdim 225341825Sdim // Seed the work list with the entry block. 226341825Sdim WorkList.push_back(&cfg->getEntry()); 227276479Sdim 228341825Sdim while (!WorkList.empty()) { 229341825Sdim CFGBlock *Block = WorkList.pop_back_val(); 230276479Sdim 231341825Sdim for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) { 232341825Sdim if (CFGBlock *SuccBlock = *I) { 233341825Sdim if (!Visited.insert(SuccBlock).second) 234341825Sdim continue; 235276479Sdim 236341825Sdim // Found a path to the exit node without a recursive call. 237341825Sdim if (ExitID == SuccBlock->getBlockID()) 238341825Sdim return false; 239276479Sdim 240341825Sdim // If the successor block contains a recursive call, end analysis there. 241341825Sdim if (hasRecursiveCallInPath(FD, *SuccBlock)) { 242341825Sdim foundRecursion = true; 243341825Sdim continue; 244341825Sdim } 245276479Sdim 246341825Sdim WorkList.push_back(SuccBlock); 247341825Sdim } 248296417Sdim } 249276479Sdim } 250341825Sdim return foundRecursion; 251276479Sdim} 252276479Sdim 253276479Sdimstatic void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, 254296417Sdim const Stmt *Body, AnalysisDeclContext &AC) { 255276479Sdim FD = FD->getCanonicalDecl(); 256276479Sdim 257276479Sdim // Only run on non-templated functions and non-templated members of 258276479Sdim // templated classes. 259276479Sdim if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate && 260276479Sdim FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization) 261276479Sdim return; 262276479Sdim 263276479Sdim CFG *cfg = AC.getCFG(); 264276479Sdim if (!cfg) return; 265276479Sdim 266353358Sdim // If the exit block is unreachable, skip processing the function. 267353358Sdim if (cfg->getExit().pred_empty()) 268353358Sdim return; 269353358Sdim 270296417Sdim // Emit diagnostic if a recursive function call is detected for all paths. 271296417Sdim if (checkForRecursiveFunctionCall(FD, cfg)) 272344779Sdim S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function); 273276479Sdim} 274276479Sdim 275276479Sdim//===----------------------------------------------------------------------===// 276321369Sdim// Check for throw in a non-throwing function. 277321369Sdim//===----------------------------------------------------------------------===// 278321369Sdim 279341825Sdim/// Determine whether an exception thrown by E, unwinding from ThrowBlock, 280341825Sdim/// can reach ExitBlock. 281341825Sdimstatic bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, 282341825Sdim CFG *Body) { 283341825Sdim SmallVector<CFGBlock *, 16> Stack; 284341825Sdim llvm::BitVector Queued(Body->getNumBlockIDs()); 285321369Sdim 286341825Sdim Stack.push_back(&ThrowBlock); 287341825Sdim Queued[ThrowBlock.getBlockID()] = true; 288321369Sdim 289341825Sdim while (!Stack.empty()) { 290341825Sdim CFGBlock &UnwindBlock = *Stack.back(); 291341825Sdim Stack.pop_back(); 292321369Sdim 293341825Sdim for (auto &Succ : UnwindBlock.succs()) { 294341825Sdim if (!Succ.isReachable() || Queued[Succ->getBlockID()]) 295321369Sdim continue; 296341825Sdim 297341825Sdim if (Succ->getBlockID() == Body->getExit().getBlockID()) 298341825Sdim return true; 299341825Sdim 300341825Sdim if (auto *Catch = 301341825Sdim dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) { 302341825Sdim QualType Caught = Catch->getCaughtType(); 303341825Sdim if (Caught.isNull() || // catch (...) catches everything 304341825Sdim !E->getSubExpr() || // throw; is considered cuaght by any handler 305341825Sdim S.handlerCanCatch(Caught, E->getSubExpr()->getType())) 306341825Sdim // Exception doesn't escape via this path. 307341825Sdim break; 308341825Sdim } else { 309341825Sdim Stack.push_back(Succ); 310341825Sdim Queued[Succ->getBlockID()] = true; 311341825Sdim } 312321369Sdim } 313321369Sdim } 314341825Sdim 315321369Sdim return false; 316321369Sdim} 317321369Sdim 318341825Sdimstatic void visitReachableThrows( 319341825Sdim CFG *BodyCFG, 320341825Sdim llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) { 321341825Sdim llvm::BitVector Reachable(BodyCFG->getNumBlockIDs()); 322341825Sdim clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable); 323341825Sdim for (CFGBlock *B : *BodyCFG) { 324341825Sdim if (!Reachable[B->getBlockID()]) 325341825Sdim continue; 326341825Sdim for (CFGElement &E : *B) { 327341825Sdim Optional<CFGStmt> S = E.getAs<CFGStmt>(); 328341825Sdim if (!S) 329321369Sdim continue; 330341825Sdim if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) 331341825Sdim Visit(Throw, *B); 332321369Sdim } 333321369Sdim } 334321369Sdim} 335321369Sdim 336321369Sdimstatic void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, 337321369Sdim const FunctionDecl *FD) { 338321369Sdim if (!S.getSourceManager().isInSystemHeader(OpLoc) && 339321369Sdim FD->getTypeSourceInfo()) { 340321369Sdim S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; 341321369Sdim if (S.getLangOpts().CPlusPlus11 && 342321369Sdim (isa<CXXDestructorDecl>(FD) || 343321369Sdim FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || 344321369Sdim FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { 345321369Sdim if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> 346321369Sdim getAs<FunctionProtoType>()) 347321369Sdim S.Diag(FD->getLocation(), diag::note_throw_in_dtor) 348321369Sdim << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() 349321369Sdim << FD->getExceptionSpecSourceRange(); 350341825Sdim } else 351321369Sdim S.Diag(FD->getLocation(), diag::note_throw_in_function) 352321369Sdim << FD->getExceptionSpecSourceRange(); 353321369Sdim } 354321369Sdim} 355321369Sdim 356321369Sdimstatic void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, 357321369Sdim AnalysisDeclContext &AC) { 358321369Sdim CFG *BodyCFG = AC.getCFG(); 359321369Sdim if (!BodyCFG) 360321369Sdim return; 361321369Sdim if (BodyCFG->getExit().pred_empty()) 362321369Sdim return; 363341825Sdim visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { 364341825Sdim if (throwEscapes(S, Throw, Block, BodyCFG)) 365341825Sdim EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); 366341825Sdim }); 367321369Sdim} 368321369Sdim 369321369Sdimstatic bool isNoexcept(const FunctionDecl *FD) { 370321369Sdim const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); 371341825Sdim if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>()) 372321369Sdim return true; 373321369Sdim return false; 374321369Sdim} 375321369Sdim 376321369Sdim//===----------------------------------------------------------------------===// 377205408Srdivacky// Check for missing return value. 378205408Srdivacky//===----------------------------------------------------------------------===// 379205408Srdivacky 380208600Srdivackyenum ControlFlowKind { 381208600Srdivacky UnknownFallThrough, 382208600Srdivacky NeverFallThrough, 383208600Srdivacky MaybeFallThrough, 384208600Srdivacky AlwaysFallThrough, 385208600Srdivacky NeverFallThroughOrReturn 386208600Srdivacky}; 387205408Srdivacky 388205408Srdivacky/// CheckFallThrough - Check that we don't fall off the end of a 389205408Srdivacky/// Statement that should return a value. 390205408Srdivacky/// 391205408Srdivacky/// \returns AlwaysFallThrough iff we always fall off the end of the statement, 392205408Srdivacky/// MaybeFallThrough iff we might or might not fall off the end, 393205408Srdivacky/// NeverFallThroughOrReturn iff we never fall off the end of the statement or 394205408Srdivacky/// return. We assume NeverFallThrough iff we never fall off the end of the 395205408Srdivacky/// statement but we may return. We assume that functions not marked noreturn 396205408Srdivacky/// will return. 397234353Sdimstatic ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { 398205408Srdivacky CFG *cfg = AC.getCFG(); 399276479Sdim if (!cfg) return UnknownFallThrough; 400205408Srdivacky 401205408Srdivacky // The CFG leaves in dead things, and we don't want the dead code paths to 402205408Srdivacky // confuse us, so we mark all live things first. 403205408Srdivacky llvm::BitVector live(cfg->getNumBlockIDs()); 404226633Sdim unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), 405205408Srdivacky live); 406205408Srdivacky 407205408Srdivacky bool AddEHEdges = AC.getAddEHEdges(); 408205408Srdivacky if (!AddEHEdges && count != cfg->getNumBlockIDs()) 409205408Srdivacky // When there are things remaining dead, and we didn't add EH edges 410205408Srdivacky // from CallExprs to the catch clauses, we have to go back and 411205408Srdivacky // mark them as live. 412276479Sdim for (const auto *B : *cfg) { 413276479Sdim if (!live[B->getBlockID()]) { 414276479Sdim if (B->pred_begin() == B->pred_end()) { 415353358Sdim const Stmt *Term = B->getTerminatorStmt(); 416353358Sdim if (Term && isa<CXXTryStmt>(Term)) 417205408Srdivacky // When not adding EH edges from calls, catch clauses 418205408Srdivacky // can otherwise seem dead. Avoid noting them as dead. 419276479Sdim count += reachable_code::ScanReachableFromBlock(B, live); 420205408Srdivacky continue; 421205408Srdivacky } 422205408Srdivacky } 423205408Srdivacky } 424205408Srdivacky 425205408Srdivacky // Now we know what is live, we check the live precessors of the exit block 426205408Srdivacky // and look for fall through paths, being careful to ignore normal returns, 427205408Srdivacky // and exceptional paths. 428205408Srdivacky bool HasLiveReturn = false; 429205408Srdivacky bool HasFakeEdge = false; 430205408Srdivacky bool HasPlainEdge = false; 431205408Srdivacky bool HasAbnormalEdge = false; 432218893Sdim 433218893Sdim // Ignore default cases that aren't likely to be reachable because all 434218893Sdim // enums in a switch(X) have explicit case statements. 435218893Sdim CFGBlock::FilterOptions FO; 436218893Sdim FO.IgnoreDefaultsWithCoveredEnums = 1; 437218893Sdim 438341825Sdim for (CFGBlock::filtered_pred_iterator I = 439341825Sdim cfg->getExit().filtered_pred_start_end(FO); 440341825Sdim I.hasMore(); ++I) { 441341825Sdim const CFGBlock &B = **I; 442205408Srdivacky if (!live[B.getBlockID()]) 443205408Srdivacky continue; 444218893Sdim 445226633Sdim // Skip blocks which contain an element marked as no-return. They don't 446226633Sdim // represent actually viable edges into the exit block, so mark them as 447226633Sdim // abnormal. 448226633Sdim if (B.hasNoReturnElement()) { 449226633Sdim HasAbnormalEdge = true; 450226633Sdim continue; 451226633Sdim } 452226633Sdim 453218893Sdim // Destructors can appear after the 'return' in the CFG. This is 454218893Sdim // normal. We need to look pass the destructors for the return 455218893Sdim // statement (if it exists). 456218893Sdim CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); 457221345Sdim 458226633Sdim for ( ; ri != re ; ++ri) 459249423Sdim if (ri->getAs<CFGStmt>()) 460218893Sdim break; 461226633Sdim 462218893Sdim // No more CFGElements in the block? 463218893Sdim if (ri == re) { 464353358Sdim const Stmt *Term = B.getTerminatorStmt(); 465353358Sdim if (Term && isa<CXXTryStmt>(Term)) { 466205408Srdivacky HasAbnormalEdge = true; 467205408Srdivacky continue; 468205408Srdivacky } 469205408Srdivacky // A labeled empty statement, or the entry block... 470205408Srdivacky HasPlainEdge = true; 471205408Srdivacky continue; 472205408Srdivacky } 473218893Sdim 474249423Sdim CFGStmt CS = ri->castAs<CFGStmt>(); 475226633Sdim const Stmt *S = CS.getStmt(); 476314564Sdim if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) { 477205408Srdivacky HasLiveReturn = true; 478205408Srdivacky continue; 479205408Srdivacky } 480205408Srdivacky if (isa<ObjCAtThrowStmt>(S)) { 481205408Srdivacky HasFakeEdge = true; 482205408Srdivacky continue; 483205408Srdivacky } 484205408Srdivacky if (isa<CXXThrowExpr>(S)) { 485205408Srdivacky HasFakeEdge = true; 486205408Srdivacky continue; 487205408Srdivacky } 488239462Sdim if (isa<MSAsmStmt>(S)) { 489239462Sdim // TODO: Verify this is correct. 490239462Sdim HasFakeEdge = true; 491239462Sdim HasLiveReturn = true; 492239462Sdim continue; 493239462Sdim } 494205408Srdivacky if (isa<CXXTryStmt>(S)) { 495205408Srdivacky HasAbnormalEdge = true; 496205408Srdivacky continue; 497205408Srdivacky } 498226633Sdim if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) 499226633Sdim == B.succ_end()) { 500226633Sdim HasAbnormalEdge = true; 501226633Sdim continue; 502226633Sdim } 503205408Srdivacky 504226633Sdim HasPlainEdge = true; 505205408Srdivacky } 506205408Srdivacky if (!HasPlainEdge) { 507205408Srdivacky if (HasLiveReturn) 508205408Srdivacky return NeverFallThrough; 509205408Srdivacky return NeverFallThroughOrReturn; 510205408Srdivacky } 511205408Srdivacky if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) 512205408Srdivacky return MaybeFallThrough; 513205408Srdivacky // This says AlwaysFallThrough for calls to functions that are not marked 514205408Srdivacky // noreturn, that don't return. If people would like this warning to be more 515205408Srdivacky // accurate, such functions should be marked as noreturn. 516205408Srdivacky return AlwaysFallThrough; 517205408Srdivacky} 518205408Srdivacky 519212904Sdimnamespace { 520212904Sdim 521205408Srdivackystruct CheckFallThroughDiagnostics { 522205408Srdivacky unsigned diag_MaybeFallThrough_HasNoReturn; 523205408Srdivacky unsigned diag_MaybeFallThrough_ReturnsNonVoid; 524205408Srdivacky unsigned diag_AlwaysFallThrough_HasNoReturn; 525205408Srdivacky unsigned diag_AlwaysFallThrough_ReturnsNonVoid; 526205408Srdivacky unsigned diag_NeverFallThroughOrReturn; 527314564Sdim enum { Function, Block, Lambda, Coroutine } funMode; 528218893Sdim SourceLocation FuncLoc; 529206084Srdivacky 530207619Srdivacky static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { 531205408Srdivacky CheckFallThroughDiagnostics D; 532218893Sdim D.FuncLoc = Func->getLocation(); 533205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 534205408Srdivacky diag::warn_falloff_noreturn_function; 535205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 536205408Srdivacky diag::warn_maybe_falloff_nonvoid_function; 537205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 538205408Srdivacky diag::warn_falloff_noreturn_function; 539205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 540205408Srdivacky diag::warn_falloff_nonvoid_function; 541207619Srdivacky 542207619Srdivacky // Don't suggest that virtual functions be marked "noreturn", since they 543207619Srdivacky // might be overridden by non-noreturn functions. 544207619Srdivacky bool isVirtualMethod = false; 545207619Srdivacky if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) 546207619Srdivacky isVirtualMethod = Method->isVirtual(); 547341825Sdim 548226633Sdim // Don't suggest that template instantiations be marked "noreturn" 549226633Sdim bool isTemplateInstantiation = false; 550234353Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) 551234353Sdim isTemplateInstantiation = Function->isTemplateInstantiation(); 552341825Sdim 553226633Sdim if (!isVirtualMethod && !isTemplateInstantiation) 554207619Srdivacky D.diag_NeverFallThroughOrReturn = 555207619Srdivacky diag::warn_suggest_noreturn_function; 556207619Srdivacky else 557207619Srdivacky D.diag_NeverFallThroughOrReturn = 0; 558341825Sdim 559234353Sdim D.funMode = Function; 560205408Srdivacky return D; 561205408Srdivacky } 562206084Srdivacky 563314564Sdim static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) { 564314564Sdim CheckFallThroughDiagnostics D; 565314564Sdim D.FuncLoc = Func->getLocation(); 566314564Sdim D.diag_MaybeFallThrough_HasNoReturn = 0; 567314564Sdim D.diag_MaybeFallThrough_ReturnsNonVoid = 568314564Sdim diag::warn_maybe_falloff_nonvoid_coroutine; 569314564Sdim D.diag_AlwaysFallThrough_HasNoReturn = 0; 570314564Sdim D.diag_AlwaysFallThrough_ReturnsNonVoid = 571314564Sdim diag::warn_falloff_nonvoid_coroutine; 572314564Sdim D.funMode = Coroutine; 573314564Sdim return D; 574314564Sdim } 575314564Sdim 576205408Srdivacky static CheckFallThroughDiagnostics MakeForBlock() { 577205408Srdivacky CheckFallThroughDiagnostics D; 578205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 579205408Srdivacky diag::err_noreturn_block_has_return_expr; 580205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 581205408Srdivacky diag::err_maybe_falloff_nonvoid_block; 582205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 583205408Srdivacky diag::err_noreturn_block_has_return_expr; 584205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 585205408Srdivacky diag::err_falloff_nonvoid_block; 586276479Sdim D.diag_NeverFallThroughOrReturn = 0; 587234353Sdim D.funMode = Block; 588205408Srdivacky return D; 589205408Srdivacky } 590206084Srdivacky 591234353Sdim static CheckFallThroughDiagnostics MakeForLambda() { 592234353Sdim CheckFallThroughDiagnostics D; 593234353Sdim D.diag_MaybeFallThrough_HasNoReturn = 594234353Sdim diag::err_noreturn_lambda_has_return_expr; 595234353Sdim D.diag_MaybeFallThrough_ReturnsNonVoid = 596234353Sdim diag::warn_maybe_falloff_nonvoid_lambda; 597234353Sdim D.diag_AlwaysFallThrough_HasNoReturn = 598234353Sdim diag::err_noreturn_lambda_has_return_expr; 599234353Sdim D.diag_AlwaysFallThrough_ReturnsNonVoid = 600234353Sdim diag::warn_falloff_nonvoid_lambda; 601234353Sdim D.diag_NeverFallThroughOrReturn = 0; 602234353Sdim D.funMode = Lambda; 603234353Sdim return D; 604234353Sdim } 605234353Sdim 606226633Sdim bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, 607205408Srdivacky bool HasNoReturn) const { 608234353Sdim if (funMode == Function) { 609218893Sdim return (ReturnsVoid || 610276479Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, 611276479Sdim FuncLoc)) && 612276479Sdim (!HasNoReturn || 613276479Sdim D.isIgnored(diag::warn_noreturn_function_has_return_expr, 614276479Sdim FuncLoc)) && 615276479Sdim (!ReturnsVoid || 616276479Sdim D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc)); 617205408Srdivacky } 618314564Sdim if (funMode == Coroutine) { 619314564Sdim return (ReturnsVoid || 620314564Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) || 621314564Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine, 622314564Sdim FuncLoc)) && 623314564Sdim (!HasNoReturn); 624314564Sdim } 625234353Sdim // For blocks / lambdas. 626276479Sdim return ReturnsVoid && !HasNoReturn; 627205408Srdivacky } 628205408Srdivacky}; 629205408Srdivacky 630296417Sdim} // anonymous namespace 631212904Sdim 632341825Sdim/// CheckFallThroughForBody - Check that we don't fall off the end of a 633205408Srdivacky/// function that should return a value. Check that we don't fall off the end 634205408Srdivacky/// of a noreturn function. We assume that functions and blocks not marked 635205408Srdivacky/// noreturn will return. 636205408Srdivackystatic void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, 637353358Sdim QualType BlockType, 638341825Sdim const CheckFallThroughDiagnostics &CD, 639341825Sdim AnalysisDeclContext &AC, 640341825Sdim sema::FunctionScopeInfo *FSI) { 641205408Srdivacky 642205408Srdivacky bool ReturnsVoid = false; 643205408Srdivacky bool HasNoReturn = false; 644341825Sdim bool IsCoroutine = FSI->isCoroutine(); 645205408Srdivacky 646314564Sdim if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 647314564Sdim if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) 648314564Sdim ReturnsVoid = CBody->getFallthroughHandler() != nullptr; 649314564Sdim else 650314564Sdim ReturnsVoid = FD->getReturnType()->isVoidType(); 651249423Sdim HasNoReturn = FD->isNoReturn(); 652205408Srdivacky } 653314564Sdim else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 654276479Sdim ReturnsVoid = MD->getReturnType()->isVoidType(); 655205408Srdivacky HasNoReturn = MD->hasAttr<NoReturnAttr>(); 656205408Srdivacky } 657205408Srdivacky else if (isa<BlockDecl>(D)) { 658206084Srdivacky if (const FunctionType *FT = 659353358Sdim BlockType->getPointeeType()->getAs<FunctionType>()) { 660276479Sdim if (FT->getReturnType()->isVoidType()) 661205408Srdivacky ReturnsVoid = true; 662205408Srdivacky if (FT->getNoReturnAttr()) 663205408Srdivacky HasNoReturn = true; 664205408Srdivacky } 665205408Srdivacky } 666205408Srdivacky 667226633Sdim DiagnosticsEngine &Diags = S.getDiagnostics(); 668205408Srdivacky 669205408Srdivacky // Short circuit for compilation speed. 670205408Srdivacky if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) 671205408Srdivacky return; 672344779Sdim SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc(); 673321369Sdim auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { 674321369Sdim if (IsCoroutine) 675341825Sdim S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); 676321369Sdim else 677321369Sdim S.Diag(Loc, DiagID); 678321369Sdim }; 679341825Sdim 680341825Sdim // cpu_dispatch functions permit empty function bodies for ICC compatibility. 681341825Sdim if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion()) 682341825Sdim return; 683341825Sdim 684280031Sdim // Either in a function body compound statement, or a function-try-block. 685280031Sdim switch (CheckFallThrough(AC)) { 686280031Sdim case UnknownFallThrough: 687280031Sdim break; 688208600Srdivacky 689280031Sdim case MaybeFallThrough: 690280031Sdim if (HasNoReturn) 691321369Sdim EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); 692280031Sdim else if (!ReturnsVoid) 693321369Sdim EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); 694280031Sdim break; 695280031Sdim case AlwaysFallThrough: 696280031Sdim if (HasNoReturn) 697321369Sdim EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); 698280031Sdim else if (!ReturnsVoid) 699321369Sdim EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); 700280031Sdim break; 701280031Sdim case NeverFallThroughOrReturn: 702280031Sdim if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { 703280031Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 704280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; 705280031Sdim } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 706280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; 707280031Sdim } else { 708280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); 709226633Sdim } 710280031Sdim } 711280031Sdim break; 712280031Sdim case NeverFallThrough: 713280031Sdim break; 714205408Srdivacky } 715205408Srdivacky} 716205408Srdivacky 717205408Srdivacky//===----------------------------------------------------------------------===// 718218893Sdim// -Wuninitialized 719218893Sdim//===----------------------------------------------------------------------===// 720218893Sdim 721218893Sdimnamespace { 722221345Sdim/// ContainsReference - A visitor class to search for references to 723221345Sdim/// a particular declaration (the needle) within any evaluated component of an 724221345Sdim/// expression (recursively). 725288943Sdimclass ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> { 726221345Sdim bool FoundReference; 727221345Sdim const DeclRefExpr *Needle; 728221345Sdim 729221345Sdimpublic: 730288943Sdim typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited; 731288943Sdim 732221345Sdim ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) 733288943Sdim : Inherited(Context), FoundReference(false), Needle(Needle) {} 734221345Sdim 735288943Sdim void VisitExpr(const Expr *E) { 736221345Sdim // Stop evaluating if we already have a reference. 737221345Sdim if (FoundReference) 738221345Sdim return; 739221345Sdim 740288943Sdim Inherited::VisitExpr(E); 741221345Sdim } 742221345Sdim 743288943Sdim void VisitDeclRefExpr(const DeclRefExpr *E) { 744221345Sdim if (E == Needle) 745221345Sdim FoundReference = true; 746221345Sdim else 747288943Sdim Inherited::VisitDeclRefExpr(E); 748221345Sdim } 749221345Sdim 750221345Sdim bool doesContainReference() const { return FoundReference; } 751221345Sdim}; 752296417Sdim} // anonymous namespace 753221345Sdim 754226633Sdimstatic bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { 755234353Sdim QualType VariableTy = VD->getType().getCanonicalType(); 756234353Sdim if (VariableTy->isBlockPointerType() && 757234353Sdim !VD->hasAttr<BlocksAttr>()) { 758276479Sdim S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) 759276479Sdim << VD->getDeclName() 760276479Sdim << FixItHint::CreateInsertion(VD->getLocation(), "__block "); 761234353Sdim return true; 762234353Sdim } 763261991Sdim 764226633Sdim // Don't issue a fixit if there is already an initializer. 765226633Sdim if (VD->getInit()) 766226633Sdim return false; 767239462Sdim 768239462Sdim // Don't suggest a fixit inside macros. 769344779Sdim if (VD->getEndLoc().isMacroID()) 770239462Sdim return false; 771239462Sdim 772344779Sdim SourceLocation Loc = S.getLocForEndOfToken(VD->getEndLoc()); 773261991Sdim 774261991Sdim // Suggest possible initialization (if any). 775261991Sdim std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); 776261991Sdim if (Init.empty()) 777261991Sdim return false; 778261991Sdim 779234353Sdim S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() 780234353Sdim << FixItHint::CreateInsertion(Loc, Init); 781234353Sdim return true; 782226633Sdim} 783226633Sdim 784239462Sdim/// Create a fixit to remove an if-like statement, on the assumption that its 785239462Sdim/// condition is CondVal. 786239462Sdimstatic void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, 787239462Sdim const Stmt *Else, bool CondVal, 788239462Sdim FixItHint &Fixit1, FixItHint &Fixit2) { 789239462Sdim if (CondVal) { 790239462Sdim // If condition is always true, remove all but the 'then'. 791239462Sdim Fixit1 = FixItHint::CreateRemoval( 792344779Sdim CharSourceRange::getCharRange(If->getBeginLoc(), Then->getBeginLoc())); 793239462Sdim if (Else) { 794344779Sdim SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getEndLoc()); 795344779Sdim Fixit2 = 796344779Sdim FixItHint::CreateRemoval(SourceRange(ElseKwLoc, Else->getEndLoc())); 797239462Sdim } 798239462Sdim } else { 799239462Sdim // If condition is always false, remove all but the 'else'. 800239462Sdim if (Else) 801344779Sdim Fixit1 = FixItHint::CreateRemoval(CharSourceRange::getCharRange( 802344779Sdim If->getBeginLoc(), Else->getBeginLoc())); 803239462Sdim else 804239462Sdim Fixit1 = FixItHint::CreateRemoval(If->getSourceRange()); 805239462Sdim } 806239462Sdim} 807239462Sdim 808239462Sdim/// DiagUninitUse -- Helper function to produce a diagnostic for an 809239462Sdim/// uninitialized use of a variable. 810239462Sdimstatic void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, 811239462Sdim bool IsCapturedByBlock) { 812239462Sdim bool Diagnosed = false; 813239462Sdim 814261991Sdim switch (Use.getKind()) { 815261991Sdim case UninitUse::Always: 816344779Sdim S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_var) 817261991Sdim << VD->getDeclName() << IsCapturedByBlock 818261991Sdim << Use.getUser()->getSourceRange(); 819261991Sdim return; 820261991Sdim 821261991Sdim case UninitUse::AfterDecl: 822261991Sdim case UninitUse::AfterCall: 823261991Sdim S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var) 824261991Sdim << VD->getDeclName() << IsCapturedByBlock 825261991Sdim << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5) 826261991Sdim << const_cast<DeclContext*>(VD->getLexicalDeclContext()) 827261991Sdim << VD->getSourceRange(); 828344779Sdim S.Diag(Use.getUser()->getBeginLoc(), diag::note_uninit_var_use) 829344779Sdim << IsCapturedByBlock << Use.getUser()->getSourceRange(); 830261991Sdim return; 831261991Sdim 832261991Sdim case UninitUse::Maybe: 833261991Sdim case UninitUse::Sometimes: 834261991Sdim // Carry on to report sometimes-uninitialized branches, if possible, 835261991Sdim // or a 'may be used uninitialized' diagnostic otherwise. 836261991Sdim break; 837261991Sdim } 838261991Sdim 839239462Sdim // Diagnose each branch which leads to a sometimes-uninitialized use. 840239462Sdim for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end(); 841239462Sdim I != E; ++I) { 842239462Sdim assert(Use.getKind() == UninitUse::Sometimes); 843239462Sdim 844239462Sdim const Expr *User = Use.getUser(); 845239462Sdim const Stmt *Term = I->Terminator; 846239462Sdim 847239462Sdim // Information used when building the diagnostic. 848239462Sdim unsigned DiagKind; 849243830Sdim StringRef Str; 850239462Sdim SourceRange Range; 851239462Sdim 852249423Sdim // FixIts to suppress the diagnostic by removing the dead condition. 853239462Sdim // For all binary terminators, branch 0 is taken if the condition is true, 854239462Sdim // and branch 1 is taken if the condition is false. 855239462Sdim int RemoveDiagKind = -1; 856239462Sdim const char *FixitStr = 857239462Sdim S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false") 858239462Sdim : (I->Output ? "1" : "0"); 859239462Sdim FixItHint Fixit1, Fixit2; 860239462Sdim 861261991Sdim switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) { 862239462Sdim default: 863239462Sdim // Don't know how to report this. Just fall back to 'may be used 864261991Sdim // uninitialized'. FIXME: Can this happen? 865239462Sdim continue; 866239462Sdim 867239462Sdim // "condition is true / condition is false". 868239462Sdim case Stmt::IfStmtClass: { 869239462Sdim const IfStmt *IS = cast<IfStmt>(Term); 870239462Sdim DiagKind = 0; 871239462Sdim Str = "if"; 872239462Sdim Range = IS->getCond()->getSourceRange(); 873239462Sdim RemoveDiagKind = 0; 874239462Sdim CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), 875239462Sdim I->Output, Fixit1, Fixit2); 876239462Sdim break; 877239462Sdim } 878239462Sdim case Stmt::ConditionalOperatorClass: { 879239462Sdim const ConditionalOperator *CO = cast<ConditionalOperator>(Term); 880239462Sdim DiagKind = 0; 881239462Sdim Str = "?:"; 882239462Sdim Range = CO->getCond()->getSourceRange(); 883239462Sdim RemoveDiagKind = 0; 884239462Sdim CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), 885239462Sdim I->Output, Fixit1, Fixit2); 886239462Sdim break; 887239462Sdim } 888239462Sdim case Stmt::BinaryOperatorClass: { 889239462Sdim const BinaryOperator *BO = cast<BinaryOperator>(Term); 890239462Sdim if (!BO->isLogicalOp()) 891239462Sdim continue; 892239462Sdim DiagKind = 0; 893239462Sdim Str = BO->getOpcodeStr(); 894239462Sdim Range = BO->getLHS()->getSourceRange(); 895239462Sdim RemoveDiagKind = 0; 896239462Sdim if ((BO->getOpcode() == BO_LAnd && I->Output) || 897239462Sdim (BO->getOpcode() == BO_LOr && !I->Output)) 898239462Sdim // true && y -> y, false || y -> y. 899344779Sdim Fixit1 = FixItHint::CreateRemoval( 900344779Sdim SourceRange(BO->getBeginLoc(), BO->getOperatorLoc())); 901239462Sdim else 902239462Sdim // false && y -> false, true || y -> true. 903239462Sdim Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr); 904239462Sdim break; 905239462Sdim } 906239462Sdim 907239462Sdim // "loop is entered / loop is exited". 908239462Sdim case Stmt::WhileStmtClass: 909239462Sdim DiagKind = 1; 910239462Sdim Str = "while"; 911239462Sdim Range = cast<WhileStmt>(Term)->getCond()->getSourceRange(); 912239462Sdim RemoveDiagKind = 1; 913239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 914239462Sdim break; 915239462Sdim case Stmt::ForStmtClass: 916239462Sdim DiagKind = 1; 917239462Sdim Str = "for"; 918239462Sdim Range = cast<ForStmt>(Term)->getCond()->getSourceRange(); 919239462Sdim RemoveDiagKind = 1; 920239462Sdim if (I->Output) 921239462Sdim Fixit1 = FixItHint::CreateRemoval(Range); 922239462Sdim else 923239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 924239462Sdim break; 925261991Sdim case Stmt::CXXForRangeStmtClass: 926261991Sdim if (I->Output == 1) { 927261991Sdim // The use occurs if a range-based for loop's body never executes. 928261991Sdim // That may be impossible, and there's no syntactic fix for this, 929261991Sdim // so treat it as a 'may be uninitialized' case. 930261991Sdim continue; 931261991Sdim } 932261991Sdim DiagKind = 1; 933261991Sdim Str = "for"; 934261991Sdim Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange(); 935261991Sdim break; 936239462Sdim 937239462Sdim // "condition is true / loop is exited". 938239462Sdim case Stmt::DoStmtClass: 939239462Sdim DiagKind = 2; 940239462Sdim Str = "do"; 941239462Sdim Range = cast<DoStmt>(Term)->getCond()->getSourceRange(); 942239462Sdim RemoveDiagKind = 1; 943239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 944239462Sdim break; 945239462Sdim 946239462Sdim // "switch case is taken". 947239462Sdim case Stmt::CaseStmtClass: 948239462Sdim DiagKind = 3; 949239462Sdim Str = "case"; 950239462Sdim Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange(); 951239462Sdim break; 952239462Sdim case Stmt::DefaultStmtClass: 953239462Sdim DiagKind = 3; 954239462Sdim Str = "default"; 955239462Sdim Range = cast<DefaultStmt>(Term)->getDefaultLoc(); 956239462Sdim break; 957239462Sdim } 958239462Sdim 959239462Sdim S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var) 960239462Sdim << VD->getDeclName() << IsCapturedByBlock << DiagKind 961239462Sdim << Str << I->Output << Range; 962344779Sdim S.Diag(User->getBeginLoc(), diag::note_uninit_var_use) 963344779Sdim << IsCapturedByBlock << User->getSourceRange(); 964239462Sdim if (RemoveDiagKind != -1) 965239462Sdim S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond) 966239462Sdim << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2; 967239462Sdim 968239462Sdim Diagnosed = true; 969239462Sdim } 970239462Sdim 971239462Sdim if (!Diagnosed) 972344779Sdim S.Diag(Use.getUser()->getBeginLoc(), diag::warn_maybe_uninit_var) 973239462Sdim << VD->getDeclName() << IsCapturedByBlock 974239462Sdim << Use.getUser()->getSourceRange(); 975239462Sdim} 976239462Sdim 977221345Sdim/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an 978221345Sdim/// uninitialized variable. This manages the different forms of diagnostic 979221345Sdim/// emitted for particular types of uses. Returns true if the use was diagnosed 980239462Sdim/// as a warning. If a particular use is one we omit warnings for, returns 981221345Sdim/// false. 982221345Sdimstatic bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, 983239462Sdim const UninitUse &Use, 984226633Sdim bool alwaysReportSelfInit = false) { 985239462Sdim if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) { 986239462Sdim // Inspect the initializer of the variable declaration which is 987239462Sdim // being referenced prior to its initialization. We emit 988239462Sdim // specialized diagnostics for self-initialization, and we 989239462Sdim // specifically avoid warning about self references which take the 990239462Sdim // form of: 991239462Sdim // 992239462Sdim // int x = x; 993239462Sdim // 994239462Sdim // This is used to indicate to GCC that 'x' is intentionally left 995239462Sdim // uninitialized. Proven code paths which access 'x' in 996239462Sdim // an uninitialized state after this will still warn. 997239462Sdim if (const Expr *Initializer = VD->getInit()) { 998239462Sdim if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) 999239462Sdim return false; 1000221345Sdim 1001239462Sdim ContainsReference CR(S.Context, DRE); 1002288943Sdim CR.Visit(Initializer); 1003239462Sdim if (CR.doesContainReference()) { 1004344779Sdim S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init) 1005344779Sdim << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); 1006239462Sdim return true; 1007221345Sdim } 1008221345Sdim } 1009239462Sdim 1010239462Sdim DiagUninitUse(S, VD, Use, false); 1011221345Sdim } else { 1012239462Sdim const BlockExpr *BE = cast<BlockExpr>(Use.getUser()); 1013239462Sdim if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) 1014344779Sdim S.Diag(BE->getBeginLoc(), 1015239462Sdim diag::warn_uninit_byref_blockvar_captured_by_block) 1016353358Sdim << VD->getDeclName() 1017353358Sdim << VD->getType().getQualifiers().hasObjCLifetime(); 1018234353Sdim else 1019239462Sdim DiagUninitUse(S, VD, Use, true); 1020221345Sdim } 1021221345Sdim 1022221345Sdim // Report where the variable was declared when the use wasn't within 1023226633Sdim // the initializer of that declaration & we didn't already suggest 1024226633Sdim // an initialization fixit. 1025239462Sdim if (!SuggestInitializationFixit(S, VD)) 1026344779Sdim S.Diag(VD->getBeginLoc(), diag::note_var_declared_here) 1027344779Sdim << VD->getDeclName(); 1028221345Sdim 1029221345Sdim return true; 1030221345Sdim} 1031221345Sdim 1032239462Sdimnamespace { 1033239462Sdim class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> { 1034239462Sdim public: 1035239462Sdim FallthroughMapper(Sema &S) 1036239462Sdim : FoundSwitchStatements(false), 1037239462Sdim S(S) { 1038239462Sdim } 1039221345Sdim 1040239462Sdim bool foundSwitchStatements() const { return FoundSwitchStatements; } 1041239462Sdim 1042239462Sdim void markFallthroughVisited(const AttributedStmt *Stmt) { 1043239462Sdim bool Found = FallthroughStmts.erase(Stmt); 1044239462Sdim assert(Found); 1045239462Sdim (void)Found; 1046239462Sdim } 1047239462Sdim 1048239462Sdim typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts; 1049239462Sdim 1050239462Sdim const AttrStmts &getFallthroughStmts() const { 1051239462Sdim return FallthroughStmts; 1052239462Sdim } 1053239462Sdim 1054249423Sdim void fillReachableBlocks(CFG *Cfg) { 1055249423Sdim assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); 1056249423Sdim std::deque<const CFGBlock *> BlockQueue; 1057249423Sdim 1058249423Sdim ReachableBlocks.insert(&Cfg->getEntry()); 1059249423Sdim BlockQueue.push_back(&Cfg->getEntry()); 1060249423Sdim // Mark all case blocks reachable to avoid problems with switching on 1061249423Sdim // constants, covered enums, etc. 1062249423Sdim // These blocks can contain fall-through annotations, and we don't want to 1063249423Sdim // issue a warn_fallthrough_attr_unreachable for them. 1064276479Sdim for (const auto *B : *Cfg) { 1065249423Sdim const Stmt *L = B->getLabel(); 1066280031Sdim if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second) 1067249423Sdim BlockQueue.push_back(B); 1068249423Sdim } 1069249423Sdim 1070249423Sdim while (!BlockQueue.empty()) { 1071249423Sdim const CFGBlock *P = BlockQueue.front(); 1072249423Sdim BlockQueue.pop_front(); 1073249423Sdim for (CFGBlock::const_succ_iterator I = P->succ_begin(), 1074249423Sdim E = P->succ_end(); 1075249423Sdim I != E; ++I) { 1076280031Sdim if (*I && ReachableBlocks.insert(*I).second) 1077249423Sdim BlockQueue.push_back(*I); 1078249423Sdim } 1079249423Sdim } 1080249423Sdim } 1081249423Sdim 1082321369Sdim bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt, 1083321369Sdim bool IsTemplateInstantiation) { 1084249423Sdim assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); 1085249423Sdim 1086239462Sdim int UnannotatedCnt = 0; 1087239462Sdim AnnotatedCnt = 0; 1088239462Sdim 1089276479Sdim std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end()); 1090239462Sdim while (!BlockQueue.empty()) { 1091239462Sdim const CFGBlock *P = BlockQueue.front(); 1092239462Sdim BlockQueue.pop_front(); 1093276479Sdim if (!P) continue; 1094239462Sdim 1095353358Sdim const Stmt *Term = P->getTerminatorStmt(); 1096239462Sdim if (Term && isa<SwitchStmt>(Term)) 1097239462Sdim continue; // Switch statement, good. 1098239462Sdim 1099239462Sdim const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel()); 1100239462Sdim if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) 1101239462Sdim continue; // Previous case label has no statements, good. 1102239462Sdim 1103249423Sdim const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel()); 1104249423Sdim if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) 1105249423Sdim continue; // Case label is preceded with a normal label, good. 1106249423Sdim 1107249423Sdim if (!ReachableBlocks.count(P)) { 1108249423Sdim for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(), 1109249423Sdim ElemEnd = P->rend(); 1110249423Sdim ElemIt != ElemEnd; ++ElemIt) { 1111249423Sdim if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) { 1112239462Sdim if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { 1113321369Sdim // Don't issue a warning for an unreachable fallthrough 1114321369Sdim // attribute in template instantiations as it may not be 1115321369Sdim // unreachable in all instantiations of the template. 1116321369Sdim if (!IsTemplateInstantiation) 1117344779Sdim S.Diag(AS->getBeginLoc(), 1118321369Sdim diag::warn_fallthrough_attr_unreachable); 1119239462Sdim markFallthroughVisited(AS); 1120239462Sdim ++AnnotatedCnt; 1121249423Sdim break; 1122239462Sdim } 1123239462Sdim // Don't care about other unreachable statements. 1124239462Sdim } 1125239462Sdim } 1126239462Sdim // If there are no unreachable statements, this may be a special 1127239462Sdim // case in CFG: 1128239462Sdim // case X: { 1129239462Sdim // A a; // A has a destructor. 1130239462Sdim // break; 1131239462Sdim // } 1132239462Sdim // // <<<< This place is represented by a 'hanging' CFG block. 1133239462Sdim // case Y: 1134239462Sdim continue; 1135239462Sdim } 1136239462Sdim 1137239462Sdim const Stmt *LastStmt = getLastStmt(*P); 1138239462Sdim if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) { 1139239462Sdim markFallthroughVisited(AS); 1140239462Sdim ++AnnotatedCnt; 1141239462Sdim continue; // Fallthrough annotation, good. 1142239462Sdim } 1143239462Sdim 1144239462Sdim if (!LastStmt) { // This block contains no executable statements. 1145239462Sdim // Traverse its predecessors. 1146239462Sdim std::copy(P->pred_begin(), P->pred_end(), 1147239462Sdim std::back_inserter(BlockQueue)); 1148239462Sdim continue; 1149239462Sdim } 1150239462Sdim 1151239462Sdim ++UnannotatedCnt; 1152239462Sdim } 1153239462Sdim return !!UnannotatedCnt; 1154239462Sdim } 1155239462Sdim 1156239462Sdim // RecursiveASTVisitor setup. 1157239462Sdim bool shouldWalkTypesOfTypeLocs() const { return false; } 1158239462Sdim 1159239462Sdim bool VisitAttributedStmt(AttributedStmt *S) { 1160239462Sdim if (asFallThroughAttr(S)) 1161239462Sdim FallthroughStmts.insert(S); 1162239462Sdim return true; 1163239462Sdim } 1164239462Sdim 1165239462Sdim bool VisitSwitchStmt(SwitchStmt *S) { 1166239462Sdim FoundSwitchStatements = true; 1167239462Sdim return true; 1168239462Sdim } 1169239462Sdim 1170249423Sdim // We don't want to traverse local type declarations. We analyze their 1171249423Sdim // methods separately. 1172249423Sdim bool TraverseDecl(Decl *D) { return true; } 1173249423Sdim 1174276479Sdim // We analyze lambda bodies separately. Skip them here. 1175344779Sdim bool TraverseLambdaExpr(LambdaExpr *LE) { 1176344779Sdim // Traverse the captures, but not the body. 1177360784Sdim for (const auto C : zip(LE->captures(), LE->capture_inits())) 1178344779Sdim TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); 1179344779Sdim return true; 1180344779Sdim } 1181276479Sdim 1182239462Sdim private: 1183239462Sdim 1184239462Sdim static const AttributedStmt *asFallThroughAttr(const Stmt *S) { 1185239462Sdim if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) { 1186239462Sdim if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs())) 1187239462Sdim return AS; 1188239462Sdim } 1189276479Sdim return nullptr; 1190239462Sdim } 1191239462Sdim 1192239462Sdim static const Stmt *getLastStmt(const CFGBlock &B) { 1193353358Sdim if (const Stmt *Term = B.getTerminatorStmt()) 1194239462Sdim return Term; 1195239462Sdim for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(), 1196239462Sdim ElemEnd = B.rend(); 1197239462Sdim ElemIt != ElemEnd; ++ElemIt) { 1198249423Sdim if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) 1199239462Sdim return CS->getStmt(); 1200239462Sdim } 1201239462Sdim // Workaround to detect a statement thrown out by CFGBuilder: 1202239462Sdim // case X: {} case Y: 1203239462Sdim // case X: ; case Y: 1204239462Sdim if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel())) 1205239462Sdim if (!isa<SwitchCase>(SW->getSubStmt())) 1206239462Sdim return SW->getSubStmt(); 1207239462Sdim 1208276479Sdim return nullptr; 1209239462Sdim } 1210239462Sdim 1211239462Sdim bool FoundSwitchStatements; 1212239462Sdim AttrStmts FallthroughStmts; 1213239462Sdim Sema &S; 1214249423Sdim llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks; 1215239462Sdim }; 1216296417Sdim} // anonymous namespace 1217239462Sdim 1218309124Sdimstatic StringRef getFallthroughAttrSpelling(Preprocessor &PP, 1219309124Sdim SourceLocation Loc) { 1220309124Sdim TokenValue FallthroughTokens[] = { 1221309124Sdim tok::l_square, tok::l_square, 1222309124Sdim PP.getIdentifierInfo("fallthrough"), 1223309124Sdim tok::r_square, tok::r_square 1224309124Sdim }; 1225309124Sdim 1226309124Sdim TokenValue ClangFallthroughTokens[] = { 1227309124Sdim tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), 1228309124Sdim tok::coloncolon, PP.getIdentifierInfo("fallthrough"), 1229309124Sdim tok::r_square, tok::r_square 1230309124Sdim }; 1231309124Sdim 1232360784Sdim bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x; 1233309124Sdim 1234309124Sdim StringRef MacroName; 1235309124Sdim if (PreferClangAttr) 1236309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1237309124Sdim if (MacroName.empty()) 1238309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); 1239309124Sdim if (MacroName.empty() && !PreferClangAttr) 1240309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1241360784Sdim if (MacroName.empty()) { 1242360784Sdim if (!PreferClangAttr) 1243360784Sdim MacroName = "[[fallthrough]]"; 1244360784Sdim else if (PP.getLangOpts().CPlusPlus) 1245360784Sdim MacroName = "[[clang::fallthrough]]"; 1246360784Sdim else 1247360784Sdim MacroName = "__attribute__((fallthrough))"; 1248360784Sdim } 1249309124Sdim return MacroName; 1250309124Sdim} 1251309124Sdim 1252239462Sdimstatic void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, 1253239462Sdim bool PerFunction) { 1254239462Sdim FallthroughMapper FM(S); 1255239462Sdim FM.TraverseStmt(AC.getBody()); 1256239462Sdim 1257239462Sdim if (!FM.foundSwitchStatements()) 1258239462Sdim return; 1259239462Sdim 1260239462Sdim if (PerFunction && FM.getFallthroughStmts().empty()) 1261239462Sdim return; 1262239462Sdim 1263239462Sdim CFG *Cfg = AC.getCFG(); 1264239462Sdim 1265239462Sdim if (!Cfg) 1266239462Sdim return; 1267239462Sdim 1268249423Sdim FM.fillReachableBlocks(Cfg); 1269239462Sdim 1270296417Sdim for (const CFGBlock *B : llvm::reverse(*Cfg)) { 1271249423Sdim const Stmt *Label = B->getLabel(); 1272239462Sdim 1273239462Sdim if (!Label || !isa<SwitchCase>(Label)) 1274239462Sdim continue; 1275239462Sdim 1276249423Sdim int AnnotatedCnt; 1277249423Sdim 1278321369Sdim bool IsTemplateInstantiation = false; 1279321369Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl())) 1280321369Sdim IsTemplateInstantiation = Function->isTemplateInstantiation(); 1281321369Sdim if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt, 1282321369Sdim IsTemplateInstantiation)) 1283239462Sdim continue; 1284239462Sdim 1285344779Sdim S.Diag(Label->getBeginLoc(), 1286344779Sdim PerFunction ? diag::warn_unannotated_fallthrough_per_function 1287344779Sdim : diag::warn_unannotated_fallthrough); 1288239462Sdim 1289239462Sdim if (!AnnotatedCnt) { 1290344779Sdim SourceLocation L = Label->getBeginLoc(); 1291239462Sdim if (L.isMacroID()) 1292239462Sdim continue; 1293360784Sdim 1294360784Sdim const Stmt *Term = B->getTerminatorStmt(); 1295360784Sdim // Skip empty cases. 1296360784Sdim while (B->empty() && !Term && B->succ_size() == 1) { 1297360784Sdim B = *B->succ_begin(); 1298360784Sdim Term = B->getTerminatorStmt(); 1299239462Sdim } 1300360784Sdim if (!(B->empty() && Term && isa<BreakStmt>(Term))) { 1301360784Sdim Preprocessor &PP = S.getPreprocessor(); 1302360784Sdim StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); 1303360784Sdim SmallString<64> TextToInsert(AnnotationSpelling); 1304360784Sdim TextToInsert += "; "; 1305360784Sdim S.Diag(L, diag::note_insert_fallthrough_fixit) 1306360784Sdim << AnnotationSpelling 1307360784Sdim << FixItHint::CreateInsertion(L, TextToInsert); 1308360784Sdim } 1309360784Sdim S.Diag(L, diag::note_insert_break_fixit) 1310360784Sdim << FixItHint::CreateInsertion(L, "break; "); 1311239462Sdim } 1312239462Sdim } 1313239462Sdim 1314276479Sdim for (const auto *F : FM.getFallthroughStmts()) 1315344779Sdim S.Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement); 1316239462Sdim} 1317239462Sdim 1318243830Sdimstatic bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, 1319243830Sdim const Stmt *S) { 1320243830Sdim assert(S); 1321243830Sdim 1322243830Sdim do { 1323243830Sdim switch (S->getStmtClass()) { 1324243830Sdim case Stmt::ForStmtClass: 1325243830Sdim case Stmt::WhileStmtClass: 1326243830Sdim case Stmt::CXXForRangeStmtClass: 1327243830Sdim case Stmt::ObjCForCollectionStmtClass: 1328243830Sdim return true; 1329243830Sdim case Stmt::DoStmtClass: { 1330344779Sdim Expr::EvalResult Result; 1331344779Sdim if (!cast<DoStmt>(S)->getCond()->EvaluateAsInt(Result, Ctx)) 1332243830Sdim return true; 1333344779Sdim return Result.Val.getInt().getBoolValue(); 1334243830Sdim } 1335243830Sdim default: 1336243830Sdim break; 1337243830Sdim } 1338243830Sdim } while ((S = PM.getParent(S))); 1339243830Sdim 1340243830Sdim return false; 1341243830Sdim} 1342243830Sdim 1343243830Sdimstatic void diagnoseRepeatedUseOfWeak(Sema &S, 1344243830Sdim const sema::FunctionScopeInfo *CurFn, 1345243830Sdim const Decl *D, 1346243830Sdim const ParentMap &PM) { 1347243830Sdim typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy; 1348243830Sdim typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap; 1349243830Sdim typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector; 1350276479Sdim typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator> 1351276479Sdim StmtUsesPair; 1352243830Sdim 1353243830Sdim ASTContext &Ctx = S.getASTContext(); 1354243830Sdim 1355243830Sdim const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses(); 1356243830Sdim 1357243830Sdim // Extract all weak objects that are referenced more than once. 1358243830Sdim SmallVector<StmtUsesPair, 8> UsesByStmt; 1359243830Sdim for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end(); 1360243830Sdim I != E; ++I) { 1361243830Sdim const WeakUseVector &Uses = I->second; 1362243830Sdim 1363243830Sdim // Find the first read of the weak object. 1364243830Sdim WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); 1365243830Sdim for ( ; UI != UE; ++UI) { 1366243830Sdim if (UI->isUnsafe()) 1367243830Sdim break; 1368243830Sdim } 1369243830Sdim 1370243830Sdim // If there were only writes to this object, don't warn. 1371243830Sdim if (UI == UE) 1372243830Sdim continue; 1373243830Sdim 1374243830Sdim // If there was only one read, followed by any number of writes, and the 1375243830Sdim // read is not within a loop, don't warn. Additionally, don't warn in a 1376243830Sdim // loop if the base object is a local variable -- local variables are often 1377243830Sdim // changed in loops. 1378243830Sdim if (UI == Uses.begin()) { 1379243830Sdim WeakUseVector::const_iterator UI2 = UI; 1380243830Sdim for (++UI2; UI2 != UE; ++UI2) 1381243830Sdim if (UI2->isUnsafe()) 1382243830Sdim break; 1383243830Sdim 1384243830Sdim if (UI2 == UE) { 1385243830Sdim if (!isInLoop(Ctx, PM, UI->getUseExpr())) 1386243830Sdim continue; 1387243830Sdim 1388243830Sdim const WeakObjectProfileTy &Profile = I->first; 1389243830Sdim if (!Profile.isExactProfile()) 1390243830Sdim continue; 1391243830Sdim 1392243830Sdim const NamedDecl *Base = Profile.getBase(); 1393243830Sdim if (!Base) 1394243830Sdim Base = Profile.getProperty(); 1395243830Sdim assert(Base && "A profile always has a base or property."); 1396243830Sdim 1397243830Sdim if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base)) 1398243830Sdim if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base)) 1399243830Sdim continue; 1400243830Sdim } 1401243830Sdim } 1402243830Sdim 1403243830Sdim UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I)); 1404243830Sdim } 1405243830Sdim 1406243830Sdim if (UsesByStmt.empty()) 1407243830Sdim return; 1408243830Sdim 1409243830Sdim // Sort by first use so that we emit the warnings in a deterministic order. 1410276479Sdim SourceManager &SM = S.getSourceManager(); 1411344779Sdim llvm::sort(UsesByStmt, 1412341825Sdim [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { 1413344779Sdim return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(), 1414344779Sdim RHS.first->getBeginLoc()); 1415344779Sdim }); 1416243830Sdim 1417243830Sdim // Classify the current code body for better warning text. 1418243830Sdim // This enum should stay in sync with the cases in 1419243830Sdim // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 1420243830Sdim // FIXME: Should we use a common classification enum and the same set of 1421243830Sdim // possibilities all throughout Sema? 1422243830Sdim enum { 1423243830Sdim Function, 1424243830Sdim Method, 1425243830Sdim Block, 1426243830Sdim Lambda 1427243830Sdim } FunctionKind; 1428243830Sdim 1429243830Sdim if (isa<sema::BlockScopeInfo>(CurFn)) 1430243830Sdim FunctionKind = Block; 1431243830Sdim else if (isa<sema::LambdaScopeInfo>(CurFn)) 1432243830Sdim FunctionKind = Lambda; 1433243830Sdim else if (isa<ObjCMethodDecl>(D)) 1434243830Sdim FunctionKind = Method; 1435243830Sdim else 1436243830Sdim FunctionKind = Function; 1437243830Sdim 1438243830Sdim // Iterate through the sorted problems and emit warnings for each. 1439276479Sdim for (const auto &P : UsesByStmt) { 1440276479Sdim const Stmt *FirstRead = P.first; 1441276479Sdim const WeakObjectProfileTy &Key = P.second->first; 1442276479Sdim const WeakUseVector &Uses = P.second->second; 1443243830Sdim 1444243830Sdim // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy 1445243830Sdim // may not contain enough information to determine that these are different 1446243830Sdim // properties. We can only be 100% sure of a repeated use in certain cases, 1447243830Sdim // and we adjust the diagnostic kind accordingly so that the less certain 1448243830Sdim // case can be turned off if it is too noisy. 1449243830Sdim unsigned DiagKind; 1450243830Sdim if (Key.isExactProfile()) 1451243830Sdim DiagKind = diag::warn_arc_repeated_use_of_weak; 1452243830Sdim else 1453243830Sdim DiagKind = diag::warn_arc_possible_repeated_use_of_weak; 1454243830Sdim 1455243830Sdim // Classify the weak object being accessed for better warning text. 1456243830Sdim // This enum should stay in sync with the cases in 1457243830Sdim // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 1458243830Sdim enum { 1459243830Sdim Variable, 1460243830Sdim Property, 1461243830Sdim ImplicitProperty, 1462243830Sdim Ivar 1463243830Sdim } ObjectKind; 1464243830Sdim 1465309124Sdim const NamedDecl *KeyProp = Key.getProperty(); 1466309124Sdim if (isa<VarDecl>(KeyProp)) 1467243830Sdim ObjectKind = Variable; 1468309124Sdim else if (isa<ObjCPropertyDecl>(KeyProp)) 1469243830Sdim ObjectKind = Property; 1470309124Sdim else if (isa<ObjCMethodDecl>(KeyProp)) 1471243830Sdim ObjectKind = ImplicitProperty; 1472309124Sdim else if (isa<ObjCIvarDecl>(KeyProp)) 1473243830Sdim ObjectKind = Ivar; 1474243830Sdim else 1475243830Sdim llvm_unreachable("Unexpected weak object kind!"); 1476243830Sdim 1477309124Sdim // Do not warn about IBOutlet weak property receivers being set to null 1478309124Sdim // since they are typically only used from the main thread. 1479309124Sdim if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp)) 1480309124Sdim if (Prop->hasAttr<IBOutletAttr>()) 1481309124Sdim continue; 1482309124Sdim 1483243830Sdim // Show the first time the object was read. 1484344779Sdim S.Diag(FirstRead->getBeginLoc(), DiagKind) 1485344779Sdim << int(ObjectKind) << KeyProp << int(FunctionKind) 1486344779Sdim << FirstRead->getSourceRange(); 1487243830Sdim 1488243830Sdim // Print all the other accesses as notes. 1489276479Sdim for (const auto &Use : Uses) { 1490276479Sdim if (Use.getUseExpr() == FirstRead) 1491243830Sdim continue; 1492344779Sdim S.Diag(Use.getUseExpr()->getBeginLoc(), 1493243830Sdim diag::note_arc_weak_also_accessed_here) 1494276479Sdim << Use.getUseExpr()->getSourceRange(); 1495243830Sdim } 1496243830Sdim } 1497243830Sdim} 1498243830Sdim 1499243830Sdimnamespace { 1500218893Sdimclass UninitValsDiagReporter : public UninitVariablesHandler { 1501218893Sdim Sema &S; 1502226633Sdim typedef SmallVector<UninitUse, 2> UsesVec; 1503261991Sdim typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType; 1504249423Sdim // Prefer using MapVector to DenseMap, so that iteration order will be 1505249423Sdim // the same as insertion order. This is needed to obtain a deterministic 1506249423Sdim // order of diagnostics when calling flushDiagnostics(). 1507249423Sdim typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; 1508296417Sdim UsesMap uses; 1509341825Sdim 1510218893Sdimpublic: 1511296417Sdim UninitValsDiagReporter(Sema &S) : S(S) {} 1512288943Sdim ~UninitValsDiagReporter() override { flushDiagnostics(); } 1513226633Sdim 1514249423Sdim MappedType &getUses(const VarDecl *vd) { 1515296417Sdim MappedType &V = uses[vd]; 1516261991Sdim if (!V.getPointer()) 1517261991Sdim V.setPointer(new UsesVec()); 1518226633Sdim return V; 1519218893Sdim } 1520276479Sdim 1521276479Sdim void handleUseOfUninitVariable(const VarDecl *vd, 1522276479Sdim const UninitUse &use) override { 1523261991Sdim getUses(vd).getPointer()->push_back(use); 1524226633Sdim } 1525341825Sdim 1526276479Sdim void handleSelfInit(const VarDecl *vd) override { 1527261991Sdim getUses(vd).setInt(true); 1528226633Sdim } 1529341825Sdim 1530218893Sdim void flushDiagnostics() { 1531296417Sdim for (const auto &P : uses) { 1532276479Sdim const VarDecl *vd = P.first; 1533276479Sdim const MappedType &V = P.second; 1534218893Sdim 1535261991Sdim UsesVec *vec = V.getPointer(); 1536261991Sdim bool hasSelfInit = V.getInt(); 1537218893Sdim 1538341825Sdim // Specially handle the case where we have uses of an uninitialized 1539226633Sdim // variable, but the root cause is an idiomatic self-init. We want 1540226633Sdim // to report the diagnostic at the self-init since that is the root cause. 1541234353Sdim if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) 1542239462Sdim DiagnoseUninitializedUse(S, vd, 1543239462Sdim UninitUse(vd->getInit()->IgnoreParenCasts(), 1544239462Sdim /* isAlwaysUninit */ true), 1545234353Sdim /* alwaysReportSelfInit */ true); 1546226633Sdim else { 1547226633Sdim // Sort the uses by their SourceLocations. While not strictly 1548226633Sdim // guaranteed to produce them in line/column order, this will provide 1549226633Sdim // a stable ordering. 1550341825Sdim llvm::sort(vec->begin(), vec->end(), 1551341825Sdim [](const UninitUse &a, const UninitUse &b) { 1552276479Sdim // Prefer a more confident report over a less confident one. 1553276479Sdim if (a.getKind() != b.getKind()) 1554276479Sdim return a.getKind() > b.getKind(); 1555344779Sdim return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc(); 1556276479Sdim }); 1557276479Sdim 1558276479Sdim for (const auto &U : *vec) { 1559239462Sdim // If we have self-init, downgrade all uses to 'may be uninitialized'. 1560276479Sdim UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U; 1561239462Sdim 1562239462Sdim if (DiagnoseUninitializedUse(S, vd, Use)) 1563226633Sdim // Skip further diagnostics for this variable. We try to warn only 1564226633Sdim // on the first point at which a variable is used uninitialized. 1565226633Sdim break; 1566218893Sdim } 1567218893Sdim } 1568341825Sdim 1569226633Sdim // Release the uses vector. 1570218893Sdim delete vec; 1571218893Sdim } 1572296417Sdim 1573296417Sdim uses.clear(); 1574218893Sdim } 1575234353Sdim 1576234353Sdimprivate: 1577234353Sdim static bool hasAlwaysUninitializedUse(const UsesVec* vec) { 1578276479Sdim return std::any_of(vec->begin(), vec->end(), [](const UninitUse &U) { 1579276479Sdim return U.getKind() == UninitUse::Always || 1580276479Sdim U.getKind() == UninitUse::AfterCall || 1581276479Sdim U.getKind() == UninitUse::AfterDecl; 1582276479Sdim }); 1583234353Sdim } 1584218893Sdim}; 1585296417Sdim} // anonymous namespace 1586218893Sdim 1587226633Sdimnamespace clang { 1588261991Sdimnamespace { 1589249423Sdimtypedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; 1590234353Sdimtypedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; 1591234353Sdimtypedef std::list<DelayedDiag> DiagList; 1592226633Sdim 1593226633Sdimstruct SortDiagBySourceLocation { 1594234353Sdim SourceManager &SM; 1595234353Sdim SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {} 1596226633Sdim 1597226633Sdim bool operator()(const DelayedDiag &left, const DelayedDiag &right) { 1598226633Sdim // Although this call will be slow, this is only called when outputting 1599226633Sdim // multiple warnings. 1600234353Sdim return SM.isBeforeInTranslationUnit(left.first.first, right.first.first); 1601226633Sdim } 1602226633Sdim}; 1603296417Sdim} // anonymous namespace 1604296417Sdim} // namespace clang 1605226633Sdim 1606261991Sdim//===----------------------------------------------------------------------===// 1607261991Sdim// -Wthread-safety 1608261991Sdim//===----------------------------------------------------------------------===// 1609261991Sdimnamespace clang { 1610280031Sdimnamespace threadSafety { 1611288943Sdimnamespace { 1612280031Sdimclass ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { 1613226633Sdim Sema &S; 1614226633Sdim DiagList Warnings; 1615234353Sdim SourceLocation FunLocation, FunEndLocation; 1616226633Sdim 1617280031Sdim const FunctionDecl *CurrentFunction; 1618280031Sdim bool Verbose; 1619280031Sdim 1620280031Sdim OptionalNotes getNotes() const { 1621280031Sdim if (Verbose && CurrentFunction) { 1622344779Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(), 1623280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1624341825Sdim << CurrentFunction); 1625280031Sdim return OptionalNotes(1, FNote); 1626280031Sdim } 1627280031Sdim return OptionalNotes(); 1628280031Sdim } 1629280031Sdim 1630280031Sdim OptionalNotes getNotes(const PartialDiagnosticAt &Note) const { 1631280031Sdim OptionalNotes ONS(1, Note); 1632280031Sdim if (Verbose && CurrentFunction) { 1633344779Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(), 1634280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1635341825Sdim << CurrentFunction); 1636288943Sdim ONS.push_back(std::move(FNote)); 1637280031Sdim } 1638280031Sdim return ONS; 1639280031Sdim } 1640280031Sdim 1641280031Sdim OptionalNotes getNotes(const PartialDiagnosticAt &Note1, 1642280031Sdim const PartialDiagnosticAt &Note2) const { 1643280031Sdim OptionalNotes ONS; 1644280031Sdim ONS.push_back(Note1); 1645280031Sdim ONS.push_back(Note2); 1646280031Sdim if (Verbose && CurrentFunction) { 1647344779Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(), 1648280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1649341825Sdim << CurrentFunction); 1650288943Sdim ONS.push_back(std::move(FNote)); 1651280031Sdim } 1652280031Sdim return ONS; 1653280031Sdim } 1654280031Sdim 1655353358Sdim OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) { 1656353358Sdim return LocLocked.isValid() 1657353358Sdim ? getNotes(PartialDiagnosticAt( 1658353358Sdim LocLocked, S.PDiag(diag::note_locked_here) << Kind)) 1659353358Sdim : getNotes(); 1660226633Sdim } 1661226633Sdim 1662226633Sdim public: 1663234353Sdim ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) 1664280031Sdim : S(S), FunLocation(FL), FunEndLocation(FEL), 1665280031Sdim CurrentFunction(nullptr), Verbose(false) {} 1666226633Sdim 1667280031Sdim void setVerbose(bool b) { Verbose = b; } 1668280031Sdim 1669341825Sdim /// Emit all buffered diagnostics in order of sourcelocation. 1670226633Sdim /// We need to output diagnostics produced while iterating through 1671226633Sdim /// the lockset in deterministic order, so this function orders diagnostics 1672226633Sdim /// and outputs them. 1673226633Sdim void emitDiagnostics() { 1674234353Sdim Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 1675276479Sdim for (const auto &Diag : Warnings) { 1676276479Sdim S.Diag(Diag.first.first, Diag.first.second); 1677276479Sdim for (const auto &Note : Diag.second) 1678276479Sdim S.Diag(Note.first, Note.second); 1679234353Sdim } 1680226633Sdim } 1681226633Sdim 1682276479Sdim void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override { 1683276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock) 1684276479Sdim << Loc); 1685288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1686226633Sdim } 1687280031Sdim 1688276479Sdim void handleUnmatchedUnlock(StringRef Kind, Name LockName, 1689276479Sdim SourceLocation Loc) override { 1690353358Sdim if (Loc.isInvalid()) 1691353358Sdim Loc = FunLocation; 1692353358Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock) 1693353358Sdim << Kind << LockName); 1694353358Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1695226633Sdim } 1696280031Sdim 1697276479Sdim void handleIncorrectUnlockKind(StringRef Kind, Name LockName, 1698276479Sdim LockKind Expected, LockKind Received, 1699353358Sdim SourceLocation LocLocked, 1700353358Sdim SourceLocation LocUnlock) override { 1701353358Sdim if (LocUnlock.isInvalid()) 1702353358Sdim LocUnlock = FunLocation; 1703353358Sdim PartialDiagnosticAt Warning( 1704353358Sdim LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch) 1705353358Sdim << Kind << LockName << Received << Expected); 1706353358Sdim Warnings.emplace_back(std::move(Warning), 1707353358Sdim makeLockedHereNote(LocLocked, Kind)); 1708226633Sdim } 1709280031Sdim 1710353358Sdim void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked, 1711353358Sdim SourceLocation LocDoubleLock) override { 1712353358Sdim if (LocDoubleLock.isInvalid()) 1713353358Sdim LocDoubleLock = FunLocation; 1714353358Sdim PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock) 1715353358Sdim << Kind << LockName); 1716353358Sdim Warnings.emplace_back(std::move(Warning), 1717353358Sdim makeLockedHereNote(LocLocked, Kind)); 1718276479Sdim } 1719226633Sdim 1720276479Sdim void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, 1721276479Sdim SourceLocation LocLocked, 1722234353Sdim SourceLocation LocEndOfScope, 1723276479Sdim LockErrorKind LEK) override { 1724226633Sdim unsigned DiagID = 0; 1725226633Sdim switch (LEK) { 1726226633Sdim case LEK_LockedSomePredecessors: 1727234353Sdim DiagID = diag::warn_lock_some_predecessors; 1728226633Sdim break; 1729226633Sdim case LEK_LockedSomeLoopIterations: 1730226633Sdim DiagID = diag::warn_expecting_lock_held_on_loop; 1731226633Sdim break; 1732226633Sdim case LEK_LockedAtEndOfFunction: 1733226633Sdim DiagID = diag::warn_no_unlock; 1734226633Sdim break; 1735239462Sdim case LEK_NotLockedAtEndOfFunction: 1736239462Sdim DiagID = diag::warn_expecting_locked; 1737239462Sdim break; 1738226633Sdim } 1739234353Sdim if (LocEndOfScope.isInvalid()) 1740234353Sdim LocEndOfScope = FunEndLocation; 1741234353Sdim 1742276479Sdim PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind 1743276479Sdim << LockName); 1744353358Sdim Warnings.emplace_back(std::move(Warning), 1745353358Sdim makeLockedHereNote(LocLocked, Kind)); 1746226633Sdim } 1747226633Sdim 1748276479Sdim void handleExclusiveAndShared(StringRef Kind, Name LockName, 1749276479Sdim SourceLocation Loc1, 1750276479Sdim SourceLocation Loc2) override { 1751276479Sdim PartialDiagnosticAt Warning(Loc1, 1752276479Sdim S.PDiag(diag::warn_lock_exclusive_and_shared) 1753276479Sdim << Kind << LockName); 1754276479Sdim PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) 1755276479Sdim << Kind << LockName); 1756288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1757226633Sdim } 1758226633Sdim 1759276479Sdim void handleNoMutexHeld(StringRef Kind, const NamedDecl *D, 1760276479Sdim ProtectedOperationKind POK, AccessKind AK, 1761276479Sdim SourceLocation Loc) override { 1762276479Sdim assert((POK == POK_VarAccess || POK == POK_VarDereference) && 1763276479Sdim "Only works for variables"); 1764226633Sdim unsigned DiagID = POK == POK_VarAccess? 1765226633Sdim diag::warn_variable_requires_any_lock: 1766226633Sdim diag::warn_var_deref_requires_any_lock; 1767234353Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) 1768341825Sdim << D << getLockKindFromAccessKind(AK)); 1769288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1770226633Sdim } 1771226633Sdim 1772276479Sdim void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, 1773276479Sdim ProtectedOperationKind POK, Name LockName, 1774276479Sdim LockKind LK, SourceLocation Loc, 1775276479Sdim Name *PossibleMatch) override { 1776226633Sdim unsigned DiagID = 0; 1777243830Sdim if (PossibleMatch) { 1778243830Sdim switch (POK) { 1779243830Sdim case POK_VarAccess: 1780243830Sdim DiagID = diag::warn_variable_requires_lock_precise; 1781243830Sdim break; 1782243830Sdim case POK_VarDereference: 1783243830Sdim DiagID = diag::warn_var_deref_requires_lock_precise; 1784243830Sdim break; 1785243830Sdim case POK_FunctionCall: 1786243830Sdim DiagID = diag::warn_fun_requires_lock_precise; 1787243830Sdim break; 1788280031Sdim case POK_PassByRef: 1789280031Sdim DiagID = diag::warn_guarded_pass_by_reference; 1790280031Sdim break; 1791280031Sdim case POK_PtPassByRef: 1792280031Sdim DiagID = diag::warn_pt_guarded_pass_by_reference; 1793280031Sdim break; 1794243830Sdim } 1795276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 1796341825Sdim << D 1797276479Sdim << LockName << LK); 1798243830Sdim PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) 1799276479Sdim << *PossibleMatch); 1800280031Sdim if (Verbose && POK == POK_VarAccess) { 1801280031Sdim PartialDiagnosticAt VNote(D->getLocation(), 1802280031Sdim S.PDiag(diag::note_guarded_by_declared_here) 1803280031Sdim << D->getNameAsString()); 1804288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote)); 1805280031Sdim } else 1806288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1807243830Sdim } else { 1808243830Sdim switch (POK) { 1809243830Sdim case POK_VarAccess: 1810243830Sdim DiagID = diag::warn_variable_requires_lock; 1811243830Sdim break; 1812243830Sdim case POK_VarDereference: 1813243830Sdim DiagID = diag::warn_var_deref_requires_lock; 1814243830Sdim break; 1815243830Sdim case POK_FunctionCall: 1816243830Sdim DiagID = diag::warn_fun_requires_lock; 1817243830Sdim break; 1818280031Sdim case POK_PassByRef: 1819280031Sdim DiagID = diag::warn_guarded_pass_by_reference; 1820280031Sdim break; 1821280031Sdim case POK_PtPassByRef: 1822280031Sdim DiagID = diag::warn_pt_guarded_pass_by_reference; 1823280031Sdim break; 1824243830Sdim } 1825276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 1826341825Sdim << D 1827276479Sdim << LockName << LK); 1828280031Sdim if (Verbose && POK == POK_VarAccess) { 1829280031Sdim PartialDiagnosticAt Note(D->getLocation(), 1830341825Sdim S.PDiag(diag::note_guarded_by_declared_here)); 1831288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1832280031Sdim } else 1833288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1834226633Sdim } 1835226633Sdim } 1836226633Sdim 1837288943Sdim void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, 1838288943Sdim SourceLocation Loc) override { 1839280031Sdim PartialDiagnosticAt Warning(Loc, 1840280031Sdim S.PDiag(diag::warn_acquire_requires_negative_cap) 1841280031Sdim << Kind << LockName << Neg); 1842288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1843280031Sdim } 1844280031Sdim 1845276479Sdim void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, 1846276479Sdim SourceLocation Loc) override { 1847276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex) 1848276479Sdim << Kind << FunName << LockName); 1849288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1850226633Sdim } 1851280031Sdim 1852288943Sdim void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name, 1853288943Sdim SourceLocation Loc) override { 1854288943Sdim PartialDiagnosticAt Warning(Loc, 1855288943Sdim S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name); 1856288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1857288943Sdim } 1858288943Sdim 1859288943Sdim void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override { 1860288943Sdim PartialDiagnosticAt Warning(Loc, 1861288943Sdim S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); 1862288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1863288943Sdim } 1864288943Sdim 1865280031Sdim void enterFunction(const FunctionDecl* FD) override { 1866280031Sdim CurrentFunction = FD; 1867280031Sdim } 1868280031Sdim 1869280031Sdim void leaveFunction(const FunctionDecl* FD) override { 1870296417Sdim CurrentFunction = nullptr; 1871280031Sdim } 1872226633Sdim}; 1873296417Sdim} // anonymous namespace 1874288943Sdim} // namespace threadSafety 1875288943Sdim} // namespace clang 1876280031Sdim 1877226633Sdim//===----------------------------------------------------------------------===// 1878261991Sdim// -Wconsumed 1879261991Sdim//===----------------------------------------------------------------------===// 1880261991Sdim 1881261991Sdimnamespace clang { 1882261991Sdimnamespace consumed { 1883261991Sdimnamespace { 1884261991Sdimclass ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { 1885341825Sdim 1886261991Sdim Sema &S; 1887261991Sdim DiagList Warnings; 1888341825Sdim 1889261991Sdimpublic: 1890288943Sdim 1891261991Sdim ConsumedWarningsHandler(Sema &S) : S(S) {} 1892276479Sdim 1893276479Sdim void emitDiagnostics() override { 1894261991Sdim Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 1895276479Sdim for (const auto &Diag : Warnings) { 1896276479Sdim S.Diag(Diag.first.first, Diag.first.second); 1897276479Sdim for (const auto &Note : Diag.second) 1898276479Sdim S.Diag(Note.first, Note.second); 1899261991Sdim } 1900261991Sdim } 1901276479Sdim 1902276479Sdim void warnLoopStateMismatch(SourceLocation Loc, 1903276479Sdim StringRef VariableName) override { 1904261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) << 1905261991Sdim VariableName); 1906288943Sdim 1907288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1908261991Sdim } 1909341825Sdim 1910261991Sdim void warnParamReturnTypestateMismatch(SourceLocation Loc, 1911261991Sdim StringRef VariableName, 1912261991Sdim StringRef ExpectedState, 1913276479Sdim StringRef ObservedState) override { 1914341825Sdim 1915261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1916261991Sdim diag::warn_param_return_typestate_mismatch) << VariableName << 1917261991Sdim ExpectedState << ObservedState); 1918288943Sdim 1919288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1920261991Sdim } 1921341825Sdim 1922261991Sdim void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 1923276479Sdim StringRef ObservedState) override { 1924341825Sdim 1925261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1926261991Sdim diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState); 1927288943Sdim 1928288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1929261991Sdim } 1930341825Sdim 1931261991Sdim void warnReturnTypestateForUnconsumableType(SourceLocation Loc, 1932276479Sdim StringRef TypeName) override { 1933261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1934261991Sdim diag::warn_return_typestate_for_unconsumable_type) << TypeName); 1935288943Sdim 1936288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1937261991Sdim } 1938341825Sdim 1939261991Sdim void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 1940276479Sdim StringRef ObservedState) override { 1941341825Sdim 1942261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1943261991Sdim diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState); 1944288943Sdim 1945288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1946261991Sdim } 1947341825Sdim 1948261991Sdim void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, 1949276479Sdim SourceLocation Loc) override { 1950341825Sdim 1951261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1952261991Sdim diag::warn_use_of_temp_in_invalid_state) << MethodName << State); 1953288943Sdim 1954288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1955261991Sdim } 1956341825Sdim 1957261991Sdim void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, 1958276479Sdim StringRef State, SourceLocation Loc) override { 1959341825Sdim 1960261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) << 1961261991Sdim MethodName << VariableName << State); 1962288943Sdim 1963288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1964261991Sdim } 1965261991Sdim}; 1966296417Sdim} // anonymous namespace 1967296417Sdim} // namespace consumed 1968296417Sdim} // namespace clang 1969261991Sdim 1970261991Sdim//===----------------------------------------------------------------------===// 1971205408Srdivacky// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based 1972205408Srdivacky// warnings on a function, method, or block. 1973205408Srdivacky//===----------------------------------------------------------------------===// 1974205408Srdivacky 1975206084Srdivackyclang::sema::AnalysisBasedWarnings::Policy::Policy() { 1976206084Srdivacky enableCheckFallThrough = 1; 1977206084Srdivacky enableCheckUnreachable = 0; 1978226633Sdim enableThreadSafetyAnalysis = 0; 1979261991Sdim enableConsumedAnalysis = 0; 1980206084Srdivacky} 1981206084Srdivacky 1982276479Sdimstatic unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) { 1983276479Sdim return (unsigned)!D.isIgnored(diag, SourceLocation()); 1984276479Sdim} 1985276479Sdim 1986224145Sdimclang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) 1987224145Sdim : S(s), 1988224145Sdim NumFunctionsAnalyzed(0), 1989224145Sdim NumFunctionsWithBadCFGs(0), 1990224145Sdim NumCFGBlocks(0), 1991224145Sdim MaxCFGBlocksPerFunction(0), 1992224145Sdim NumUninitAnalysisFunctions(0), 1993224145Sdim NumUninitAnalysisVariables(0), 1994224145Sdim MaxUninitAnalysisVariablesPerFunction(0), 1995224145Sdim NumUninitAnalysisBlockVisits(0), 1996224145Sdim MaxUninitAnalysisBlockVisitsPerFunction(0) { 1997276479Sdim 1998276479Sdim using namespace diag; 1999226633Sdim DiagnosticsEngine &D = S.getDiagnostics(); 2000276479Sdim 2001276479Sdim DefaultPolicy.enableCheckUnreachable = 2002276479Sdim isEnabled(D, warn_unreachable) || 2003276479Sdim isEnabled(D, warn_unreachable_break) || 2004276479Sdim isEnabled(D, warn_unreachable_return) || 2005276479Sdim isEnabled(D, warn_unreachable_loop_increment); 2006276479Sdim 2007276479Sdim DefaultPolicy.enableThreadSafetyAnalysis = 2008276479Sdim isEnabled(D, warn_double_lock); 2009276479Sdim 2010276479Sdim DefaultPolicy.enableConsumedAnalysis = 2011276479Sdim isEnabled(D, warn_use_in_invalid_state); 2012205408Srdivacky} 2013205408Srdivacky 2014276479Sdimstatic void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { 2015276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) 2016219077Sdim S.Diag(D.Loc, D.PD); 2017219077Sdim} 2018219077Sdim 2019206084Srdivackyvoid clang::sema:: 2020206084SrdivackyAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 2021219077Sdim sema::FunctionScopeInfo *fscope, 2022353358Sdim const Decl *D, QualType BlockType) { 2023206084Srdivacky 2024205408Srdivacky // We avoid doing analysis-based warnings when there are errors for 2025205408Srdivacky // two reasons: 2026205408Srdivacky // (1) The CFGs often can't be constructed (if the body is invalid), so 2027205408Srdivacky // don't bother trying. 2028205408Srdivacky // (2) The code already has problems; running the analysis just takes more 2029205408Srdivacky // time. 2030226633Sdim DiagnosticsEngine &Diags = S.getDiagnostics(); 2031207619Srdivacky 2032327952Sdim // Do not do any analysis if we are going to just ignore them. 2033327952Sdim if (Diags.getIgnoreAllWarnings() || 2034327952Sdim (Diags.getSuppressSystemWarnings() && 2035327952Sdim S.SourceMgr.isInSystemHeader(D->getLocation()))) 2036206084Srdivacky return; 2037206084Srdivacky 2038212904Sdim // For code in dependent contexts, we'll do this at instantiation time. 2039212904Sdim if (cast<DeclContext>(D)->isDependentContext()) 2040212904Sdim return; 2041205408Srdivacky 2042309124Sdim if (Diags.hasUncompilableErrorOccurred()) { 2043219077Sdim // Flush out any possibly unreachable diagnostics. 2044219077Sdim flushDiagnostics(S, fscope); 2045219077Sdim return; 2046219077Sdim } 2047341825Sdim 2048205408Srdivacky const Stmt *Body = D->getBody(); 2049205408Srdivacky assert(Body); 2050205408Srdivacky 2051261991Sdim // Construct the analysis context with the specified CFG build options. 2052276479Sdim AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D); 2053226633Sdim 2054205408Srdivacky // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 2055261991Sdim // explosion for destructors that can result and the compile time hit. 2056226633Sdim AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; 2057226633Sdim AC.getCFGBuildOptions().AddEHEdges = false; 2058226633Sdim AC.getCFGBuildOptions().AddInitializers = true; 2059226633Sdim AC.getCFGBuildOptions().AddImplicitDtors = true; 2060243830Sdim AC.getCFGBuildOptions().AddTemporaryDtors = true; 2061276479Sdim AC.getCFGBuildOptions().AddCXXNewAllocator = false; 2062288943Sdim AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; 2063243830Sdim 2064226633Sdim // Force that certain expressions appear as CFGElements in the CFG. This 2065226633Sdim // is used to speed up various analyses. 2066226633Sdim // FIXME: This isn't the right factoring. This is here for initial 2067226633Sdim // prototyping, but we need a way for analyses to say what expressions they 2068226633Sdim // expect to always be CFGElements and then fill in the BuildOptions 2069226633Sdim // appropriately. This is essentially a layering violation. 2070261991Sdim if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis || 2071261991Sdim P.enableConsumedAnalysis) { 2072234353Sdim // Unreachable code analysis and thread safety require a linearized CFG. 2073226633Sdim AC.getCFGBuildOptions().setAllAlwaysAdd(); 2074226633Sdim } 2075226633Sdim else { 2076226633Sdim AC.getCFGBuildOptions() 2077226633Sdim .setAlwaysAdd(Stmt::BinaryOperatorClass) 2078239462Sdim .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) 2079226633Sdim .setAlwaysAdd(Stmt::BlockExprClass) 2080226633Sdim .setAlwaysAdd(Stmt::CStyleCastExprClass) 2081226633Sdim .setAlwaysAdd(Stmt::DeclRefExprClass) 2082226633Sdim .setAlwaysAdd(Stmt::ImplicitCastExprClass) 2083239462Sdim .setAlwaysAdd(Stmt::UnaryOperatorClass) 2084239462Sdim .setAlwaysAdd(Stmt::AttributedStmtClass); 2085226633Sdim } 2086205408Srdivacky 2087360784Sdim // Install the logical handler. 2088344779Sdim llvm::Optional<LogicalErrorHandler> LEH; 2089360784Sdim if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { 2090344779Sdim LEH.emplace(S); 2091344779Sdim AC.getCFGBuildOptions().Observer = &*LEH; 2092276479Sdim } 2093261991Sdim 2094219077Sdim // Emit delayed diagnostics. 2095219077Sdim if (!fscope->PossiblyUnreachableDiags.empty()) { 2096219077Sdim bool analyzed = false; 2097221345Sdim 2098221345Sdim // Register the expressions with the CFGBuilder. 2099276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) { 2100353358Sdim for (const Stmt *S : D.Stmts) 2101353358Sdim AC.registerForcedBlockExpression(S); 2102221345Sdim } 2103221345Sdim 2104221345Sdim if (AC.getCFG()) { 2105221345Sdim analyzed = true; 2106276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) { 2107353358Sdim bool AllReachable = true; 2108353358Sdim for (const Stmt *S : D.Stmts) { 2109353358Sdim const CFGBlock *block = AC.getBlockForRegisteredExpression(S); 2110234353Sdim CFGReverseBlockReachabilityAnalysis *cra = 2111234353Sdim AC.getCFGReachablityAnalysis(); 2112234353Sdim // FIXME: We should be able to assert that block is non-null, but 2113234353Sdim // the CFG analysis can skip potentially-evaluated expressions in 2114234353Sdim // edge cases; see test/Sema/vla-2.c. 2115234353Sdim if (block && cra) { 2116219077Sdim // Can this block be reached from the entrance? 2117353358Sdim if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) { 2118353358Sdim AllReachable = false; 2119353358Sdim break; 2120353358Sdim } 2121219077Sdim } 2122353358Sdim // If we cannot map to a basic block, assume the statement is 2123353358Sdim // reachable. 2124219077Sdim } 2125353358Sdim 2126353358Sdim if (AllReachable) 2127221345Sdim S.Diag(D.Loc, D.PD); 2128219077Sdim } 2129221345Sdim } 2130219077Sdim 2131219077Sdim if (!analyzed) 2132219077Sdim flushDiagnostics(S, fscope); 2133219077Sdim } 2134341825Sdim 2135205408Srdivacky // Warning: check missing 'return' 2136206084Srdivacky if (P.enableCheckFallThrough) { 2137205408Srdivacky const CheckFallThroughDiagnostics &CD = 2138314564Sdim (isa<BlockDecl>(D) 2139314564Sdim ? CheckFallThroughDiagnostics::MakeForBlock() 2140314564Sdim : (isa<CXXMethodDecl>(D) && 2141314564Sdim cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && 2142314564Sdim cast<CXXMethodDecl>(D)->getParent()->isLambda()) 2143314564Sdim ? CheckFallThroughDiagnostics::MakeForLambda() 2144321369Sdim : (fscope->isCoroutine() 2145314564Sdim ? CheckFallThroughDiagnostics::MakeForCoroutine(D) 2146314564Sdim : CheckFallThroughDiagnostics::MakeForFunction(D))); 2147353358Sdim CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope); 2148205408Srdivacky } 2149205408Srdivacky 2150205408Srdivacky // Warning: check for unreachable code 2151234353Sdim if (P.enableCheckUnreachable) { 2152234353Sdim // Only check for unreachable code on non-template instantiations. 2153234353Sdim // Different template instantiations can effectively change the control-flow 2154234353Sdim // and it is very difficult to prove that a snippet of code in a template 2155234353Sdim // is unreachable for all instantiations. 2156234353Sdim bool isTemplateInstantiation = false; 2157234353Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) 2158234353Sdim isTemplateInstantiation = Function->isTemplateInstantiation(); 2159234353Sdim if (!isTemplateInstantiation) 2160234353Sdim CheckUnreachable(S, AC); 2161234353Sdim } 2162226633Sdim 2163226633Sdim // Check for thread safety violations 2164226633Sdim if (P.enableThreadSafetyAnalysis) { 2165234353Sdim SourceLocation FL = AC.getDecl()->getLocation(); 2166344779Sdim SourceLocation FEL = AC.getDecl()->getEndLoc(); 2167280031Sdim threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL); 2168344779Sdim if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getBeginLoc())) 2169249423Sdim Reporter.setIssueBetaWarnings(true); 2170344779Sdim if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getBeginLoc())) 2171280031Sdim Reporter.setVerbose(true); 2172249423Sdim 2173288943Sdim threadSafety::runThreadSafetyAnalysis(AC, Reporter, 2174288943Sdim &S.ThreadSafetyDeclCache); 2175226633Sdim Reporter.emitDiagnostics(); 2176226633Sdim } 2177226633Sdim 2178261991Sdim // Check for violations of consumed properties. 2179261991Sdim if (P.enableConsumedAnalysis) { 2180261991Sdim consumed::ConsumedWarningsHandler WarningHandler(S); 2181261991Sdim consumed::ConsumedAnalyzer Analyzer(WarningHandler); 2182261991Sdim Analyzer.run(AC); 2183261991Sdim } 2184261991Sdim 2185344779Sdim if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) || 2186344779Sdim !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) || 2187344779Sdim !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc())) { 2188221345Sdim if (CFG *cfg = AC.getCFG()) { 2189218893Sdim UninitValsDiagReporter reporter(S); 2190224145Sdim UninitVariablesAnalysisStats stats; 2191224145Sdim std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats)); 2192218893Sdim runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, 2193224145Sdim reporter, stats); 2194224145Sdim 2195224145Sdim if (S.CollectStats && stats.NumVariablesAnalyzed > 0) { 2196224145Sdim ++NumUninitAnalysisFunctions; 2197224145Sdim NumUninitAnalysisVariables += stats.NumVariablesAnalyzed; 2198224145Sdim NumUninitAnalysisBlockVisits += stats.NumBlockVisits; 2199224145Sdim MaxUninitAnalysisVariablesPerFunction = 2200224145Sdim std::max(MaxUninitAnalysisVariablesPerFunction, 2201224145Sdim stats.NumVariablesAnalyzed); 2202224145Sdim MaxUninitAnalysisBlockVisitsPerFunction = 2203224145Sdim std::max(MaxUninitAnalysisBlockVisitsPerFunction, 2204224145Sdim stats.NumBlockVisits); 2205224145Sdim } 2206218893Sdim } 2207218893Sdim } 2208224145Sdim 2209239462Sdim bool FallThroughDiagFull = 2210344779Sdim !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc()); 2211276479Sdim bool FallThroughDiagPerFunction = !Diags.isIgnored( 2212344779Sdim diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc()); 2213309124Sdim if (FallThroughDiagFull || FallThroughDiagPerFunction || 2214309124Sdim fscope->HasFallthroughStmt) { 2215239462Sdim DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); 2216239462Sdim } 2217239462Sdim 2218296417Sdim if (S.getLangOpts().ObjCWeak && 2219344779Sdim !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc())) 2220243830Sdim diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); 2221243830Sdim 2222276479Sdim 2223276479Sdim // Check for infinite self-recursion in functions 2224276479Sdim if (!Diags.isIgnored(diag::warn_infinite_recursive_function, 2225344779Sdim D->getBeginLoc())) { 2226276479Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 2227276479Sdim checkRecursiveFunction(S, FD, Body, AC); 2228276479Sdim } 2229276479Sdim } 2230276479Sdim 2231321369Sdim // Check for throw out of non-throwing function. 2232344779Sdim if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc())) 2233321369Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 2234321369Sdim if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) 2235321369Sdim checkThrowInNonThrowingFunc(S, FD, AC); 2236321369Sdim 2237276479Sdim // If none of the previous checks caused a CFG build, trigger one here 2238360784Sdim // for the logical error handler. 2239360784Sdim if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { 2240276479Sdim AC.getCFG(); 2241276479Sdim } 2242276479Sdim 2243224145Sdim // Collect statistics about the CFG if it was built. 2244224145Sdim if (S.CollectStats && AC.isCFGBuilt()) { 2245224145Sdim ++NumFunctionsAnalyzed; 2246224145Sdim if (CFG *cfg = AC.getCFG()) { 2247224145Sdim // If we successfully built a CFG for this context, record some more 2248224145Sdim // detail information about it. 2249224145Sdim NumCFGBlocks += cfg->getNumBlockIDs(); 2250224145Sdim MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction, 2251224145Sdim cfg->getNumBlockIDs()); 2252224145Sdim } else { 2253224145Sdim ++NumFunctionsWithBadCFGs; 2254224145Sdim } 2255224145Sdim } 2256205408Srdivacky} 2257224145Sdim 2258224145Sdimvoid clang::sema::AnalysisBasedWarnings::PrintStats() const { 2259224145Sdim llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; 2260224145Sdim 2261224145Sdim unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; 2262224145Sdim unsigned AvgCFGBlocksPerFunction = 2263224145Sdim !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; 2264224145Sdim llvm::errs() << NumFunctionsAnalyzed << " functions analyzed (" 2265224145Sdim << NumFunctionsWithBadCFGs << " w/o CFGs).\n" 2266224145Sdim << " " << NumCFGBlocks << " CFG blocks built.\n" 2267224145Sdim << " " << AvgCFGBlocksPerFunction 2268224145Sdim << " average CFG blocks per function.\n" 2269224145Sdim << " " << MaxCFGBlocksPerFunction 2270224145Sdim << " max CFG blocks per function.\n"; 2271224145Sdim 2272224145Sdim unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0 2273224145Sdim : NumUninitAnalysisVariables/NumUninitAnalysisFunctions; 2274224145Sdim unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0 2275224145Sdim : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions; 2276224145Sdim llvm::errs() << NumUninitAnalysisFunctions 2277224145Sdim << " functions analyzed for uninitialiazed variables\n" 2278224145Sdim << " " << NumUninitAnalysisVariables << " variables analyzed.\n" 2279224145Sdim << " " << AvgUninitVariablesPerFunction 2280224145Sdim << " average variables per function.\n" 2281224145Sdim << " " << MaxUninitAnalysisVariablesPerFunction 2282224145Sdim << " max variables per function.\n" 2283224145Sdim << " " << NumUninitAnalysisBlockVisits << " block visits.\n" 2284224145Sdim << " " << AvgUninitBlockVisitsPerFunction 2285224145Sdim << " average block visits per function.\n" 2286224145Sdim << " " << MaxUninitAnalysisBlockVisitsPerFunction 2287224145Sdim << " max block visits per function.\n"; 2288224145Sdim} 2289