AnalysisBasedWarnings.cpp revision 321369
1205408Srdivacky//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// 2205408Srdivacky// 3205408Srdivacky// The LLVM Compiler Infrastructure 4205408Srdivacky// 5205408Srdivacky// This file is distributed under the University of Illinois Open Source 6205408Srdivacky// License. See LICENSE.TXT for details. 7205408Srdivacky// 8205408Srdivacky//===----------------------------------------------------------------------===// 9205408Srdivacky// 10205408Srdivacky// This file defines analysis_warnings::[Policy,Executor]. 11205408Srdivacky// Together they are used by Sema to issue warnings based on inexpensive 12205408Srdivacky// static analysis algorithms in libAnalysis. 13205408Srdivacky// 14205408Srdivacky//===----------------------------------------------------------------------===// 15205408Srdivacky 16212904Sdim#include "clang/Sema/AnalysisBasedWarnings.h" 17249423Sdim#include "clang/AST/DeclCXX.h" 18212904Sdim#include "clang/AST/DeclObjC.h" 19249423Sdim#include "clang/AST/EvaluatedExprVisitor.h" 20249423Sdim#include "clang/AST/ExprCXX.h" 21205408Srdivacky#include "clang/AST/ExprObjC.h" 22249423Sdim#include "clang/AST/ParentMap.h" 23249423Sdim#include "clang/AST/RecursiveASTVisitor.h" 24249423Sdim#include "clang/AST/StmtCXX.h" 25205408Srdivacky#include "clang/AST/StmtObjC.h" 26226633Sdim#include "clang/AST/StmtVisitor.h" 27249423Sdim#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" 28261991Sdim#include "clang/Analysis/Analyses/Consumed.h" 29249423Sdim#include "clang/Analysis/Analyses/ReachableCode.h" 30249423Sdim#include "clang/Analysis/Analyses/ThreadSafety.h" 31249423Sdim#include "clang/Analysis/Analyses/UninitializedValues.h" 32205408Srdivacky#include "clang/Analysis/AnalysisContext.h" 33205408Srdivacky#include "clang/Analysis/CFG.h" 34219077Sdim#include "clang/Analysis/CFGStmtMap.h" 35249423Sdim#include "clang/Basic/SourceLocation.h" 36249423Sdim#include "clang/Basic/SourceManager.h" 37249423Sdim#include "clang/Lex/Preprocessor.h" 38249423Sdim#include "clang/Sema/ScopeInfo.h" 39249423Sdim#include "clang/Sema/SemaInternal.h" 40205408Srdivacky#include "llvm/ADT/BitVector.h" 41249423Sdim#include "llvm/ADT/MapVector.h" 42243830Sdim#include "llvm/ADT/SmallString.h" 43226633Sdim#include "llvm/ADT/SmallVector.h" 44226633Sdim#include "llvm/ADT/StringRef.h" 45205408Srdivacky#include "llvm/Support/Casting.h" 46226633Sdim#include <algorithm> 47249423Sdim#include <deque> 48239462Sdim#include <iterator> 49205408Srdivacky 50205408Srdivackyusing namespace clang; 51205408Srdivacky 52205408Srdivacky//===----------------------------------------------------------------------===// 53205408Srdivacky// Unreachable code analysis. 54205408Srdivacky//===----------------------------------------------------------------------===// 55205408Srdivacky 56205408Srdivackynamespace { 57205408Srdivacky class UnreachableCodeHandler : public reachable_code::Callback { 58205408Srdivacky Sema &S; 59314564Sdim SourceRange PreviousSilenceableCondVal; 60314564Sdim 61205408Srdivacky public: 62205408Srdivacky UnreachableCodeHandler(Sema &s) : S(s) {} 63205408Srdivacky 64276479Sdim void HandleUnreachable(reachable_code::UnreachableKind UK, 65276479Sdim SourceLocation L, 66276479Sdim SourceRange SilenceableCondVal, 67276479Sdim SourceRange R1, 68276479Sdim SourceRange R2) override { 69314564Sdim // Avoid reporting multiple unreachable code diagnostics that are 70314564Sdim // triggered by the same conditional value. 71314564Sdim if (PreviousSilenceableCondVal.isValid() && 72314564Sdim SilenceableCondVal.isValid() && 73314564Sdim PreviousSilenceableCondVal == SilenceableCondVal) 74314564Sdim return; 75314564Sdim PreviousSilenceableCondVal = SilenceableCondVal; 76314564Sdim 77276479Sdim unsigned diag = diag::warn_unreachable; 78276479Sdim switch (UK) { 79276479Sdim case reachable_code::UK_Break: 80276479Sdim diag = diag::warn_unreachable_break; 81276479Sdim break; 82276479Sdim case reachable_code::UK_Return: 83276479Sdim diag = diag::warn_unreachable_return; 84276479Sdim break; 85276479Sdim case reachable_code::UK_Loop_Increment: 86276479Sdim diag = diag::warn_unreachable_loop_increment; 87276479Sdim break; 88276479Sdim case reachable_code::UK_Other: 89276479Sdim break; 90276479Sdim } 91276479Sdim 92276479Sdim S.Diag(L, diag) << R1 << R2; 93276479Sdim 94276479Sdim SourceLocation Open = SilenceableCondVal.getBegin(); 95276479Sdim if (Open.isValid()) { 96276479Sdim SourceLocation Close = SilenceableCondVal.getEnd(); 97276479Sdim Close = S.getLocForEndOfToken(Close); 98276479Sdim if (Close.isValid()) { 99276479Sdim S.Diag(Open, diag::note_unreachable_silence) 100276479Sdim << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (") 101276479Sdim << FixItHint::CreateInsertion(Close, ")"); 102276479Sdim } 103276479Sdim } 104205408Srdivacky } 105205408Srdivacky }; 106296417Sdim} // anonymous namespace 107205408Srdivacky 108205408Srdivacky/// CheckUnreachable - Check for unreachable code. 109234353Sdimstatic void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) { 110276479Sdim // As a heuristic prune all diagnostics not in the main file. Currently 111276479Sdim // the majority of warnings in headers are false positives. These 112276479Sdim // are largely caused by configuration state, e.g. preprocessor 113276479Sdim // defined code, etc. 114276479Sdim // 115276479Sdim // Note that this is also a performance optimization. Analyzing 116276479Sdim // headers many times can be expensive. 117276479Sdim if (!S.getSourceManager().isInMainFile(AC.getDecl()->getLocStart())) 118276479Sdim return; 119276479Sdim 120205408Srdivacky UnreachableCodeHandler UC(S); 121276479Sdim reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC); 122205408Srdivacky} 123205408Srdivacky 124288943Sdimnamespace { 125276479Sdim/// \brief Warn on logical operator errors in CFGBuilder 126276479Sdimclass LogicalErrorHandler : public CFGCallback { 127276479Sdim Sema &S; 128276479Sdim 129276479Sdimpublic: 130276479Sdim LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {} 131276479Sdim 132276479Sdim static bool HasMacroID(const Expr *E) { 133276479Sdim if (E->getExprLoc().isMacroID()) 134276479Sdim return true; 135276479Sdim 136276479Sdim // Recurse to children. 137288943Sdim for (const Stmt *SubStmt : E->children()) 138288943Sdim if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt)) 139288943Sdim if (HasMacroID(SubExpr)) 140288943Sdim return true; 141276479Sdim 142276479Sdim return false; 143276479Sdim } 144276479Sdim 145288943Sdim void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override { 146276479Sdim if (HasMacroID(B)) 147276479Sdim return; 148276479Sdim 149276479Sdim SourceRange DiagRange = B->getSourceRange(); 150276479Sdim S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison) 151276479Sdim << DiagRange << isAlwaysTrue; 152276479Sdim } 153276479Sdim 154288943Sdim void compareBitwiseEquality(const BinaryOperator *B, 155288943Sdim bool isAlwaysTrue) override { 156276479Sdim if (HasMacroID(B)) 157276479Sdim return; 158276479Sdim 159276479Sdim SourceRange DiagRange = B->getSourceRange(); 160276479Sdim S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always) 161276479Sdim << DiagRange << isAlwaysTrue; 162276479Sdim } 163276479Sdim}; 164296417Sdim} // anonymous namespace 165276479Sdim 166205408Srdivacky//===----------------------------------------------------------------------===// 167276479Sdim// Check for infinite self-recursion in functions 168276479Sdim//===----------------------------------------------------------------------===// 169276479Sdim 170296417Sdim// Returns true if the function is called anywhere within the CFGBlock. 171296417Sdim// For member functions, the additional condition of being call from the 172296417Sdim// this pointer is required. 173296417Sdimstatic bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { 174296417Sdim // Process all the Stmt's in this block to find any calls to FD. 175296417Sdim for (const auto &B : Block) { 176296417Sdim if (B.getKind() != CFGElement::Statement) 177296417Sdim continue; 178296417Sdim 179296417Sdim const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt()); 180296417Sdim if (!CE || !CE->getCalleeDecl() || 181296417Sdim CE->getCalleeDecl()->getCanonicalDecl() != FD) 182296417Sdim continue; 183296417Sdim 184296417Sdim // Skip function calls which are qualified with a templated class. 185296417Sdim if (const DeclRefExpr *DRE = 186296417Sdim dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts())) { 187296417Sdim if (NestedNameSpecifier *NNS = DRE->getQualifier()) { 188296417Sdim if (NNS->getKind() == NestedNameSpecifier::TypeSpec && 189296417Sdim isa<TemplateSpecializationType>(NNS->getAsType())) { 190296417Sdim continue; 191296417Sdim } 192296417Sdim } 193296417Sdim } 194296417Sdim 195296417Sdim const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE); 196296417Sdim if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) || 197296417Sdim !MCE->getMethodDecl()->isVirtual()) 198296417Sdim return true; 199296417Sdim } 200296417Sdim return false; 201296417Sdim} 202296417Sdim 203276479Sdim// All blocks are in one of three states. States are ordered so that blocks 204276479Sdim// can only move to higher states. 205276479Sdimenum RecursiveState { 206276479Sdim FoundNoPath, 207276479Sdim FoundPath, 208276479Sdim FoundPathWithNoRecursiveCall 209276479Sdim}; 210276479Sdim 211296417Sdim// Returns true if there exists a path to the exit block and every path 212296417Sdim// to the exit block passes through a call to FD. 213296417Sdimstatic bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { 214276479Sdim 215296417Sdim const unsigned ExitID = cfg->getExit().getBlockID(); 216276479Sdim 217296417Sdim // Mark all nodes as FoundNoPath, then set the status of the entry block. 218296417Sdim SmallVector<RecursiveState, 16> States(cfg->getNumBlockIDs(), FoundNoPath); 219296417Sdim States[cfg->getEntry().getBlockID()] = FoundPathWithNoRecursiveCall; 220276479Sdim 221296417Sdim // Make the processing stack and seed it with the entry block. 222296417Sdim SmallVector<CFGBlock *, 16> Stack; 223296417Sdim Stack.push_back(&cfg->getEntry()); 224276479Sdim 225296417Sdim while (!Stack.empty()) { 226296417Sdim CFGBlock *CurBlock = Stack.back(); 227296417Sdim Stack.pop_back(); 228276479Sdim 229296417Sdim unsigned ID = CurBlock->getBlockID(); 230296417Sdim RecursiveState CurState = States[ID]; 231276479Sdim 232296417Sdim if (CurState == FoundPathWithNoRecursiveCall) { 233296417Sdim // Found a path to the exit node without a recursive call. 234296417Sdim if (ExitID == ID) 235296417Sdim return false; 236276479Sdim 237296417Sdim // Only change state if the block has a recursive call. 238296417Sdim if (hasRecursiveCallInPath(FD, *CurBlock)) 239296417Sdim CurState = FoundPath; 240296417Sdim } 241296417Sdim 242296417Sdim // Loop over successor blocks and add them to the Stack if their state 243296417Sdim // changes. 244296417Sdim for (auto I = CurBlock->succ_begin(), E = CurBlock->succ_end(); I != E; ++I) 245296417Sdim if (*I) { 246296417Sdim unsigned next_ID = (*I)->getBlockID(); 247296417Sdim if (States[next_ID] < CurState) { 248296417Sdim States[next_ID] = CurState; 249296417Sdim Stack.push_back(*I); 250276479Sdim } 251276479Sdim } 252276479Sdim } 253276479Sdim 254296417Sdim // Return true if the exit node is reachable, and only reachable through 255296417Sdim // a recursive call. 256296417Sdim return States[ExitID] == FoundPath; 257276479Sdim} 258276479Sdim 259276479Sdimstatic void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, 260296417Sdim const Stmt *Body, AnalysisDeclContext &AC) { 261276479Sdim FD = FD->getCanonicalDecl(); 262276479Sdim 263276479Sdim // Only run on non-templated functions and non-templated members of 264276479Sdim // templated classes. 265276479Sdim if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate && 266276479Sdim FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization) 267276479Sdim return; 268276479Sdim 269276479Sdim CFG *cfg = AC.getCFG(); 270276479Sdim if (!cfg) return; 271276479Sdim 272276479Sdim // If the exit block is unreachable, skip processing the function. 273276479Sdim if (cfg->getExit().pred_empty()) 274276479Sdim return; 275276479Sdim 276296417Sdim // Emit diagnostic if a recursive function call is detected for all paths. 277296417Sdim if (checkForRecursiveFunctionCall(FD, cfg)) 278276479Sdim S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function); 279276479Sdim} 280276479Sdim 281276479Sdim//===----------------------------------------------------------------------===// 282321369Sdim// Check for throw in a non-throwing function. 283321369Sdim//===----------------------------------------------------------------------===// 284321369Sdimenum ThrowState { 285321369Sdim FoundNoPathForThrow, 286321369Sdim FoundPathForThrow, 287321369Sdim FoundPathWithNoThrowOutFunction, 288321369Sdim}; 289321369Sdim 290321369Sdimstatic bool isThrowCaught(const CXXThrowExpr *Throw, 291321369Sdim const CXXCatchStmt *Catch) { 292321369Sdim const Type *ThrowType = nullptr; 293321369Sdim if (Throw->getSubExpr()) 294321369Sdim ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull(); 295321369Sdim if (!ThrowType) 296321369Sdim return false; 297321369Sdim const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull(); 298321369Sdim if (!CaughtType) 299321369Sdim return true; 300321369Sdim if (ThrowType->isReferenceType()) 301321369Sdim ThrowType = ThrowType->castAs<ReferenceType>() 302321369Sdim ->getPointeeType() 303321369Sdim ->getUnqualifiedDesugaredType(); 304321369Sdim if (CaughtType->isReferenceType()) 305321369Sdim CaughtType = CaughtType->castAs<ReferenceType>() 306321369Sdim ->getPointeeType() 307321369Sdim ->getUnqualifiedDesugaredType(); 308321369Sdim if (ThrowType->isPointerType() && CaughtType->isPointerType()) { 309321369Sdim ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType(); 310321369Sdim CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType(); 311321369Sdim } 312321369Sdim if (CaughtType == ThrowType) 313321369Sdim return true; 314321369Sdim const CXXRecordDecl *CaughtAsRecordType = 315321369Sdim CaughtType->getAsCXXRecordDecl(); 316321369Sdim const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl(); 317321369Sdim if (CaughtAsRecordType && ThrowTypeAsRecordType) 318321369Sdim return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType); 319321369Sdim return false; 320321369Sdim} 321321369Sdim 322321369Sdimstatic bool isThrowCaughtByHandlers(const CXXThrowExpr *CE, 323321369Sdim const CXXTryStmt *TryStmt) { 324321369Sdim for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) { 325321369Sdim if (isThrowCaught(CE, TryStmt->getHandler(H))) 326321369Sdim return true; 327321369Sdim } 328321369Sdim return false; 329321369Sdim} 330321369Sdim 331321369Sdimstatic bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) { 332321369Sdim for (const auto &B : Block) { 333321369Sdim if (B.getKind() != CFGElement::Statement) 334321369Sdim continue; 335321369Sdim const auto *CE = dyn_cast<CXXThrowExpr>(B.getAs<CFGStmt>()->getStmt()); 336321369Sdim if (!CE) 337321369Sdim continue; 338321369Sdim 339321369Sdim OpLoc = CE->getThrowLoc(); 340321369Sdim for (const auto &I : Block.succs()) { 341321369Sdim if (!I.isReachable()) 342321369Sdim continue; 343321369Sdim if (const auto *Terminator = 344321369Sdim dyn_cast_or_null<CXXTryStmt>(I->getTerminator())) 345321369Sdim if (isThrowCaughtByHandlers(CE, Terminator)) 346321369Sdim return false; 347321369Sdim } 348321369Sdim return true; 349321369Sdim } 350321369Sdim return false; 351321369Sdim} 352321369Sdim 353321369Sdimstatic bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { 354321369Sdim 355321369Sdim unsigned ExitID = BodyCFG->getExit().getBlockID(); 356321369Sdim 357321369Sdim SmallVector<ThrowState, 16> States(BodyCFG->getNumBlockIDs(), 358321369Sdim FoundNoPathForThrow); 359321369Sdim States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction; 360321369Sdim 361321369Sdim SmallVector<CFGBlock *, 16> Stack; 362321369Sdim Stack.push_back(&BodyCFG->getEntry()); 363321369Sdim while (!Stack.empty()) { 364321369Sdim CFGBlock *CurBlock = Stack.back(); 365321369Sdim Stack.pop_back(); 366321369Sdim 367321369Sdim unsigned ID = CurBlock->getBlockID(); 368321369Sdim ThrowState CurState = States[ID]; 369321369Sdim if (CurState == FoundPathWithNoThrowOutFunction) { 370321369Sdim if (ExitID == ID) 371321369Sdim continue; 372321369Sdim 373321369Sdim if (doesThrowEscapePath(*CurBlock, OpLoc)) 374321369Sdim CurState = FoundPathForThrow; 375321369Sdim } 376321369Sdim 377321369Sdim // Loop over successor blocks and add them to the Stack if their state 378321369Sdim // changes. 379321369Sdim for (const auto &I : CurBlock->succs()) 380321369Sdim if (I.isReachable()) { 381321369Sdim unsigned NextID = I->getBlockID(); 382321369Sdim if (NextID == ExitID && CurState == FoundPathForThrow) { 383321369Sdim States[NextID] = CurState; 384321369Sdim } else if (States[NextID] < CurState) { 385321369Sdim States[NextID] = CurState; 386321369Sdim Stack.push_back(I); 387321369Sdim } 388321369Sdim } 389321369Sdim } 390321369Sdim // Return true if the exit node is reachable, and only reachable through 391321369Sdim // a throw expression. 392321369Sdim return States[ExitID] == FoundPathForThrow; 393321369Sdim} 394321369Sdim 395321369Sdimstatic void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, 396321369Sdim const FunctionDecl *FD) { 397321369Sdim if (!S.getSourceManager().isInSystemHeader(OpLoc) && 398321369Sdim FD->getTypeSourceInfo()) { 399321369Sdim S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; 400321369Sdim if (S.getLangOpts().CPlusPlus11 && 401321369Sdim (isa<CXXDestructorDecl>(FD) || 402321369Sdim FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || 403321369Sdim FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { 404321369Sdim if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> 405321369Sdim getAs<FunctionProtoType>()) 406321369Sdim S.Diag(FD->getLocation(), diag::note_throw_in_dtor) 407321369Sdim << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() 408321369Sdim << FD->getExceptionSpecSourceRange(); 409321369Sdim } else 410321369Sdim S.Diag(FD->getLocation(), diag::note_throw_in_function) 411321369Sdim << FD->getExceptionSpecSourceRange(); 412321369Sdim } 413321369Sdim} 414321369Sdim 415321369Sdimstatic void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, 416321369Sdim AnalysisDeclContext &AC) { 417321369Sdim CFG *BodyCFG = AC.getCFG(); 418321369Sdim if (!BodyCFG) 419321369Sdim return; 420321369Sdim if (BodyCFG->getExit().pred_empty()) 421321369Sdim return; 422321369Sdim SourceLocation OpLoc; 423321369Sdim if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG)) 424321369Sdim EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD); 425321369Sdim} 426321369Sdim 427321369Sdimstatic bool isNoexcept(const FunctionDecl *FD) { 428321369Sdim const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); 429321369Sdim if (FPT->isNothrow(FD->getASTContext())) 430321369Sdim return true; 431321369Sdim return false; 432321369Sdim} 433321369Sdim 434321369Sdim//===----------------------------------------------------------------------===// 435205408Srdivacky// Check for missing return value. 436205408Srdivacky//===----------------------------------------------------------------------===// 437205408Srdivacky 438208600Srdivackyenum ControlFlowKind { 439208600Srdivacky UnknownFallThrough, 440208600Srdivacky NeverFallThrough, 441208600Srdivacky MaybeFallThrough, 442208600Srdivacky AlwaysFallThrough, 443208600Srdivacky NeverFallThroughOrReturn 444208600Srdivacky}; 445205408Srdivacky 446205408Srdivacky/// CheckFallThrough - Check that we don't fall off the end of a 447205408Srdivacky/// Statement that should return a value. 448205408Srdivacky/// 449205408Srdivacky/// \returns AlwaysFallThrough iff we always fall off the end of the statement, 450205408Srdivacky/// MaybeFallThrough iff we might or might not fall off the end, 451205408Srdivacky/// NeverFallThroughOrReturn iff we never fall off the end of the statement or 452205408Srdivacky/// return. We assume NeverFallThrough iff we never fall off the end of the 453205408Srdivacky/// statement but we may return. We assume that functions not marked noreturn 454205408Srdivacky/// will return. 455234353Sdimstatic ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { 456205408Srdivacky CFG *cfg = AC.getCFG(); 457276479Sdim if (!cfg) return UnknownFallThrough; 458205408Srdivacky 459205408Srdivacky // The CFG leaves in dead things, and we don't want the dead code paths to 460205408Srdivacky // confuse us, so we mark all live things first. 461205408Srdivacky llvm::BitVector live(cfg->getNumBlockIDs()); 462226633Sdim unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), 463205408Srdivacky live); 464205408Srdivacky 465205408Srdivacky bool AddEHEdges = AC.getAddEHEdges(); 466205408Srdivacky if (!AddEHEdges && count != cfg->getNumBlockIDs()) 467205408Srdivacky // When there are things remaining dead, and we didn't add EH edges 468205408Srdivacky // from CallExprs to the catch clauses, we have to go back and 469205408Srdivacky // mark them as live. 470276479Sdim for (const auto *B : *cfg) { 471276479Sdim if (!live[B->getBlockID()]) { 472276479Sdim if (B->pred_begin() == B->pred_end()) { 473276479Sdim if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator())) 474205408Srdivacky // When not adding EH edges from calls, catch clauses 475205408Srdivacky // can otherwise seem dead. Avoid noting them as dead. 476276479Sdim count += reachable_code::ScanReachableFromBlock(B, live); 477205408Srdivacky continue; 478205408Srdivacky } 479205408Srdivacky } 480205408Srdivacky } 481205408Srdivacky 482205408Srdivacky // Now we know what is live, we check the live precessors of the exit block 483205408Srdivacky // and look for fall through paths, being careful to ignore normal returns, 484205408Srdivacky // and exceptional paths. 485205408Srdivacky bool HasLiveReturn = false; 486205408Srdivacky bool HasFakeEdge = false; 487205408Srdivacky bool HasPlainEdge = false; 488205408Srdivacky bool HasAbnormalEdge = false; 489218893Sdim 490218893Sdim // Ignore default cases that aren't likely to be reachable because all 491218893Sdim // enums in a switch(X) have explicit case statements. 492218893Sdim CFGBlock::FilterOptions FO; 493218893Sdim FO.IgnoreDefaultsWithCoveredEnums = 1; 494218893Sdim 495218893Sdim for (CFGBlock::filtered_pred_iterator 496218893Sdim I = cfg->getExit().filtered_pred_start_end(FO); I.hasMore(); ++I) { 497218893Sdim const CFGBlock& B = **I; 498205408Srdivacky if (!live[B.getBlockID()]) 499205408Srdivacky continue; 500218893Sdim 501226633Sdim // Skip blocks which contain an element marked as no-return. They don't 502226633Sdim // represent actually viable edges into the exit block, so mark them as 503226633Sdim // abnormal. 504226633Sdim if (B.hasNoReturnElement()) { 505226633Sdim HasAbnormalEdge = true; 506226633Sdim continue; 507226633Sdim } 508226633Sdim 509218893Sdim // Destructors can appear after the 'return' in the CFG. This is 510218893Sdim // normal. We need to look pass the destructors for the return 511218893Sdim // statement (if it exists). 512218893Sdim CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); 513221345Sdim 514226633Sdim for ( ; ri != re ; ++ri) 515249423Sdim if (ri->getAs<CFGStmt>()) 516218893Sdim break; 517226633Sdim 518218893Sdim // No more CFGElements in the block? 519218893Sdim if (ri == re) { 520205408Srdivacky if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { 521205408Srdivacky HasAbnormalEdge = true; 522205408Srdivacky continue; 523205408Srdivacky } 524205408Srdivacky // A labeled empty statement, or the entry block... 525205408Srdivacky HasPlainEdge = true; 526205408Srdivacky continue; 527205408Srdivacky } 528218893Sdim 529249423Sdim CFGStmt CS = ri->castAs<CFGStmt>(); 530226633Sdim const Stmt *S = CS.getStmt(); 531314564Sdim if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) { 532205408Srdivacky HasLiveReturn = true; 533205408Srdivacky continue; 534205408Srdivacky } 535205408Srdivacky if (isa<ObjCAtThrowStmt>(S)) { 536205408Srdivacky HasFakeEdge = true; 537205408Srdivacky continue; 538205408Srdivacky } 539205408Srdivacky if (isa<CXXThrowExpr>(S)) { 540205408Srdivacky HasFakeEdge = true; 541205408Srdivacky continue; 542205408Srdivacky } 543239462Sdim if (isa<MSAsmStmt>(S)) { 544239462Sdim // TODO: Verify this is correct. 545239462Sdim HasFakeEdge = true; 546239462Sdim HasLiveReturn = true; 547239462Sdim continue; 548239462Sdim } 549205408Srdivacky if (isa<CXXTryStmt>(S)) { 550205408Srdivacky HasAbnormalEdge = true; 551205408Srdivacky continue; 552205408Srdivacky } 553226633Sdim if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) 554226633Sdim == B.succ_end()) { 555226633Sdim HasAbnormalEdge = true; 556226633Sdim continue; 557226633Sdim } 558205408Srdivacky 559226633Sdim HasPlainEdge = true; 560205408Srdivacky } 561205408Srdivacky if (!HasPlainEdge) { 562205408Srdivacky if (HasLiveReturn) 563205408Srdivacky return NeverFallThrough; 564205408Srdivacky return NeverFallThroughOrReturn; 565205408Srdivacky } 566205408Srdivacky if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) 567205408Srdivacky return MaybeFallThrough; 568205408Srdivacky // This says AlwaysFallThrough for calls to functions that are not marked 569205408Srdivacky // noreturn, that don't return. If people would like this warning to be more 570205408Srdivacky // accurate, such functions should be marked as noreturn. 571205408Srdivacky return AlwaysFallThrough; 572205408Srdivacky} 573205408Srdivacky 574212904Sdimnamespace { 575212904Sdim 576205408Srdivackystruct CheckFallThroughDiagnostics { 577205408Srdivacky unsigned diag_MaybeFallThrough_HasNoReturn; 578205408Srdivacky unsigned diag_MaybeFallThrough_ReturnsNonVoid; 579205408Srdivacky unsigned diag_AlwaysFallThrough_HasNoReturn; 580205408Srdivacky unsigned diag_AlwaysFallThrough_ReturnsNonVoid; 581205408Srdivacky unsigned diag_NeverFallThroughOrReturn; 582314564Sdim enum { Function, Block, Lambda, Coroutine } funMode; 583218893Sdim SourceLocation FuncLoc; 584206084Srdivacky 585207619Srdivacky static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { 586205408Srdivacky CheckFallThroughDiagnostics D; 587218893Sdim D.FuncLoc = Func->getLocation(); 588205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 589205408Srdivacky diag::warn_falloff_noreturn_function; 590205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 591205408Srdivacky diag::warn_maybe_falloff_nonvoid_function; 592205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 593205408Srdivacky diag::warn_falloff_noreturn_function; 594205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 595205408Srdivacky diag::warn_falloff_nonvoid_function; 596207619Srdivacky 597207619Srdivacky // Don't suggest that virtual functions be marked "noreturn", since they 598207619Srdivacky // might be overridden by non-noreturn functions. 599207619Srdivacky bool isVirtualMethod = false; 600207619Srdivacky if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) 601207619Srdivacky isVirtualMethod = Method->isVirtual(); 602207619Srdivacky 603226633Sdim // Don't suggest that template instantiations be marked "noreturn" 604226633Sdim bool isTemplateInstantiation = false; 605234353Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) 606234353Sdim isTemplateInstantiation = Function->isTemplateInstantiation(); 607226633Sdim 608226633Sdim if (!isVirtualMethod && !isTemplateInstantiation) 609207619Srdivacky D.diag_NeverFallThroughOrReturn = 610207619Srdivacky diag::warn_suggest_noreturn_function; 611207619Srdivacky else 612207619Srdivacky D.diag_NeverFallThroughOrReturn = 0; 613207619Srdivacky 614234353Sdim D.funMode = Function; 615205408Srdivacky return D; 616205408Srdivacky } 617206084Srdivacky 618314564Sdim static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) { 619314564Sdim CheckFallThroughDiagnostics D; 620314564Sdim D.FuncLoc = Func->getLocation(); 621314564Sdim D.diag_MaybeFallThrough_HasNoReturn = 0; 622314564Sdim D.diag_MaybeFallThrough_ReturnsNonVoid = 623314564Sdim diag::warn_maybe_falloff_nonvoid_coroutine; 624314564Sdim D.diag_AlwaysFallThrough_HasNoReturn = 0; 625314564Sdim D.diag_AlwaysFallThrough_ReturnsNonVoid = 626314564Sdim diag::warn_falloff_nonvoid_coroutine; 627314564Sdim D.funMode = Coroutine; 628314564Sdim return D; 629314564Sdim } 630314564Sdim 631205408Srdivacky static CheckFallThroughDiagnostics MakeForBlock() { 632205408Srdivacky CheckFallThroughDiagnostics D; 633205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 634205408Srdivacky diag::err_noreturn_block_has_return_expr; 635205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 636205408Srdivacky diag::err_maybe_falloff_nonvoid_block; 637205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 638205408Srdivacky diag::err_noreturn_block_has_return_expr; 639205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 640205408Srdivacky diag::err_falloff_nonvoid_block; 641276479Sdim D.diag_NeverFallThroughOrReturn = 0; 642234353Sdim D.funMode = Block; 643205408Srdivacky return D; 644205408Srdivacky } 645206084Srdivacky 646234353Sdim static CheckFallThroughDiagnostics MakeForLambda() { 647234353Sdim CheckFallThroughDiagnostics D; 648234353Sdim D.diag_MaybeFallThrough_HasNoReturn = 649234353Sdim diag::err_noreturn_lambda_has_return_expr; 650234353Sdim D.diag_MaybeFallThrough_ReturnsNonVoid = 651234353Sdim diag::warn_maybe_falloff_nonvoid_lambda; 652234353Sdim D.diag_AlwaysFallThrough_HasNoReturn = 653234353Sdim diag::err_noreturn_lambda_has_return_expr; 654234353Sdim D.diag_AlwaysFallThrough_ReturnsNonVoid = 655234353Sdim diag::warn_falloff_nonvoid_lambda; 656234353Sdim D.diag_NeverFallThroughOrReturn = 0; 657234353Sdim D.funMode = Lambda; 658234353Sdim return D; 659234353Sdim } 660234353Sdim 661226633Sdim bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, 662205408Srdivacky bool HasNoReturn) const { 663234353Sdim if (funMode == Function) { 664218893Sdim return (ReturnsVoid || 665276479Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, 666276479Sdim FuncLoc)) && 667276479Sdim (!HasNoReturn || 668276479Sdim D.isIgnored(diag::warn_noreturn_function_has_return_expr, 669276479Sdim FuncLoc)) && 670276479Sdim (!ReturnsVoid || 671276479Sdim D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc)); 672205408Srdivacky } 673314564Sdim if (funMode == Coroutine) { 674314564Sdim return (ReturnsVoid || 675314564Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) || 676314564Sdim D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine, 677314564Sdim FuncLoc)) && 678314564Sdim (!HasNoReturn); 679314564Sdim } 680234353Sdim // For blocks / lambdas. 681276479Sdim return ReturnsVoid && !HasNoReturn; 682205408Srdivacky } 683205408Srdivacky}; 684205408Srdivacky 685296417Sdim} // anonymous namespace 686212904Sdim 687205408Srdivacky/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a 688205408Srdivacky/// function that should return a value. Check that we don't fall off the end 689205408Srdivacky/// of a noreturn function. We assume that functions and blocks not marked 690205408Srdivacky/// noreturn will return. 691205408Srdivackystatic void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, 692219077Sdim const BlockExpr *blkExpr, 693205408Srdivacky const CheckFallThroughDiagnostics& CD, 694234353Sdim AnalysisDeclContext &AC) { 695205408Srdivacky 696205408Srdivacky bool ReturnsVoid = false; 697205408Srdivacky bool HasNoReturn = false; 698321369Sdim bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine(); 699205408Srdivacky 700314564Sdim if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 701314564Sdim if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) 702314564Sdim ReturnsVoid = CBody->getFallthroughHandler() != nullptr; 703314564Sdim else 704314564Sdim ReturnsVoid = FD->getReturnType()->isVoidType(); 705249423Sdim HasNoReturn = FD->isNoReturn(); 706205408Srdivacky } 707314564Sdim else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 708276479Sdim ReturnsVoid = MD->getReturnType()->isVoidType(); 709205408Srdivacky HasNoReturn = MD->hasAttr<NoReturnAttr>(); 710205408Srdivacky } 711205408Srdivacky else if (isa<BlockDecl>(D)) { 712219077Sdim QualType BlockTy = blkExpr->getType(); 713206084Srdivacky if (const FunctionType *FT = 714205408Srdivacky BlockTy->getPointeeType()->getAs<FunctionType>()) { 715276479Sdim if (FT->getReturnType()->isVoidType()) 716205408Srdivacky ReturnsVoid = true; 717205408Srdivacky if (FT->getNoReturnAttr()) 718205408Srdivacky HasNoReturn = true; 719205408Srdivacky } 720205408Srdivacky } 721205408Srdivacky 722226633Sdim DiagnosticsEngine &Diags = S.getDiagnostics(); 723205408Srdivacky 724205408Srdivacky // Short circuit for compilation speed. 725205408Srdivacky if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) 726205408Srdivacky return; 727280031Sdim SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); 728321369Sdim auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { 729321369Sdim if (IsCoroutine) 730321369Sdim S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType(); 731321369Sdim else 732321369Sdim S.Diag(Loc, DiagID); 733321369Sdim }; 734280031Sdim // Either in a function body compound statement, or a function-try-block. 735280031Sdim switch (CheckFallThrough(AC)) { 736280031Sdim case UnknownFallThrough: 737280031Sdim break; 738208600Srdivacky 739280031Sdim case MaybeFallThrough: 740280031Sdim if (HasNoReturn) 741321369Sdim EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); 742280031Sdim else if (!ReturnsVoid) 743321369Sdim EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); 744280031Sdim break; 745280031Sdim case AlwaysFallThrough: 746280031Sdim if (HasNoReturn) 747321369Sdim EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); 748280031Sdim else if (!ReturnsVoid) 749321369Sdim EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); 750280031Sdim break; 751280031Sdim case NeverFallThroughOrReturn: 752280031Sdim if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { 753280031Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 754280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; 755280031Sdim } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 756280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; 757280031Sdim } else { 758280031Sdim S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); 759226633Sdim } 760280031Sdim } 761280031Sdim break; 762280031Sdim case NeverFallThrough: 763280031Sdim break; 764205408Srdivacky } 765205408Srdivacky} 766205408Srdivacky 767205408Srdivacky//===----------------------------------------------------------------------===// 768218893Sdim// -Wuninitialized 769218893Sdim//===----------------------------------------------------------------------===// 770218893Sdim 771218893Sdimnamespace { 772221345Sdim/// ContainsReference - A visitor class to search for references to 773221345Sdim/// a particular declaration (the needle) within any evaluated component of an 774221345Sdim/// expression (recursively). 775288943Sdimclass ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> { 776221345Sdim bool FoundReference; 777221345Sdim const DeclRefExpr *Needle; 778221345Sdim 779221345Sdimpublic: 780288943Sdim typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited; 781288943Sdim 782221345Sdim ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) 783288943Sdim : Inherited(Context), FoundReference(false), Needle(Needle) {} 784221345Sdim 785288943Sdim void VisitExpr(const Expr *E) { 786221345Sdim // Stop evaluating if we already have a reference. 787221345Sdim if (FoundReference) 788221345Sdim return; 789221345Sdim 790288943Sdim Inherited::VisitExpr(E); 791221345Sdim } 792221345Sdim 793288943Sdim void VisitDeclRefExpr(const DeclRefExpr *E) { 794221345Sdim if (E == Needle) 795221345Sdim FoundReference = true; 796221345Sdim else 797288943Sdim Inherited::VisitDeclRefExpr(E); 798221345Sdim } 799221345Sdim 800221345Sdim bool doesContainReference() const { return FoundReference; } 801221345Sdim}; 802296417Sdim} // anonymous namespace 803221345Sdim 804226633Sdimstatic bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { 805234353Sdim QualType VariableTy = VD->getType().getCanonicalType(); 806234353Sdim if (VariableTy->isBlockPointerType() && 807234353Sdim !VD->hasAttr<BlocksAttr>()) { 808276479Sdim S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) 809276479Sdim << VD->getDeclName() 810276479Sdim << FixItHint::CreateInsertion(VD->getLocation(), "__block "); 811234353Sdim return true; 812234353Sdim } 813261991Sdim 814226633Sdim // Don't issue a fixit if there is already an initializer. 815226633Sdim if (VD->getInit()) 816226633Sdim return false; 817239462Sdim 818239462Sdim // Don't suggest a fixit inside macros. 819239462Sdim if (VD->getLocEnd().isMacroID()) 820239462Sdim return false; 821239462Sdim 822276479Sdim SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd()); 823261991Sdim 824261991Sdim // Suggest possible initialization (if any). 825261991Sdim std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); 826261991Sdim if (Init.empty()) 827261991Sdim return false; 828261991Sdim 829234353Sdim S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() 830234353Sdim << FixItHint::CreateInsertion(Loc, Init); 831234353Sdim return true; 832226633Sdim} 833226633Sdim 834239462Sdim/// Create a fixit to remove an if-like statement, on the assumption that its 835239462Sdim/// condition is CondVal. 836239462Sdimstatic void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, 837239462Sdim const Stmt *Else, bool CondVal, 838239462Sdim FixItHint &Fixit1, FixItHint &Fixit2) { 839239462Sdim if (CondVal) { 840239462Sdim // If condition is always true, remove all but the 'then'. 841239462Sdim Fixit1 = FixItHint::CreateRemoval( 842239462Sdim CharSourceRange::getCharRange(If->getLocStart(), 843239462Sdim Then->getLocStart())); 844239462Sdim if (Else) { 845296417Sdim SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getLocEnd()); 846239462Sdim Fixit2 = FixItHint::CreateRemoval( 847239462Sdim SourceRange(ElseKwLoc, Else->getLocEnd())); 848239462Sdim } 849239462Sdim } else { 850239462Sdim // If condition is always false, remove all but the 'else'. 851239462Sdim if (Else) 852239462Sdim Fixit1 = FixItHint::CreateRemoval( 853239462Sdim CharSourceRange::getCharRange(If->getLocStart(), 854239462Sdim Else->getLocStart())); 855239462Sdim else 856239462Sdim Fixit1 = FixItHint::CreateRemoval(If->getSourceRange()); 857239462Sdim } 858239462Sdim} 859239462Sdim 860239462Sdim/// DiagUninitUse -- Helper function to produce a diagnostic for an 861239462Sdim/// uninitialized use of a variable. 862239462Sdimstatic void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, 863239462Sdim bool IsCapturedByBlock) { 864239462Sdim bool Diagnosed = false; 865239462Sdim 866261991Sdim switch (Use.getKind()) { 867261991Sdim case UninitUse::Always: 868261991Sdim S.Diag(Use.getUser()->getLocStart(), diag::warn_uninit_var) 869261991Sdim << VD->getDeclName() << IsCapturedByBlock 870261991Sdim << Use.getUser()->getSourceRange(); 871261991Sdim return; 872261991Sdim 873261991Sdim case UninitUse::AfterDecl: 874261991Sdim case UninitUse::AfterCall: 875261991Sdim S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var) 876261991Sdim << VD->getDeclName() << IsCapturedByBlock 877261991Sdim << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5) 878261991Sdim << const_cast<DeclContext*>(VD->getLexicalDeclContext()) 879261991Sdim << VD->getSourceRange(); 880261991Sdim S.Diag(Use.getUser()->getLocStart(), diag::note_uninit_var_use) 881261991Sdim << IsCapturedByBlock << Use.getUser()->getSourceRange(); 882261991Sdim return; 883261991Sdim 884261991Sdim case UninitUse::Maybe: 885261991Sdim case UninitUse::Sometimes: 886261991Sdim // Carry on to report sometimes-uninitialized branches, if possible, 887261991Sdim // or a 'may be used uninitialized' diagnostic otherwise. 888261991Sdim break; 889261991Sdim } 890261991Sdim 891239462Sdim // Diagnose each branch which leads to a sometimes-uninitialized use. 892239462Sdim for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end(); 893239462Sdim I != E; ++I) { 894239462Sdim assert(Use.getKind() == UninitUse::Sometimes); 895239462Sdim 896239462Sdim const Expr *User = Use.getUser(); 897239462Sdim const Stmt *Term = I->Terminator; 898239462Sdim 899239462Sdim // Information used when building the diagnostic. 900239462Sdim unsigned DiagKind; 901243830Sdim StringRef Str; 902239462Sdim SourceRange Range; 903239462Sdim 904249423Sdim // FixIts to suppress the diagnostic by removing the dead condition. 905239462Sdim // For all binary terminators, branch 0 is taken if the condition is true, 906239462Sdim // and branch 1 is taken if the condition is false. 907239462Sdim int RemoveDiagKind = -1; 908239462Sdim const char *FixitStr = 909239462Sdim S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false") 910239462Sdim : (I->Output ? "1" : "0"); 911239462Sdim FixItHint Fixit1, Fixit2; 912239462Sdim 913261991Sdim switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) { 914239462Sdim default: 915239462Sdim // Don't know how to report this. Just fall back to 'may be used 916261991Sdim // uninitialized'. FIXME: Can this happen? 917239462Sdim continue; 918239462Sdim 919239462Sdim // "condition is true / condition is false". 920239462Sdim case Stmt::IfStmtClass: { 921239462Sdim const IfStmt *IS = cast<IfStmt>(Term); 922239462Sdim DiagKind = 0; 923239462Sdim Str = "if"; 924239462Sdim Range = IS->getCond()->getSourceRange(); 925239462Sdim RemoveDiagKind = 0; 926239462Sdim CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), 927239462Sdim I->Output, Fixit1, Fixit2); 928239462Sdim break; 929239462Sdim } 930239462Sdim case Stmt::ConditionalOperatorClass: { 931239462Sdim const ConditionalOperator *CO = cast<ConditionalOperator>(Term); 932239462Sdim DiagKind = 0; 933239462Sdim Str = "?:"; 934239462Sdim Range = CO->getCond()->getSourceRange(); 935239462Sdim RemoveDiagKind = 0; 936239462Sdim CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), 937239462Sdim I->Output, Fixit1, Fixit2); 938239462Sdim break; 939239462Sdim } 940239462Sdim case Stmt::BinaryOperatorClass: { 941239462Sdim const BinaryOperator *BO = cast<BinaryOperator>(Term); 942239462Sdim if (!BO->isLogicalOp()) 943239462Sdim continue; 944239462Sdim DiagKind = 0; 945239462Sdim Str = BO->getOpcodeStr(); 946239462Sdim Range = BO->getLHS()->getSourceRange(); 947239462Sdim RemoveDiagKind = 0; 948239462Sdim if ((BO->getOpcode() == BO_LAnd && I->Output) || 949239462Sdim (BO->getOpcode() == BO_LOr && !I->Output)) 950239462Sdim // true && y -> y, false || y -> y. 951239462Sdim Fixit1 = FixItHint::CreateRemoval(SourceRange(BO->getLocStart(), 952239462Sdim BO->getOperatorLoc())); 953239462Sdim else 954239462Sdim // false && y -> false, true || y -> true. 955239462Sdim Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr); 956239462Sdim break; 957239462Sdim } 958239462Sdim 959239462Sdim // "loop is entered / loop is exited". 960239462Sdim case Stmt::WhileStmtClass: 961239462Sdim DiagKind = 1; 962239462Sdim Str = "while"; 963239462Sdim Range = cast<WhileStmt>(Term)->getCond()->getSourceRange(); 964239462Sdim RemoveDiagKind = 1; 965239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 966239462Sdim break; 967239462Sdim case Stmt::ForStmtClass: 968239462Sdim DiagKind = 1; 969239462Sdim Str = "for"; 970239462Sdim Range = cast<ForStmt>(Term)->getCond()->getSourceRange(); 971239462Sdim RemoveDiagKind = 1; 972239462Sdim if (I->Output) 973239462Sdim Fixit1 = FixItHint::CreateRemoval(Range); 974239462Sdim else 975239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 976239462Sdim break; 977261991Sdim case Stmt::CXXForRangeStmtClass: 978261991Sdim if (I->Output == 1) { 979261991Sdim // The use occurs if a range-based for loop's body never executes. 980261991Sdim // That may be impossible, and there's no syntactic fix for this, 981261991Sdim // so treat it as a 'may be uninitialized' case. 982261991Sdim continue; 983261991Sdim } 984261991Sdim DiagKind = 1; 985261991Sdim Str = "for"; 986261991Sdim Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange(); 987261991Sdim break; 988239462Sdim 989239462Sdim // "condition is true / loop is exited". 990239462Sdim case Stmt::DoStmtClass: 991239462Sdim DiagKind = 2; 992239462Sdim Str = "do"; 993239462Sdim Range = cast<DoStmt>(Term)->getCond()->getSourceRange(); 994239462Sdim RemoveDiagKind = 1; 995239462Sdim Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 996239462Sdim break; 997239462Sdim 998239462Sdim // "switch case is taken". 999239462Sdim case Stmt::CaseStmtClass: 1000239462Sdim DiagKind = 3; 1001239462Sdim Str = "case"; 1002239462Sdim Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange(); 1003239462Sdim break; 1004239462Sdim case Stmt::DefaultStmtClass: 1005239462Sdim DiagKind = 3; 1006239462Sdim Str = "default"; 1007239462Sdim Range = cast<DefaultStmt>(Term)->getDefaultLoc(); 1008239462Sdim break; 1009239462Sdim } 1010239462Sdim 1011239462Sdim S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var) 1012239462Sdim << VD->getDeclName() << IsCapturedByBlock << DiagKind 1013239462Sdim << Str << I->Output << Range; 1014239462Sdim S.Diag(User->getLocStart(), diag::note_uninit_var_use) 1015239462Sdim << IsCapturedByBlock << User->getSourceRange(); 1016239462Sdim if (RemoveDiagKind != -1) 1017239462Sdim S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond) 1018239462Sdim << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2; 1019239462Sdim 1020239462Sdim Diagnosed = true; 1021239462Sdim } 1022239462Sdim 1023239462Sdim if (!Diagnosed) 1024261991Sdim S.Diag(Use.getUser()->getLocStart(), diag::warn_maybe_uninit_var) 1025239462Sdim << VD->getDeclName() << IsCapturedByBlock 1026239462Sdim << Use.getUser()->getSourceRange(); 1027239462Sdim} 1028239462Sdim 1029221345Sdim/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an 1030221345Sdim/// uninitialized variable. This manages the different forms of diagnostic 1031221345Sdim/// emitted for particular types of uses. Returns true if the use was diagnosed 1032239462Sdim/// as a warning. If a particular use is one we omit warnings for, returns 1033221345Sdim/// false. 1034221345Sdimstatic bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, 1035239462Sdim const UninitUse &Use, 1036226633Sdim bool alwaysReportSelfInit = false) { 1037239462Sdim if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) { 1038239462Sdim // Inspect the initializer of the variable declaration which is 1039239462Sdim // being referenced prior to its initialization. We emit 1040239462Sdim // specialized diagnostics for self-initialization, and we 1041239462Sdim // specifically avoid warning about self references which take the 1042239462Sdim // form of: 1043239462Sdim // 1044239462Sdim // int x = x; 1045239462Sdim // 1046239462Sdim // This is used to indicate to GCC that 'x' is intentionally left 1047239462Sdim // uninitialized. Proven code paths which access 'x' in 1048239462Sdim // an uninitialized state after this will still warn. 1049239462Sdim if (const Expr *Initializer = VD->getInit()) { 1050239462Sdim if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) 1051239462Sdim return false; 1052221345Sdim 1053239462Sdim ContainsReference CR(S.Context, DRE); 1054288943Sdim CR.Visit(Initializer); 1055239462Sdim if (CR.doesContainReference()) { 1056221345Sdim S.Diag(DRE->getLocStart(), 1057221345Sdim diag::warn_uninit_self_reference_in_init) 1058239462Sdim << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); 1059239462Sdim return true; 1060221345Sdim } 1061221345Sdim } 1062239462Sdim 1063239462Sdim DiagUninitUse(S, VD, Use, false); 1064221345Sdim } else { 1065239462Sdim const BlockExpr *BE = cast<BlockExpr>(Use.getUser()); 1066239462Sdim if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) 1067239462Sdim S.Diag(BE->getLocStart(), 1068239462Sdim diag::warn_uninit_byref_blockvar_captured_by_block) 1069234353Sdim << VD->getDeclName(); 1070234353Sdim else 1071239462Sdim DiagUninitUse(S, VD, Use, true); 1072221345Sdim } 1073221345Sdim 1074221345Sdim // Report where the variable was declared when the use wasn't within 1075226633Sdim // the initializer of that declaration & we didn't already suggest 1076226633Sdim // an initialization fixit. 1077239462Sdim if (!SuggestInitializationFixit(S, VD)) 1078309124Sdim S.Diag(VD->getLocStart(), diag::note_var_declared_here) 1079221345Sdim << VD->getDeclName(); 1080221345Sdim 1081221345Sdim return true; 1082221345Sdim} 1083221345Sdim 1084239462Sdimnamespace { 1085239462Sdim class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> { 1086239462Sdim public: 1087239462Sdim FallthroughMapper(Sema &S) 1088239462Sdim : FoundSwitchStatements(false), 1089239462Sdim S(S) { 1090239462Sdim } 1091221345Sdim 1092239462Sdim bool foundSwitchStatements() const { return FoundSwitchStatements; } 1093239462Sdim 1094239462Sdim void markFallthroughVisited(const AttributedStmt *Stmt) { 1095239462Sdim bool Found = FallthroughStmts.erase(Stmt); 1096239462Sdim assert(Found); 1097239462Sdim (void)Found; 1098239462Sdim } 1099239462Sdim 1100239462Sdim typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts; 1101239462Sdim 1102239462Sdim const AttrStmts &getFallthroughStmts() const { 1103239462Sdim return FallthroughStmts; 1104239462Sdim } 1105239462Sdim 1106249423Sdim void fillReachableBlocks(CFG *Cfg) { 1107249423Sdim assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); 1108249423Sdim std::deque<const CFGBlock *> BlockQueue; 1109249423Sdim 1110249423Sdim ReachableBlocks.insert(&Cfg->getEntry()); 1111249423Sdim BlockQueue.push_back(&Cfg->getEntry()); 1112249423Sdim // Mark all case blocks reachable to avoid problems with switching on 1113249423Sdim // constants, covered enums, etc. 1114249423Sdim // These blocks can contain fall-through annotations, and we don't want to 1115249423Sdim // issue a warn_fallthrough_attr_unreachable for them. 1116276479Sdim for (const auto *B : *Cfg) { 1117249423Sdim const Stmt *L = B->getLabel(); 1118280031Sdim if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second) 1119249423Sdim BlockQueue.push_back(B); 1120249423Sdim } 1121249423Sdim 1122249423Sdim while (!BlockQueue.empty()) { 1123249423Sdim const CFGBlock *P = BlockQueue.front(); 1124249423Sdim BlockQueue.pop_front(); 1125249423Sdim for (CFGBlock::const_succ_iterator I = P->succ_begin(), 1126249423Sdim E = P->succ_end(); 1127249423Sdim I != E; ++I) { 1128280031Sdim if (*I && ReachableBlocks.insert(*I).second) 1129249423Sdim BlockQueue.push_back(*I); 1130249423Sdim } 1131249423Sdim } 1132249423Sdim } 1133249423Sdim 1134321369Sdim bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt, 1135321369Sdim bool IsTemplateInstantiation) { 1136249423Sdim assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); 1137249423Sdim 1138239462Sdim int UnannotatedCnt = 0; 1139239462Sdim AnnotatedCnt = 0; 1140239462Sdim 1141276479Sdim std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end()); 1142239462Sdim while (!BlockQueue.empty()) { 1143239462Sdim const CFGBlock *P = BlockQueue.front(); 1144239462Sdim BlockQueue.pop_front(); 1145276479Sdim if (!P) continue; 1146239462Sdim 1147239462Sdim const Stmt *Term = P->getTerminator(); 1148239462Sdim if (Term && isa<SwitchStmt>(Term)) 1149239462Sdim continue; // Switch statement, good. 1150239462Sdim 1151239462Sdim const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel()); 1152239462Sdim if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) 1153239462Sdim continue; // Previous case label has no statements, good. 1154239462Sdim 1155249423Sdim const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel()); 1156249423Sdim if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) 1157249423Sdim continue; // Case label is preceded with a normal label, good. 1158249423Sdim 1159249423Sdim if (!ReachableBlocks.count(P)) { 1160249423Sdim for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(), 1161249423Sdim ElemEnd = P->rend(); 1162249423Sdim ElemIt != ElemEnd; ++ElemIt) { 1163249423Sdim if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) { 1164239462Sdim if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { 1165321369Sdim // Don't issue a warning for an unreachable fallthrough 1166321369Sdim // attribute in template instantiations as it may not be 1167321369Sdim // unreachable in all instantiations of the template. 1168321369Sdim if (!IsTemplateInstantiation) 1169321369Sdim S.Diag(AS->getLocStart(), 1170321369Sdim diag::warn_fallthrough_attr_unreachable); 1171239462Sdim markFallthroughVisited(AS); 1172239462Sdim ++AnnotatedCnt; 1173249423Sdim break; 1174239462Sdim } 1175239462Sdim // Don't care about other unreachable statements. 1176239462Sdim } 1177239462Sdim } 1178239462Sdim // If there are no unreachable statements, this may be a special 1179239462Sdim // case in CFG: 1180239462Sdim // case X: { 1181239462Sdim // A a; // A has a destructor. 1182239462Sdim // break; 1183239462Sdim // } 1184239462Sdim // // <<<< This place is represented by a 'hanging' CFG block. 1185239462Sdim // case Y: 1186239462Sdim continue; 1187239462Sdim } 1188239462Sdim 1189239462Sdim const Stmt *LastStmt = getLastStmt(*P); 1190239462Sdim if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) { 1191239462Sdim markFallthroughVisited(AS); 1192239462Sdim ++AnnotatedCnt; 1193239462Sdim continue; // Fallthrough annotation, good. 1194239462Sdim } 1195239462Sdim 1196239462Sdim if (!LastStmt) { // This block contains no executable statements. 1197239462Sdim // Traverse its predecessors. 1198239462Sdim std::copy(P->pred_begin(), P->pred_end(), 1199239462Sdim std::back_inserter(BlockQueue)); 1200239462Sdim continue; 1201239462Sdim } 1202239462Sdim 1203239462Sdim ++UnannotatedCnt; 1204239462Sdim } 1205239462Sdim return !!UnannotatedCnt; 1206239462Sdim } 1207239462Sdim 1208239462Sdim // RecursiveASTVisitor setup. 1209239462Sdim bool shouldWalkTypesOfTypeLocs() const { return false; } 1210239462Sdim 1211239462Sdim bool VisitAttributedStmt(AttributedStmt *S) { 1212239462Sdim if (asFallThroughAttr(S)) 1213239462Sdim FallthroughStmts.insert(S); 1214239462Sdim return true; 1215239462Sdim } 1216239462Sdim 1217239462Sdim bool VisitSwitchStmt(SwitchStmt *S) { 1218239462Sdim FoundSwitchStatements = true; 1219239462Sdim return true; 1220239462Sdim } 1221239462Sdim 1222249423Sdim // We don't want to traverse local type declarations. We analyze their 1223249423Sdim // methods separately. 1224249423Sdim bool TraverseDecl(Decl *D) { return true; } 1225249423Sdim 1226276479Sdim // We analyze lambda bodies separately. Skip them here. 1227276479Sdim bool TraverseLambdaBody(LambdaExpr *LE) { return true; } 1228276479Sdim 1229239462Sdim private: 1230239462Sdim 1231239462Sdim static const AttributedStmt *asFallThroughAttr(const Stmt *S) { 1232239462Sdim if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) { 1233239462Sdim if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs())) 1234239462Sdim return AS; 1235239462Sdim } 1236276479Sdim return nullptr; 1237239462Sdim } 1238239462Sdim 1239239462Sdim static const Stmt *getLastStmt(const CFGBlock &B) { 1240239462Sdim if (const Stmt *Term = B.getTerminator()) 1241239462Sdim return Term; 1242239462Sdim for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(), 1243239462Sdim ElemEnd = B.rend(); 1244239462Sdim ElemIt != ElemEnd; ++ElemIt) { 1245249423Sdim if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) 1246239462Sdim return CS->getStmt(); 1247239462Sdim } 1248239462Sdim // Workaround to detect a statement thrown out by CFGBuilder: 1249239462Sdim // case X: {} case Y: 1250239462Sdim // case X: ; case Y: 1251239462Sdim if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel())) 1252239462Sdim if (!isa<SwitchCase>(SW->getSubStmt())) 1253239462Sdim return SW->getSubStmt(); 1254239462Sdim 1255276479Sdim return nullptr; 1256239462Sdim } 1257239462Sdim 1258239462Sdim bool FoundSwitchStatements; 1259239462Sdim AttrStmts FallthroughStmts; 1260239462Sdim Sema &S; 1261249423Sdim llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks; 1262239462Sdim }; 1263296417Sdim} // anonymous namespace 1264239462Sdim 1265309124Sdimstatic StringRef getFallthroughAttrSpelling(Preprocessor &PP, 1266309124Sdim SourceLocation Loc) { 1267309124Sdim TokenValue FallthroughTokens[] = { 1268309124Sdim tok::l_square, tok::l_square, 1269309124Sdim PP.getIdentifierInfo("fallthrough"), 1270309124Sdim tok::r_square, tok::r_square 1271309124Sdim }; 1272309124Sdim 1273309124Sdim TokenValue ClangFallthroughTokens[] = { 1274309124Sdim tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), 1275309124Sdim tok::coloncolon, PP.getIdentifierInfo("fallthrough"), 1276309124Sdim tok::r_square, tok::r_square 1277309124Sdim }; 1278309124Sdim 1279309124Sdim bool PreferClangAttr = !PP.getLangOpts().CPlusPlus1z; 1280309124Sdim 1281309124Sdim StringRef MacroName; 1282309124Sdim if (PreferClangAttr) 1283309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1284309124Sdim if (MacroName.empty()) 1285309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); 1286309124Sdim if (MacroName.empty() && !PreferClangAttr) 1287309124Sdim MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1288309124Sdim if (MacroName.empty()) 1289309124Sdim MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]"; 1290309124Sdim return MacroName; 1291309124Sdim} 1292309124Sdim 1293239462Sdimstatic void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, 1294239462Sdim bool PerFunction) { 1295243830Sdim // Only perform this analysis when using C++11. There is no good workflow 1296243830Sdim // for this warning when not using C++11. There is no good way to silence 1297243830Sdim // the warning (no attribute is available) unless we are using C++11's support 1298243830Sdim // for generalized attributes. Once could use pragmas to silence the warning, 1299243830Sdim // but as a general solution that is gross and not in the spirit of this 1300243830Sdim // warning. 1301243830Sdim // 1302243830Sdim // NOTE: This an intermediate solution. There are on-going discussions on 1303243830Sdim // how to properly support this warning outside of C++11 with an annotation. 1304249423Sdim if (!AC.getASTContext().getLangOpts().CPlusPlus11) 1305243830Sdim return; 1306243830Sdim 1307239462Sdim FallthroughMapper FM(S); 1308239462Sdim FM.TraverseStmt(AC.getBody()); 1309239462Sdim 1310239462Sdim if (!FM.foundSwitchStatements()) 1311239462Sdim return; 1312239462Sdim 1313239462Sdim if (PerFunction && FM.getFallthroughStmts().empty()) 1314239462Sdim return; 1315239462Sdim 1316239462Sdim CFG *Cfg = AC.getCFG(); 1317239462Sdim 1318239462Sdim if (!Cfg) 1319239462Sdim return; 1320239462Sdim 1321249423Sdim FM.fillReachableBlocks(Cfg); 1322239462Sdim 1323296417Sdim for (const CFGBlock *B : llvm::reverse(*Cfg)) { 1324249423Sdim const Stmt *Label = B->getLabel(); 1325239462Sdim 1326239462Sdim if (!Label || !isa<SwitchCase>(Label)) 1327239462Sdim continue; 1328239462Sdim 1329249423Sdim int AnnotatedCnt; 1330249423Sdim 1331321369Sdim bool IsTemplateInstantiation = false; 1332321369Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl())) 1333321369Sdim IsTemplateInstantiation = Function->isTemplateInstantiation(); 1334321369Sdim if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt, 1335321369Sdim IsTemplateInstantiation)) 1336239462Sdim continue; 1337239462Sdim 1338239462Sdim S.Diag(Label->getLocStart(), 1339239462Sdim PerFunction ? diag::warn_unannotated_fallthrough_per_function 1340239462Sdim : diag::warn_unannotated_fallthrough); 1341239462Sdim 1342239462Sdim if (!AnnotatedCnt) { 1343239462Sdim SourceLocation L = Label->getLocStart(); 1344239462Sdim if (L.isMacroID()) 1345239462Sdim continue; 1346249423Sdim if (S.getLangOpts().CPlusPlus11) { 1347249423Sdim const Stmt *Term = B->getTerminator(); 1348249423Sdim // Skip empty cases. 1349249423Sdim while (B->empty() && !Term && B->succ_size() == 1) { 1350249423Sdim B = *B->succ_begin(); 1351249423Sdim Term = B->getTerminator(); 1352249423Sdim } 1353249423Sdim if (!(B->empty() && Term && isa<BreakStmt>(Term))) { 1354243830Sdim Preprocessor &PP = S.getPreprocessor(); 1355309124Sdim StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); 1356243830Sdim SmallString<64> TextToInsert(AnnotationSpelling); 1357243830Sdim TextToInsert += "; "; 1358239462Sdim S.Diag(L, diag::note_insert_fallthrough_fixit) << 1359243830Sdim AnnotationSpelling << 1360243830Sdim FixItHint::CreateInsertion(L, TextToInsert); 1361239462Sdim } 1362239462Sdim } 1363239462Sdim S.Diag(L, diag::note_insert_break_fixit) << 1364239462Sdim FixItHint::CreateInsertion(L, "break; "); 1365239462Sdim } 1366239462Sdim } 1367239462Sdim 1368276479Sdim for (const auto *F : FM.getFallthroughStmts()) 1369309124Sdim S.Diag(F->getLocStart(), diag::err_fallthrough_attr_invalid_placement); 1370239462Sdim} 1371239462Sdim 1372243830Sdimstatic bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, 1373243830Sdim const Stmt *S) { 1374243830Sdim assert(S); 1375243830Sdim 1376243830Sdim do { 1377243830Sdim switch (S->getStmtClass()) { 1378243830Sdim case Stmt::ForStmtClass: 1379243830Sdim case Stmt::WhileStmtClass: 1380243830Sdim case Stmt::CXXForRangeStmtClass: 1381243830Sdim case Stmt::ObjCForCollectionStmtClass: 1382243830Sdim return true; 1383243830Sdim case Stmt::DoStmtClass: { 1384243830Sdim const Expr *Cond = cast<DoStmt>(S)->getCond(); 1385243830Sdim llvm::APSInt Val; 1386243830Sdim if (!Cond->EvaluateAsInt(Val, Ctx)) 1387243830Sdim return true; 1388243830Sdim return Val.getBoolValue(); 1389243830Sdim } 1390243830Sdim default: 1391243830Sdim break; 1392243830Sdim } 1393243830Sdim } while ((S = PM.getParent(S))); 1394243830Sdim 1395243830Sdim return false; 1396243830Sdim} 1397243830Sdim 1398243830Sdimstatic void diagnoseRepeatedUseOfWeak(Sema &S, 1399243830Sdim const sema::FunctionScopeInfo *CurFn, 1400243830Sdim const Decl *D, 1401243830Sdim const ParentMap &PM) { 1402243830Sdim typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy; 1403243830Sdim typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap; 1404243830Sdim typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector; 1405276479Sdim typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator> 1406276479Sdim StmtUsesPair; 1407243830Sdim 1408243830Sdim ASTContext &Ctx = S.getASTContext(); 1409243830Sdim 1410243830Sdim const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses(); 1411243830Sdim 1412243830Sdim // Extract all weak objects that are referenced more than once. 1413243830Sdim SmallVector<StmtUsesPair, 8> UsesByStmt; 1414243830Sdim for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end(); 1415243830Sdim I != E; ++I) { 1416243830Sdim const WeakUseVector &Uses = I->second; 1417243830Sdim 1418243830Sdim // Find the first read of the weak object. 1419243830Sdim WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); 1420243830Sdim for ( ; UI != UE; ++UI) { 1421243830Sdim if (UI->isUnsafe()) 1422243830Sdim break; 1423243830Sdim } 1424243830Sdim 1425243830Sdim // If there were only writes to this object, don't warn. 1426243830Sdim if (UI == UE) 1427243830Sdim continue; 1428243830Sdim 1429243830Sdim // If there was only one read, followed by any number of writes, and the 1430243830Sdim // read is not within a loop, don't warn. Additionally, don't warn in a 1431243830Sdim // loop if the base object is a local variable -- local variables are often 1432243830Sdim // changed in loops. 1433243830Sdim if (UI == Uses.begin()) { 1434243830Sdim WeakUseVector::const_iterator UI2 = UI; 1435243830Sdim for (++UI2; UI2 != UE; ++UI2) 1436243830Sdim if (UI2->isUnsafe()) 1437243830Sdim break; 1438243830Sdim 1439243830Sdim if (UI2 == UE) { 1440243830Sdim if (!isInLoop(Ctx, PM, UI->getUseExpr())) 1441243830Sdim continue; 1442243830Sdim 1443243830Sdim const WeakObjectProfileTy &Profile = I->first; 1444243830Sdim if (!Profile.isExactProfile()) 1445243830Sdim continue; 1446243830Sdim 1447243830Sdim const NamedDecl *Base = Profile.getBase(); 1448243830Sdim if (!Base) 1449243830Sdim Base = Profile.getProperty(); 1450243830Sdim assert(Base && "A profile always has a base or property."); 1451243830Sdim 1452243830Sdim if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base)) 1453243830Sdim if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base)) 1454243830Sdim continue; 1455243830Sdim } 1456243830Sdim } 1457243830Sdim 1458243830Sdim UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I)); 1459243830Sdim } 1460243830Sdim 1461243830Sdim if (UsesByStmt.empty()) 1462243830Sdim return; 1463243830Sdim 1464243830Sdim // Sort by first use so that we emit the warnings in a deterministic order. 1465276479Sdim SourceManager &SM = S.getSourceManager(); 1466243830Sdim std::sort(UsesByStmt.begin(), UsesByStmt.end(), 1467276479Sdim [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { 1468276479Sdim return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(), 1469276479Sdim RHS.first->getLocStart()); 1470276479Sdim }); 1471243830Sdim 1472243830Sdim // Classify the current code body for better warning text. 1473243830Sdim // This enum should stay in sync with the cases in 1474243830Sdim // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 1475243830Sdim // FIXME: Should we use a common classification enum and the same set of 1476243830Sdim // possibilities all throughout Sema? 1477243830Sdim enum { 1478243830Sdim Function, 1479243830Sdim Method, 1480243830Sdim Block, 1481243830Sdim Lambda 1482243830Sdim } FunctionKind; 1483243830Sdim 1484243830Sdim if (isa<sema::BlockScopeInfo>(CurFn)) 1485243830Sdim FunctionKind = Block; 1486243830Sdim else if (isa<sema::LambdaScopeInfo>(CurFn)) 1487243830Sdim FunctionKind = Lambda; 1488243830Sdim else if (isa<ObjCMethodDecl>(D)) 1489243830Sdim FunctionKind = Method; 1490243830Sdim else 1491243830Sdim FunctionKind = Function; 1492243830Sdim 1493243830Sdim // Iterate through the sorted problems and emit warnings for each. 1494276479Sdim for (const auto &P : UsesByStmt) { 1495276479Sdim const Stmt *FirstRead = P.first; 1496276479Sdim const WeakObjectProfileTy &Key = P.second->first; 1497276479Sdim const WeakUseVector &Uses = P.second->second; 1498243830Sdim 1499243830Sdim // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy 1500243830Sdim // may not contain enough information to determine that these are different 1501243830Sdim // properties. We can only be 100% sure of a repeated use in certain cases, 1502243830Sdim // and we adjust the diagnostic kind accordingly so that the less certain 1503243830Sdim // case can be turned off if it is too noisy. 1504243830Sdim unsigned DiagKind; 1505243830Sdim if (Key.isExactProfile()) 1506243830Sdim DiagKind = diag::warn_arc_repeated_use_of_weak; 1507243830Sdim else 1508243830Sdim DiagKind = diag::warn_arc_possible_repeated_use_of_weak; 1509243830Sdim 1510243830Sdim // Classify the weak object being accessed for better warning text. 1511243830Sdim // This enum should stay in sync with the cases in 1512243830Sdim // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 1513243830Sdim enum { 1514243830Sdim Variable, 1515243830Sdim Property, 1516243830Sdim ImplicitProperty, 1517243830Sdim Ivar 1518243830Sdim } ObjectKind; 1519243830Sdim 1520309124Sdim const NamedDecl *KeyProp = Key.getProperty(); 1521309124Sdim if (isa<VarDecl>(KeyProp)) 1522243830Sdim ObjectKind = Variable; 1523309124Sdim else if (isa<ObjCPropertyDecl>(KeyProp)) 1524243830Sdim ObjectKind = Property; 1525309124Sdim else if (isa<ObjCMethodDecl>(KeyProp)) 1526243830Sdim ObjectKind = ImplicitProperty; 1527309124Sdim else if (isa<ObjCIvarDecl>(KeyProp)) 1528243830Sdim ObjectKind = Ivar; 1529243830Sdim else 1530243830Sdim llvm_unreachable("Unexpected weak object kind!"); 1531243830Sdim 1532309124Sdim // Do not warn about IBOutlet weak property receivers being set to null 1533309124Sdim // since they are typically only used from the main thread. 1534309124Sdim if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp)) 1535309124Sdim if (Prop->hasAttr<IBOutletAttr>()) 1536309124Sdim continue; 1537309124Sdim 1538243830Sdim // Show the first time the object was read. 1539243830Sdim S.Diag(FirstRead->getLocStart(), DiagKind) 1540309124Sdim << int(ObjectKind) << KeyProp << int(FunctionKind) 1541243830Sdim << FirstRead->getSourceRange(); 1542243830Sdim 1543243830Sdim // Print all the other accesses as notes. 1544276479Sdim for (const auto &Use : Uses) { 1545276479Sdim if (Use.getUseExpr() == FirstRead) 1546243830Sdim continue; 1547276479Sdim S.Diag(Use.getUseExpr()->getLocStart(), 1548243830Sdim diag::note_arc_weak_also_accessed_here) 1549276479Sdim << Use.getUseExpr()->getSourceRange(); 1550243830Sdim } 1551243830Sdim } 1552243830Sdim} 1553243830Sdim 1554243830Sdimnamespace { 1555218893Sdimclass UninitValsDiagReporter : public UninitVariablesHandler { 1556218893Sdim Sema &S; 1557226633Sdim typedef SmallVector<UninitUse, 2> UsesVec; 1558261991Sdim typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType; 1559249423Sdim // Prefer using MapVector to DenseMap, so that iteration order will be 1560249423Sdim // the same as insertion order. This is needed to obtain a deterministic 1561249423Sdim // order of diagnostics when calling flushDiagnostics(). 1562249423Sdim typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; 1563296417Sdim UsesMap uses; 1564218893Sdim 1565218893Sdimpublic: 1566296417Sdim UninitValsDiagReporter(Sema &S) : S(S) {} 1567288943Sdim ~UninitValsDiagReporter() override { flushDiagnostics(); } 1568226633Sdim 1569249423Sdim MappedType &getUses(const VarDecl *vd) { 1570296417Sdim MappedType &V = uses[vd]; 1571261991Sdim if (!V.getPointer()) 1572261991Sdim V.setPointer(new UsesVec()); 1573226633Sdim return V; 1574218893Sdim } 1575276479Sdim 1576276479Sdim void handleUseOfUninitVariable(const VarDecl *vd, 1577276479Sdim const UninitUse &use) override { 1578261991Sdim getUses(vd).getPointer()->push_back(use); 1579226633Sdim } 1580226633Sdim 1581276479Sdim void handleSelfInit(const VarDecl *vd) override { 1582261991Sdim getUses(vd).setInt(true); 1583226633Sdim } 1584226633Sdim 1585218893Sdim void flushDiagnostics() { 1586296417Sdim for (const auto &P : uses) { 1587276479Sdim const VarDecl *vd = P.first; 1588276479Sdim const MappedType &V = P.second; 1589218893Sdim 1590261991Sdim UsesVec *vec = V.getPointer(); 1591261991Sdim bool hasSelfInit = V.getInt(); 1592218893Sdim 1593226633Sdim // Specially handle the case where we have uses of an uninitialized 1594226633Sdim // variable, but the root cause is an idiomatic self-init. We want 1595226633Sdim // to report the diagnostic at the self-init since that is the root cause. 1596234353Sdim if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) 1597239462Sdim DiagnoseUninitializedUse(S, vd, 1598239462Sdim UninitUse(vd->getInit()->IgnoreParenCasts(), 1599239462Sdim /* isAlwaysUninit */ true), 1600234353Sdim /* alwaysReportSelfInit */ true); 1601226633Sdim else { 1602226633Sdim // Sort the uses by their SourceLocations. While not strictly 1603226633Sdim // guaranteed to produce them in line/column order, this will provide 1604226633Sdim // a stable ordering. 1605276479Sdim std::sort(vec->begin(), vec->end(), 1606276479Sdim [](const UninitUse &a, const UninitUse &b) { 1607276479Sdim // Prefer a more confident report over a less confident one. 1608276479Sdim if (a.getKind() != b.getKind()) 1609276479Sdim return a.getKind() > b.getKind(); 1610276479Sdim return a.getUser()->getLocStart() < b.getUser()->getLocStart(); 1611276479Sdim }); 1612276479Sdim 1613276479Sdim for (const auto &U : *vec) { 1614239462Sdim // If we have self-init, downgrade all uses to 'may be uninitialized'. 1615276479Sdim UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U; 1616239462Sdim 1617239462Sdim if (DiagnoseUninitializedUse(S, vd, Use)) 1618226633Sdim // Skip further diagnostics for this variable. We try to warn only 1619226633Sdim // on the first point at which a variable is used uninitialized. 1620226633Sdim break; 1621218893Sdim } 1622218893Sdim } 1623226633Sdim 1624226633Sdim // Release the uses vector. 1625218893Sdim delete vec; 1626218893Sdim } 1627296417Sdim 1628296417Sdim uses.clear(); 1629218893Sdim } 1630234353Sdim 1631234353Sdimprivate: 1632234353Sdim static bool hasAlwaysUninitializedUse(const UsesVec* vec) { 1633276479Sdim return std::any_of(vec->begin(), vec->end(), [](const UninitUse &U) { 1634276479Sdim return U.getKind() == UninitUse::Always || 1635276479Sdim U.getKind() == UninitUse::AfterCall || 1636276479Sdim U.getKind() == UninitUse::AfterDecl; 1637276479Sdim }); 1638234353Sdim } 1639218893Sdim}; 1640296417Sdim} // anonymous namespace 1641218893Sdim 1642226633Sdimnamespace clang { 1643261991Sdimnamespace { 1644249423Sdimtypedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; 1645234353Sdimtypedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; 1646234353Sdimtypedef std::list<DelayedDiag> DiagList; 1647226633Sdim 1648226633Sdimstruct SortDiagBySourceLocation { 1649234353Sdim SourceManager &SM; 1650234353Sdim SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {} 1651226633Sdim 1652226633Sdim bool operator()(const DelayedDiag &left, const DelayedDiag &right) { 1653226633Sdim // Although this call will be slow, this is only called when outputting 1654226633Sdim // multiple warnings. 1655234353Sdim return SM.isBeforeInTranslationUnit(left.first.first, right.first.first); 1656226633Sdim } 1657226633Sdim}; 1658296417Sdim} // anonymous namespace 1659296417Sdim} // namespace clang 1660226633Sdim 1661261991Sdim//===----------------------------------------------------------------------===// 1662261991Sdim// -Wthread-safety 1663261991Sdim//===----------------------------------------------------------------------===// 1664261991Sdimnamespace clang { 1665280031Sdimnamespace threadSafety { 1666288943Sdimnamespace { 1667280031Sdimclass ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { 1668226633Sdim Sema &S; 1669226633Sdim DiagList Warnings; 1670234353Sdim SourceLocation FunLocation, FunEndLocation; 1671226633Sdim 1672280031Sdim const FunctionDecl *CurrentFunction; 1673280031Sdim bool Verbose; 1674280031Sdim 1675280031Sdim OptionalNotes getNotes() const { 1676280031Sdim if (Verbose && CurrentFunction) { 1677280031Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), 1678280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1679280031Sdim << CurrentFunction->getNameAsString()); 1680280031Sdim return OptionalNotes(1, FNote); 1681280031Sdim } 1682280031Sdim return OptionalNotes(); 1683280031Sdim } 1684280031Sdim 1685280031Sdim OptionalNotes getNotes(const PartialDiagnosticAt &Note) const { 1686280031Sdim OptionalNotes ONS(1, Note); 1687280031Sdim if (Verbose && CurrentFunction) { 1688280031Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), 1689280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1690280031Sdim << CurrentFunction->getNameAsString()); 1691288943Sdim ONS.push_back(std::move(FNote)); 1692280031Sdim } 1693280031Sdim return ONS; 1694280031Sdim } 1695280031Sdim 1696280031Sdim OptionalNotes getNotes(const PartialDiagnosticAt &Note1, 1697280031Sdim const PartialDiagnosticAt &Note2) const { 1698280031Sdim OptionalNotes ONS; 1699280031Sdim ONS.push_back(Note1); 1700280031Sdim ONS.push_back(Note2); 1701280031Sdim if (Verbose && CurrentFunction) { 1702280031Sdim PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), 1703280031Sdim S.PDiag(diag::note_thread_warning_in_fun) 1704280031Sdim << CurrentFunction->getNameAsString()); 1705288943Sdim ONS.push_back(std::move(FNote)); 1706280031Sdim } 1707280031Sdim return ONS; 1708280031Sdim } 1709280031Sdim 1710226633Sdim // Helper functions 1711276479Sdim void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName, 1712276479Sdim SourceLocation Loc) { 1713234353Sdim // Gracefully handle rare cases when the analysis can't get a more 1714234353Sdim // precise source location. 1715234353Sdim if (!Loc.isValid()) 1716234353Sdim Loc = FunLocation; 1717276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName); 1718288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1719226633Sdim } 1720226633Sdim 1721226633Sdim public: 1722234353Sdim ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) 1723280031Sdim : S(S), FunLocation(FL), FunEndLocation(FEL), 1724280031Sdim CurrentFunction(nullptr), Verbose(false) {} 1725226633Sdim 1726280031Sdim void setVerbose(bool b) { Verbose = b; } 1727280031Sdim 1728226633Sdim /// \brief Emit all buffered diagnostics in order of sourcelocation. 1729226633Sdim /// We need to output diagnostics produced while iterating through 1730226633Sdim /// the lockset in deterministic order, so this function orders diagnostics 1731226633Sdim /// and outputs them. 1732226633Sdim void emitDiagnostics() { 1733234353Sdim Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 1734276479Sdim for (const auto &Diag : Warnings) { 1735276479Sdim S.Diag(Diag.first.first, Diag.first.second); 1736276479Sdim for (const auto &Note : Diag.second) 1737276479Sdim S.Diag(Note.first, Note.second); 1738234353Sdim } 1739226633Sdim } 1740226633Sdim 1741276479Sdim void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override { 1742276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock) 1743276479Sdim << Loc); 1744288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1745226633Sdim } 1746280031Sdim 1747276479Sdim void handleUnmatchedUnlock(StringRef Kind, Name LockName, 1748276479Sdim SourceLocation Loc) override { 1749276479Sdim warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc); 1750226633Sdim } 1751280031Sdim 1752276479Sdim void handleIncorrectUnlockKind(StringRef Kind, Name LockName, 1753276479Sdim LockKind Expected, LockKind Received, 1754276479Sdim SourceLocation Loc) override { 1755276479Sdim if (Loc.isInvalid()) 1756276479Sdim Loc = FunLocation; 1757276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch) 1758276479Sdim << Kind << LockName << Received 1759276479Sdim << Expected); 1760288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1761226633Sdim } 1762280031Sdim 1763276479Sdim void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override { 1764276479Sdim warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc); 1765276479Sdim } 1766226633Sdim 1767276479Sdim void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, 1768276479Sdim SourceLocation LocLocked, 1769234353Sdim SourceLocation LocEndOfScope, 1770276479Sdim LockErrorKind LEK) override { 1771226633Sdim unsigned DiagID = 0; 1772226633Sdim switch (LEK) { 1773226633Sdim case LEK_LockedSomePredecessors: 1774234353Sdim DiagID = diag::warn_lock_some_predecessors; 1775226633Sdim break; 1776226633Sdim case LEK_LockedSomeLoopIterations: 1777226633Sdim DiagID = diag::warn_expecting_lock_held_on_loop; 1778226633Sdim break; 1779226633Sdim case LEK_LockedAtEndOfFunction: 1780226633Sdim DiagID = diag::warn_no_unlock; 1781226633Sdim break; 1782239462Sdim case LEK_NotLockedAtEndOfFunction: 1783239462Sdim DiagID = diag::warn_expecting_locked; 1784239462Sdim break; 1785226633Sdim } 1786234353Sdim if (LocEndOfScope.isInvalid()) 1787234353Sdim LocEndOfScope = FunEndLocation; 1788234353Sdim 1789276479Sdim PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind 1790276479Sdim << LockName); 1791251662Sdim if (LocLocked.isValid()) { 1792276479Sdim PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here) 1793276479Sdim << Kind); 1794288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1795251662Sdim return; 1796251662Sdim } 1797288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1798226633Sdim } 1799226633Sdim 1800276479Sdim void handleExclusiveAndShared(StringRef Kind, Name LockName, 1801276479Sdim SourceLocation Loc1, 1802276479Sdim SourceLocation Loc2) override { 1803276479Sdim PartialDiagnosticAt Warning(Loc1, 1804276479Sdim S.PDiag(diag::warn_lock_exclusive_and_shared) 1805276479Sdim << Kind << LockName); 1806276479Sdim PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) 1807276479Sdim << Kind << LockName); 1808288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1809226633Sdim } 1810226633Sdim 1811276479Sdim void handleNoMutexHeld(StringRef Kind, const NamedDecl *D, 1812276479Sdim ProtectedOperationKind POK, AccessKind AK, 1813276479Sdim SourceLocation Loc) override { 1814276479Sdim assert((POK == POK_VarAccess || POK == POK_VarDereference) && 1815276479Sdim "Only works for variables"); 1816226633Sdim unsigned DiagID = POK == POK_VarAccess? 1817226633Sdim diag::warn_variable_requires_any_lock: 1818226633Sdim diag::warn_var_deref_requires_any_lock; 1819234353Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) 1820243830Sdim << D->getNameAsString() << getLockKindFromAccessKind(AK)); 1821288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1822226633Sdim } 1823226633Sdim 1824276479Sdim void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, 1825276479Sdim ProtectedOperationKind POK, Name LockName, 1826276479Sdim LockKind LK, SourceLocation Loc, 1827276479Sdim Name *PossibleMatch) override { 1828226633Sdim unsigned DiagID = 0; 1829243830Sdim if (PossibleMatch) { 1830243830Sdim switch (POK) { 1831243830Sdim case POK_VarAccess: 1832243830Sdim DiagID = diag::warn_variable_requires_lock_precise; 1833243830Sdim break; 1834243830Sdim case POK_VarDereference: 1835243830Sdim DiagID = diag::warn_var_deref_requires_lock_precise; 1836243830Sdim break; 1837243830Sdim case POK_FunctionCall: 1838243830Sdim DiagID = diag::warn_fun_requires_lock_precise; 1839243830Sdim break; 1840280031Sdim case POK_PassByRef: 1841280031Sdim DiagID = diag::warn_guarded_pass_by_reference; 1842280031Sdim break; 1843280031Sdim case POK_PtPassByRef: 1844280031Sdim DiagID = diag::warn_pt_guarded_pass_by_reference; 1845280031Sdim break; 1846243830Sdim } 1847276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 1848276479Sdim << D->getNameAsString() 1849276479Sdim << LockName << LK); 1850243830Sdim PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) 1851276479Sdim << *PossibleMatch); 1852280031Sdim if (Verbose && POK == POK_VarAccess) { 1853280031Sdim PartialDiagnosticAt VNote(D->getLocation(), 1854280031Sdim S.PDiag(diag::note_guarded_by_declared_here) 1855280031Sdim << D->getNameAsString()); 1856288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote)); 1857280031Sdim } else 1858288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1859243830Sdim } else { 1860243830Sdim switch (POK) { 1861243830Sdim case POK_VarAccess: 1862243830Sdim DiagID = diag::warn_variable_requires_lock; 1863243830Sdim break; 1864243830Sdim case POK_VarDereference: 1865243830Sdim DiagID = diag::warn_var_deref_requires_lock; 1866243830Sdim break; 1867243830Sdim case POK_FunctionCall: 1868243830Sdim DiagID = diag::warn_fun_requires_lock; 1869243830Sdim break; 1870280031Sdim case POK_PassByRef: 1871280031Sdim DiagID = diag::warn_guarded_pass_by_reference; 1872280031Sdim break; 1873280031Sdim case POK_PtPassByRef: 1874280031Sdim DiagID = diag::warn_pt_guarded_pass_by_reference; 1875280031Sdim break; 1876243830Sdim } 1877276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 1878276479Sdim << D->getNameAsString() 1879276479Sdim << LockName << LK); 1880280031Sdim if (Verbose && POK == POK_VarAccess) { 1881280031Sdim PartialDiagnosticAt Note(D->getLocation(), 1882280031Sdim S.PDiag(diag::note_guarded_by_declared_here) 1883280031Sdim << D->getNameAsString()); 1884288943Sdim Warnings.emplace_back(std::move(Warning), getNotes(Note)); 1885280031Sdim } else 1886288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1887226633Sdim } 1888226633Sdim } 1889226633Sdim 1890288943Sdim void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, 1891288943Sdim SourceLocation Loc) override { 1892280031Sdim PartialDiagnosticAt Warning(Loc, 1893280031Sdim S.PDiag(diag::warn_acquire_requires_negative_cap) 1894280031Sdim << Kind << LockName << Neg); 1895288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1896280031Sdim } 1897280031Sdim 1898276479Sdim void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, 1899276479Sdim SourceLocation Loc) override { 1900276479Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex) 1901276479Sdim << Kind << FunName << LockName); 1902288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1903226633Sdim } 1904280031Sdim 1905288943Sdim void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name, 1906288943Sdim SourceLocation Loc) override { 1907288943Sdim PartialDiagnosticAt Warning(Loc, 1908288943Sdim S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name); 1909288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1910288943Sdim } 1911288943Sdim 1912288943Sdim void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override { 1913288943Sdim PartialDiagnosticAt Warning(Loc, 1914288943Sdim S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); 1915288943Sdim Warnings.emplace_back(std::move(Warning), getNotes()); 1916288943Sdim } 1917288943Sdim 1918280031Sdim void enterFunction(const FunctionDecl* FD) override { 1919280031Sdim CurrentFunction = FD; 1920280031Sdim } 1921280031Sdim 1922280031Sdim void leaveFunction(const FunctionDecl* FD) override { 1923296417Sdim CurrentFunction = nullptr; 1924280031Sdim } 1925226633Sdim}; 1926296417Sdim} // anonymous namespace 1927288943Sdim} // namespace threadSafety 1928288943Sdim} // namespace clang 1929280031Sdim 1930226633Sdim//===----------------------------------------------------------------------===// 1931261991Sdim// -Wconsumed 1932261991Sdim//===----------------------------------------------------------------------===// 1933261991Sdim 1934261991Sdimnamespace clang { 1935261991Sdimnamespace consumed { 1936261991Sdimnamespace { 1937261991Sdimclass ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { 1938261991Sdim 1939261991Sdim Sema &S; 1940261991Sdim DiagList Warnings; 1941261991Sdim 1942261991Sdimpublic: 1943288943Sdim 1944261991Sdim ConsumedWarningsHandler(Sema &S) : S(S) {} 1945276479Sdim 1946276479Sdim void emitDiagnostics() override { 1947261991Sdim Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 1948276479Sdim for (const auto &Diag : Warnings) { 1949276479Sdim S.Diag(Diag.first.first, Diag.first.second); 1950276479Sdim for (const auto &Note : Diag.second) 1951276479Sdim S.Diag(Note.first, Note.second); 1952261991Sdim } 1953261991Sdim } 1954276479Sdim 1955276479Sdim void warnLoopStateMismatch(SourceLocation Loc, 1956276479Sdim StringRef VariableName) override { 1957261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) << 1958261991Sdim VariableName); 1959288943Sdim 1960288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1961261991Sdim } 1962261991Sdim 1963261991Sdim void warnParamReturnTypestateMismatch(SourceLocation Loc, 1964261991Sdim StringRef VariableName, 1965261991Sdim StringRef ExpectedState, 1966276479Sdim StringRef ObservedState) override { 1967261991Sdim 1968261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1969261991Sdim diag::warn_param_return_typestate_mismatch) << VariableName << 1970261991Sdim ExpectedState << ObservedState); 1971288943Sdim 1972288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1973261991Sdim } 1974261991Sdim 1975261991Sdim void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 1976276479Sdim StringRef ObservedState) override { 1977261991Sdim 1978261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1979261991Sdim diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState); 1980288943Sdim 1981288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1982261991Sdim } 1983261991Sdim 1984261991Sdim void warnReturnTypestateForUnconsumableType(SourceLocation Loc, 1985276479Sdim StringRef TypeName) override { 1986261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1987261991Sdim diag::warn_return_typestate_for_unconsumable_type) << TypeName); 1988288943Sdim 1989288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1990261991Sdim } 1991261991Sdim 1992261991Sdim void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 1993276479Sdim StringRef ObservedState) override { 1994261991Sdim 1995261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 1996261991Sdim diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState); 1997288943Sdim 1998288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 1999261991Sdim } 2000261991Sdim 2001261991Sdim void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, 2002276479Sdim SourceLocation Loc) override { 2003261991Sdim 2004261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag( 2005261991Sdim diag::warn_use_of_temp_in_invalid_state) << MethodName << State); 2006288943Sdim 2007288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 2008261991Sdim } 2009261991Sdim 2010261991Sdim void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, 2011276479Sdim StringRef State, SourceLocation Loc) override { 2012261991Sdim 2013261991Sdim PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) << 2014261991Sdim MethodName << VariableName << State); 2015288943Sdim 2016288943Sdim Warnings.emplace_back(std::move(Warning), OptionalNotes()); 2017261991Sdim } 2018261991Sdim}; 2019296417Sdim} // anonymous namespace 2020296417Sdim} // namespace consumed 2021296417Sdim} // namespace clang 2022261991Sdim 2023261991Sdim//===----------------------------------------------------------------------===// 2024205408Srdivacky// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based 2025205408Srdivacky// warnings on a function, method, or block. 2026205408Srdivacky//===----------------------------------------------------------------------===// 2027205408Srdivacky 2028206084Srdivackyclang::sema::AnalysisBasedWarnings::Policy::Policy() { 2029206084Srdivacky enableCheckFallThrough = 1; 2030206084Srdivacky enableCheckUnreachable = 0; 2031226633Sdim enableThreadSafetyAnalysis = 0; 2032261991Sdim enableConsumedAnalysis = 0; 2033206084Srdivacky} 2034206084Srdivacky 2035276479Sdimstatic unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) { 2036276479Sdim return (unsigned)!D.isIgnored(diag, SourceLocation()); 2037276479Sdim} 2038276479Sdim 2039224145Sdimclang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) 2040224145Sdim : S(s), 2041224145Sdim NumFunctionsAnalyzed(0), 2042224145Sdim NumFunctionsWithBadCFGs(0), 2043224145Sdim NumCFGBlocks(0), 2044224145Sdim MaxCFGBlocksPerFunction(0), 2045224145Sdim NumUninitAnalysisFunctions(0), 2046224145Sdim NumUninitAnalysisVariables(0), 2047224145Sdim MaxUninitAnalysisVariablesPerFunction(0), 2048224145Sdim NumUninitAnalysisBlockVisits(0), 2049224145Sdim MaxUninitAnalysisBlockVisitsPerFunction(0) { 2050276479Sdim 2051276479Sdim using namespace diag; 2052226633Sdim DiagnosticsEngine &D = S.getDiagnostics(); 2053276479Sdim 2054276479Sdim DefaultPolicy.enableCheckUnreachable = 2055276479Sdim isEnabled(D, warn_unreachable) || 2056276479Sdim isEnabled(D, warn_unreachable_break) || 2057276479Sdim isEnabled(D, warn_unreachable_return) || 2058276479Sdim isEnabled(D, warn_unreachable_loop_increment); 2059276479Sdim 2060276479Sdim DefaultPolicy.enableThreadSafetyAnalysis = 2061276479Sdim isEnabled(D, warn_double_lock); 2062276479Sdim 2063276479Sdim DefaultPolicy.enableConsumedAnalysis = 2064276479Sdim isEnabled(D, warn_use_in_invalid_state); 2065205408Srdivacky} 2066205408Srdivacky 2067276479Sdimstatic void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { 2068276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) 2069219077Sdim S.Diag(D.Loc, D.PD); 2070219077Sdim} 2071219077Sdim 2072206084Srdivackyvoid clang::sema:: 2073206084SrdivackyAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 2074219077Sdim sema::FunctionScopeInfo *fscope, 2075219077Sdim const Decl *D, const BlockExpr *blkExpr) { 2076206084Srdivacky 2077205408Srdivacky // We avoid doing analysis-based warnings when there are errors for 2078205408Srdivacky // two reasons: 2079205408Srdivacky // (1) The CFGs often can't be constructed (if the body is invalid), so 2080205408Srdivacky // don't bother trying. 2081205408Srdivacky // (2) The code already has problems; running the analysis just takes more 2082205408Srdivacky // time. 2083226633Sdim DiagnosticsEngine &Diags = S.getDiagnostics(); 2084207619Srdivacky 2085206084Srdivacky // Do not do any analysis for declarations in system headers if we are 2086206084Srdivacky // going to just ignore them. 2087207619Srdivacky if (Diags.getSuppressSystemWarnings() && 2088206084Srdivacky S.SourceMgr.isInSystemHeader(D->getLocation())) 2089206084Srdivacky return; 2090206084Srdivacky 2091212904Sdim // For code in dependent contexts, we'll do this at instantiation time. 2092212904Sdim if (cast<DeclContext>(D)->isDependentContext()) 2093212904Sdim return; 2094205408Srdivacky 2095309124Sdim if (Diags.hasUncompilableErrorOccurred()) { 2096219077Sdim // Flush out any possibly unreachable diagnostics. 2097219077Sdim flushDiagnostics(S, fscope); 2098219077Sdim return; 2099219077Sdim } 2100219077Sdim 2101205408Srdivacky const Stmt *Body = D->getBody(); 2102205408Srdivacky assert(Body); 2103205408Srdivacky 2104261991Sdim // Construct the analysis context with the specified CFG build options. 2105276479Sdim AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D); 2106226633Sdim 2107205408Srdivacky // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 2108261991Sdim // explosion for destructors that can result and the compile time hit. 2109226633Sdim AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; 2110226633Sdim AC.getCFGBuildOptions().AddEHEdges = false; 2111226633Sdim AC.getCFGBuildOptions().AddInitializers = true; 2112226633Sdim AC.getCFGBuildOptions().AddImplicitDtors = true; 2113243830Sdim AC.getCFGBuildOptions().AddTemporaryDtors = true; 2114276479Sdim AC.getCFGBuildOptions().AddCXXNewAllocator = false; 2115288943Sdim AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; 2116243830Sdim 2117226633Sdim // Force that certain expressions appear as CFGElements in the CFG. This 2118226633Sdim // is used to speed up various analyses. 2119226633Sdim // FIXME: This isn't the right factoring. This is here for initial 2120226633Sdim // prototyping, but we need a way for analyses to say what expressions they 2121226633Sdim // expect to always be CFGElements and then fill in the BuildOptions 2122226633Sdim // appropriately. This is essentially a layering violation. 2123261991Sdim if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis || 2124261991Sdim P.enableConsumedAnalysis) { 2125234353Sdim // Unreachable code analysis and thread safety require a linearized CFG. 2126226633Sdim AC.getCFGBuildOptions().setAllAlwaysAdd(); 2127226633Sdim } 2128226633Sdim else { 2129226633Sdim AC.getCFGBuildOptions() 2130226633Sdim .setAlwaysAdd(Stmt::BinaryOperatorClass) 2131239462Sdim .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) 2132226633Sdim .setAlwaysAdd(Stmt::BlockExprClass) 2133226633Sdim .setAlwaysAdd(Stmt::CStyleCastExprClass) 2134226633Sdim .setAlwaysAdd(Stmt::DeclRefExprClass) 2135226633Sdim .setAlwaysAdd(Stmt::ImplicitCastExprClass) 2136239462Sdim .setAlwaysAdd(Stmt::UnaryOperatorClass) 2137239462Sdim .setAlwaysAdd(Stmt::AttributedStmtClass); 2138226633Sdim } 2139205408Srdivacky 2140276479Sdim // Install the logical handler for -Wtautological-overlap-compare 2141276479Sdim std::unique_ptr<LogicalErrorHandler> LEH; 2142276479Sdim if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, 2143276479Sdim D->getLocStart())) { 2144276479Sdim LEH.reset(new LogicalErrorHandler(S)); 2145276479Sdim AC.getCFGBuildOptions().Observer = LEH.get(); 2146276479Sdim } 2147261991Sdim 2148219077Sdim // Emit delayed diagnostics. 2149219077Sdim if (!fscope->PossiblyUnreachableDiags.empty()) { 2150219077Sdim bool analyzed = false; 2151221345Sdim 2152221345Sdim // Register the expressions with the CFGBuilder. 2153276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) { 2154276479Sdim if (D.stmt) 2155276479Sdim AC.registerForcedBlockExpression(D.stmt); 2156221345Sdim } 2157221345Sdim 2158221345Sdim if (AC.getCFG()) { 2159221345Sdim analyzed = true; 2160276479Sdim for (const auto &D : fscope->PossiblyUnreachableDiags) { 2161221345Sdim bool processed = false; 2162276479Sdim if (D.stmt) { 2163276479Sdim const CFGBlock *block = AC.getBlockForRegisteredExpression(D.stmt); 2164234353Sdim CFGReverseBlockReachabilityAnalysis *cra = 2165234353Sdim AC.getCFGReachablityAnalysis(); 2166234353Sdim // FIXME: We should be able to assert that block is non-null, but 2167234353Sdim // the CFG analysis can skip potentially-evaluated expressions in 2168234353Sdim // edge cases; see test/Sema/vla-2.c. 2169234353Sdim if (block && cra) { 2170219077Sdim // Can this block be reached from the entrance? 2171221345Sdim if (cra->isReachable(&AC.getCFG()->getEntry(), block)) 2172219077Sdim S.Diag(D.Loc, D.PD); 2173221345Sdim processed = true; 2174219077Sdim } 2175219077Sdim } 2176221345Sdim if (!processed) { 2177221345Sdim // Emit the warning anyway if we cannot map to a basic block. 2178221345Sdim S.Diag(D.Loc, D.PD); 2179221345Sdim } 2180219077Sdim } 2181221345Sdim } 2182219077Sdim 2183219077Sdim if (!analyzed) 2184219077Sdim flushDiagnostics(S, fscope); 2185219077Sdim } 2186219077Sdim 2187205408Srdivacky // Warning: check missing 'return' 2188206084Srdivacky if (P.enableCheckFallThrough) { 2189205408Srdivacky const CheckFallThroughDiagnostics &CD = 2190314564Sdim (isa<BlockDecl>(D) 2191314564Sdim ? CheckFallThroughDiagnostics::MakeForBlock() 2192314564Sdim : (isa<CXXMethodDecl>(D) && 2193314564Sdim cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && 2194314564Sdim cast<CXXMethodDecl>(D)->getParent()->isLambda()) 2195314564Sdim ? CheckFallThroughDiagnostics::MakeForLambda() 2196321369Sdim : (fscope->isCoroutine() 2197314564Sdim ? CheckFallThroughDiagnostics::MakeForCoroutine(D) 2198314564Sdim : CheckFallThroughDiagnostics::MakeForFunction(D))); 2199219077Sdim CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); 2200205408Srdivacky } 2201205408Srdivacky 2202205408Srdivacky // Warning: check for unreachable code 2203234353Sdim if (P.enableCheckUnreachable) { 2204234353Sdim // Only check for unreachable code on non-template instantiations. 2205234353Sdim // Different template instantiations can effectively change the control-flow 2206234353Sdim // and it is very difficult to prove that a snippet of code in a template 2207234353Sdim // is unreachable for all instantiations. 2208234353Sdim bool isTemplateInstantiation = false; 2209234353Sdim if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) 2210234353Sdim isTemplateInstantiation = Function->isTemplateInstantiation(); 2211234353Sdim if (!isTemplateInstantiation) 2212234353Sdim CheckUnreachable(S, AC); 2213234353Sdim } 2214226633Sdim 2215226633Sdim // Check for thread safety violations 2216226633Sdim if (P.enableThreadSafetyAnalysis) { 2217234353Sdim SourceLocation FL = AC.getDecl()->getLocation(); 2218234353Sdim SourceLocation FEL = AC.getDecl()->getLocEnd(); 2219280031Sdim threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL); 2220276479Sdim if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getLocStart())) 2221249423Sdim Reporter.setIssueBetaWarnings(true); 2222280031Sdim if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart())) 2223280031Sdim Reporter.setVerbose(true); 2224249423Sdim 2225288943Sdim threadSafety::runThreadSafetyAnalysis(AC, Reporter, 2226288943Sdim &S.ThreadSafetyDeclCache); 2227226633Sdim Reporter.emitDiagnostics(); 2228226633Sdim } 2229226633Sdim 2230261991Sdim // Check for violations of consumed properties. 2231261991Sdim if (P.enableConsumedAnalysis) { 2232261991Sdim consumed::ConsumedWarningsHandler WarningHandler(S); 2233261991Sdim consumed::ConsumedAnalyzer Analyzer(WarningHandler); 2234261991Sdim Analyzer.run(AC); 2235261991Sdim } 2236261991Sdim 2237276479Sdim if (!Diags.isIgnored(diag::warn_uninit_var, D->getLocStart()) || 2238276479Sdim !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getLocStart()) || 2239276479Sdim !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getLocStart())) { 2240221345Sdim if (CFG *cfg = AC.getCFG()) { 2241218893Sdim UninitValsDiagReporter reporter(S); 2242224145Sdim UninitVariablesAnalysisStats stats; 2243224145Sdim std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats)); 2244218893Sdim runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, 2245224145Sdim reporter, stats); 2246224145Sdim 2247224145Sdim if (S.CollectStats && stats.NumVariablesAnalyzed > 0) { 2248224145Sdim ++NumUninitAnalysisFunctions; 2249224145Sdim NumUninitAnalysisVariables += stats.NumVariablesAnalyzed; 2250224145Sdim NumUninitAnalysisBlockVisits += stats.NumBlockVisits; 2251224145Sdim MaxUninitAnalysisVariablesPerFunction = 2252224145Sdim std::max(MaxUninitAnalysisVariablesPerFunction, 2253224145Sdim stats.NumVariablesAnalyzed); 2254224145Sdim MaxUninitAnalysisBlockVisitsPerFunction = 2255224145Sdim std::max(MaxUninitAnalysisBlockVisitsPerFunction, 2256224145Sdim stats.NumBlockVisits); 2257224145Sdim } 2258218893Sdim } 2259218893Sdim } 2260224145Sdim 2261239462Sdim bool FallThroughDiagFull = 2262276479Sdim !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getLocStart()); 2263276479Sdim bool FallThroughDiagPerFunction = !Diags.isIgnored( 2264276479Sdim diag::warn_unannotated_fallthrough_per_function, D->getLocStart()); 2265309124Sdim if (FallThroughDiagFull || FallThroughDiagPerFunction || 2266309124Sdim fscope->HasFallthroughStmt) { 2267239462Sdim DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); 2268239462Sdim } 2269239462Sdim 2270296417Sdim if (S.getLangOpts().ObjCWeak && 2271276479Sdim !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getLocStart())) 2272243830Sdim diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); 2273243830Sdim 2274276479Sdim 2275276479Sdim // Check for infinite self-recursion in functions 2276276479Sdim if (!Diags.isIgnored(diag::warn_infinite_recursive_function, 2277276479Sdim D->getLocStart())) { 2278276479Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 2279276479Sdim checkRecursiveFunction(S, FD, Body, AC); 2280276479Sdim } 2281276479Sdim } 2282276479Sdim 2283321369Sdim // Check for throw out of non-throwing function. 2284321369Sdim if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getLocStart())) 2285321369Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 2286321369Sdim if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) 2287321369Sdim checkThrowInNonThrowingFunc(S, FD, AC); 2288321369Sdim 2289276479Sdim // If none of the previous checks caused a CFG build, trigger one here 2290276479Sdim // for -Wtautological-overlap-compare 2291276479Sdim if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, 2292276479Sdim D->getLocStart())) { 2293276479Sdim AC.getCFG(); 2294276479Sdim } 2295276479Sdim 2296224145Sdim // Collect statistics about the CFG if it was built. 2297224145Sdim if (S.CollectStats && AC.isCFGBuilt()) { 2298224145Sdim ++NumFunctionsAnalyzed; 2299224145Sdim if (CFG *cfg = AC.getCFG()) { 2300224145Sdim // If we successfully built a CFG for this context, record some more 2301224145Sdim // detail information about it. 2302224145Sdim NumCFGBlocks += cfg->getNumBlockIDs(); 2303224145Sdim MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction, 2304224145Sdim cfg->getNumBlockIDs()); 2305224145Sdim } else { 2306224145Sdim ++NumFunctionsWithBadCFGs; 2307224145Sdim } 2308224145Sdim } 2309205408Srdivacky} 2310224145Sdim 2311224145Sdimvoid clang::sema::AnalysisBasedWarnings::PrintStats() const { 2312224145Sdim llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; 2313224145Sdim 2314224145Sdim unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; 2315224145Sdim unsigned AvgCFGBlocksPerFunction = 2316224145Sdim !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; 2317224145Sdim llvm::errs() << NumFunctionsAnalyzed << " functions analyzed (" 2318224145Sdim << NumFunctionsWithBadCFGs << " w/o CFGs).\n" 2319224145Sdim << " " << NumCFGBlocks << " CFG blocks built.\n" 2320224145Sdim << " " << AvgCFGBlocksPerFunction 2321224145Sdim << " average CFG blocks per function.\n" 2322224145Sdim << " " << MaxCFGBlocksPerFunction 2323224145Sdim << " max CFG blocks per function.\n"; 2324224145Sdim 2325224145Sdim unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0 2326224145Sdim : NumUninitAnalysisVariables/NumUninitAnalysisFunctions; 2327224145Sdim unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0 2328224145Sdim : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions; 2329224145Sdim llvm::errs() << NumUninitAnalysisFunctions 2330224145Sdim << " functions analyzed for uninitialiazed variables\n" 2331224145Sdim << " " << NumUninitAnalysisVariables << " variables analyzed.\n" 2332224145Sdim << " " << AvgUninitVariablesPerFunction 2333224145Sdim << " average variables per function.\n" 2334224145Sdim << " " << MaxUninitAnalysisVariablesPerFunction 2335224145Sdim << " max variables per function.\n" 2336224145Sdim << " " << NumUninitAnalysisBlockVisits << " block visits.\n" 2337224145Sdim << " " << AvgUninitBlockVisitsPerFunction 2338224145Sdim << " average block visits per function.\n" 2339224145Sdim << " " << MaxUninitAnalysisBlockVisitsPerFunction 2340224145Sdim << " max block visits per function.\n"; 2341224145Sdim} 2342