AnalysisBasedWarnings.cpp revision 212904
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" 17212904Sdim#include "clang/Sema/SemaInternal.h" 18205408Srdivacky#include "clang/Basic/SourceManager.h" 19212904Sdim#include "clang/AST/DeclObjC.h" 20212904Sdim#include "clang/AST/DeclCXX.h" 21205408Srdivacky#include "clang/AST/ExprObjC.h" 22205408Srdivacky#include "clang/AST/ExprCXX.h" 23205408Srdivacky#include "clang/AST/StmtObjC.h" 24205408Srdivacky#include "clang/AST/StmtCXX.h" 25205408Srdivacky#include "clang/Analysis/AnalysisContext.h" 26205408Srdivacky#include "clang/Analysis/CFG.h" 27205408Srdivacky#include "clang/Analysis/Analyses/ReachableCode.h" 28205408Srdivacky#include "llvm/ADT/BitVector.h" 29205408Srdivacky#include "llvm/Support/Casting.h" 30205408Srdivacky 31205408Srdivackyusing namespace clang; 32205408Srdivacky 33205408Srdivacky//===----------------------------------------------------------------------===// 34205408Srdivacky// Unreachable code analysis. 35205408Srdivacky//===----------------------------------------------------------------------===// 36205408Srdivacky 37205408Srdivackynamespace { 38205408Srdivacky class UnreachableCodeHandler : public reachable_code::Callback { 39205408Srdivacky Sema &S; 40205408Srdivacky public: 41205408Srdivacky UnreachableCodeHandler(Sema &s) : S(s) {} 42205408Srdivacky 43205408Srdivacky void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { 44205408Srdivacky S.Diag(L, diag::warn_unreachable) << R1 << R2; 45205408Srdivacky } 46205408Srdivacky }; 47205408Srdivacky} 48205408Srdivacky 49205408Srdivacky/// CheckUnreachable - Check for unreachable code. 50205408Srdivackystatic void CheckUnreachable(Sema &S, AnalysisContext &AC) { 51205408Srdivacky UnreachableCodeHandler UC(S); 52205408Srdivacky reachable_code::FindUnreachableCode(AC, UC); 53205408Srdivacky} 54205408Srdivacky 55205408Srdivacky//===----------------------------------------------------------------------===// 56205408Srdivacky// Check for missing return value. 57205408Srdivacky//===----------------------------------------------------------------------===// 58205408Srdivacky 59208600Srdivackyenum ControlFlowKind { 60208600Srdivacky UnknownFallThrough, 61208600Srdivacky NeverFallThrough, 62208600Srdivacky MaybeFallThrough, 63208600Srdivacky AlwaysFallThrough, 64208600Srdivacky NeverFallThroughOrReturn 65208600Srdivacky}; 66205408Srdivacky 67205408Srdivacky/// CheckFallThrough - Check that we don't fall off the end of a 68205408Srdivacky/// Statement that should return a value. 69205408Srdivacky/// 70205408Srdivacky/// \returns AlwaysFallThrough iff we always fall off the end of the statement, 71205408Srdivacky/// MaybeFallThrough iff we might or might not fall off the end, 72205408Srdivacky/// NeverFallThroughOrReturn iff we never fall off the end of the statement or 73205408Srdivacky/// return. We assume NeverFallThrough iff we never fall off the end of the 74205408Srdivacky/// statement but we may return. We assume that functions not marked noreturn 75205408Srdivacky/// will return. 76205408Srdivackystatic ControlFlowKind CheckFallThrough(AnalysisContext &AC) { 77205408Srdivacky CFG *cfg = AC.getCFG(); 78208600Srdivacky if (cfg == 0) return UnknownFallThrough; 79205408Srdivacky 80205408Srdivacky // The CFG leaves in dead things, and we don't want the dead code paths to 81205408Srdivacky // confuse us, so we mark all live things first. 82205408Srdivacky llvm::BitVector live(cfg->getNumBlockIDs()); 83205408Srdivacky unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), 84205408Srdivacky live); 85205408Srdivacky 86205408Srdivacky bool AddEHEdges = AC.getAddEHEdges(); 87205408Srdivacky if (!AddEHEdges && count != cfg->getNumBlockIDs()) 88205408Srdivacky // When there are things remaining dead, and we didn't add EH edges 89205408Srdivacky // from CallExprs to the catch clauses, we have to go back and 90205408Srdivacky // mark them as live. 91205408Srdivacky for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { 92205408Srdivacky CFGBlock &b = **I; 93205408Srdivacky if (!live[b.getBlockID()]) { 94205408Srdivacky if (b.pred_begin() == b.pred_end()) { 95205408Srdivacky if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) 96205408Srdivacky // When not adding EH edges from calls, catch clauses 97205408Srdivacky // can otherwise seem dead. Avoid noting them as dead. 98205408Srdivacky count += reachable_code::ScanReachableFromBlock(b, live); 99205408Srdivacky continue; 100205408Srdivacky } 101205408Srdivacky } 102205408Srdivacky } 103205408Srdivacky 104205408Srdivacky // Now we know what is live, we check the live precessors of the exit block 105205408Srdivacky // and look for fall through paths, being careful to ignore normal returns, 106205408Srdivacky // and exceptional paths. 107205408Srdivacky bool HasLiveReturn = false; 108205408Srdivacky bool HasFakeEdge = false; 109205408Srdivacky bool HasPlainEdge = false; 110205408Srdivacky bool HasAbnormalEdge = false; 111205408Srdivacky for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), 112205408Srdivacky E = cfg->getExit().pred_end(); 113205408Srdivacky I != E; 114205408Srdivacky ++I) { 115205408Srdivacky CFGBlock& B = **I; 116205408Srdivacky if (!live[B.getBlockID()]) 117205408Srdivacky continue; 118205408Srdivacky if (B.size() == 0) { 119205408Srdivacky if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { 120205408Srdivacky HasAbnormalEdge = true; 121205408Srdivacky continue; 122205408Srdivacky } 123205408Srdivacky 124205408Srdivacky // A labeled empty statement, or the entry block... 125205408Srdivacky HasPlainEdge = true; 126205408Srdivacky continue; 127205408Srdivacky } 128205408Srdivacky Stmt *S = B[B.size()-1]; 129205408Srdivacky if (isa<ReturnStmt>(S)) { 130205408Srdivacky HasLiveReturn = true; 131205408Srdivacky continue; 132205408Srdivacky } 133205408Srdivacky if (isa<ObjCAtThrowStmt>(S)) { 134205408Srdivacky HasFakeEdge = true; 135205408Srdivacky continue; 136205408Srdivacky } 137205408Srdivacky if (isa<CXXThrowExpr>(S)) { 138205408Srdivacky HasFakeEdge = true; 139205408Srdivacky continue; 140205408Srdivacky } 141205408Srdivacky if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { 142205408Srdivacky if (AS->isMSAsm()) { 143205408Srdivacky HasFakeEdge = true; 144205408Srdivacky HasLiveReturn = true; 145205408Srdivacky continue; 146205408Srdivacky } 147205408Srdivacky } 148205408Srdivacky if (isa<CXXTryStmt>(S)) { 149205408Srdivacky HasAbnormalEdge = true; 150205408Srdivacky continue; 151205408Srdivacky } 152205408Srdivacky 153205408Srdivacky bool NoReturnEdge = false; 154205408Srdivacky if (CallExpr *C = dyn_cast<CallExpr>(S)) { 155207619Srdivacky if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) 156207619Srdivacky == B.succ_end()) { 157205408Srdivacky HasAbnormalEdge = true; 158205408Srdivacky continue; 159205408Srdivacky } 160205408Srdivacky Expr *CEE = C->getCallee()->IgnoreParenCasts(); 161206084Srdivacky if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { 162205408Srdivacky NoReturnEdge = true; 163205408Srdivacky HasFakeEdge = true; 164205408Srdivacky } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { 165205408Srdivacky ValueDecl *VD = DRE->getDecl(); 166205408Srdivacky if (VD->hasAttr<NoReturnAttr>()) { 167205408Srdivacky NoReturnEdge = true; 168205408Srdivacky HasFakeEdge = true; 169205408Srdivacky } 170205408Srdivacky } 171205408Srdivacky } 172208600Srdivacky // FIXME: Remove this hack once temporaries and their destructors are 173208600Srdivacky // modeled correctly by the CFG. 174208600Srdivacky if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) { 175208600Srdivacky for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) { 176208600Srdivacky const FunctionDecl *FD = E->getTemporary(I)->getDestructor(); 177208600Srdivacky if (FD->hasAttr<NoReturnAttr>() || 178208600Srdivacky FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) { 179208600Srdivacky NoReturnEdge = true; 180208600Srdivacky HasFakeEdge = true; 181208600Srdivacky break; 182208600Srdivacky } 183208600Srdivacky } 184208600Srdivacky } 185205408Srdivacky // FIXME: Add noreturn message sends. 186205408Srdivacky if (NoReturnEdge == false) 187205408Srdivacky HasPlainEdge = true; 188205408Srdivacky } 189205408Srdivacky if (!HasPlainEdge) { 190205408Srdivacky if (HasLiveReturn) 191205408Srdivacky return NeverFallThrough; 192205408Srdivacky return NeverFallThroughOrReturn; 193205408Srdivacky } 194205408Srdivacky if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) 195205408Srdivacky return MaybeFallThrough; 196205408Srdivacky // This says AlwaysFallThrough for calls to functions that are not marked 197205408Srdivacky // noreturn, that don't return. If people would like this warning to be more 198205408Srdivacky // accurate, such functions should be marked as noreturn. 199205408Srdivacky return AlwaysFallThrough; 200205408Srdivacky} 201205408Srdivacky 202212904Sdimnamespace { 203212904Sdim 204205408Srdivackystruct CheckFallThroughDiagnostics { 205205408Srdivacky unsigned diag_MaybeFallThrough_HasNoReturn; 206205408Srdivacky unsigned diag_MaybeFallThrough_ReturnsNonVoid; 207205408Srdivacky unsigned diag_AlwaysFallThrough_HasNoReturn; 208205408Srdivacky unsigned diag_AlwaysFallThrough_ReturnsNonVoid; 209205408Srdivacky unsigned diag_NeverFallThroughOrReturn; 210205408Srdivacky bool funMode; 211206084Srdivacky 212207619Srdivacky static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { 213205408Srdivacky CheckFallThroughDiagnostics D; 214205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 215205408Srdivacky diag::warn_falloff_noreturn_function; 216205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 217205408Srdivacky diag::warn_maybe_falloff_nonvoid_function; 218205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 219205408Srdivacky diag::warn_falloff_noreturn_function; 220205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 221205408Srdivacky diag::warn_falloff_nonvoid_function; 222207619Srdivacky 223207619Srdivacky // Don't suggest that virtual functions be marked "noreturn", since they 224207619Srdivacky // might be overridden by non-noreturn functions. 225207619Srdivacky bool isVirtualMethod = false; 226207619Srdivacky if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) 227207619Srdivacky isVirtualMethod = Method->isVirtual(); 228207619Srdivacky 229207619Srdivacky if (!isVirtualMethod) 230207619Srdivacky D.diag_NeverFallThroughOrReturn = 231207619Srdivacky diag::warn_suggest_noreturn_function; 232207619Srdivacky else 233207619Srdivacky D.diag_NeverFallThroughOrReturn = 0; 234207619Srdivacky 235205408Srdivacky D.funMode = true; 236205408Srdivacky return D; 237205408Srdivacky } 238206084Srdivacky 239205408Srdivacky static CheckFallThroughDiagnostics MakeForBlock() { 240205408Srdivacky CheckFallThroughDiagnostics D; 241205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 242205408Srdivacky diag::err_noreturn_block_has_return_expr; 243205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 244205408Srdivacky diag::err_maybe_falloff_nonvoid_block; 245205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 246205408Srdivacky diag::err_noreturn_block_has_return_expr; 247205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 248205408Srdivacky diag::err_falloff_nonvoid_block; 249205408Srdivacky D.diag_NeverFallThroughOrReturn = 250205408Srdivacky diag::warn_suggest_noreturn_block; 251205408Srdivacky D.funMode = false; 252205408Srdivacky return D; 253205408Srdivacky } 254206084Srdivacky 255205408Srdivacky bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, 256205408Srdivacky bool HasNoReturn) const { 257205408Srdivacky if (funMode) { 258205408Srdivacky return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) 259205408Srdivacky == Diagnostic::Ignored || ReturnsVoid) 260205408Srdivacky && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) 261205408Srdivacky == Diagnostic::Ignored || !HasNoReturn) 262205408Srdivacky && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) 263205408Srdivacky == Diagnostic::Ignored || !ReturnsVoid); 264205408Srdivacky } 265206084Srdivacky 266205408Srdivacky // For blocks. 267205408Srdivacky return ReturnsVoid && !HasNoReturn 268205408Srdivacky && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) 269205408Srdivacky == Diagnostic::Ignored || !ReturnsVoid); 270205408Srdivacky } 271205408Srdivacky}; 272205408Srdivacky 273212904Sdim} 274212904Sdim 275205408Srdivacky/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a 276205408Srdivacky/// function that should return a value. Check that we don't fall off the end 277205408Srdivacky/// of a noreturn function. We assume that functions and blocks not marked 278205408Srdivacky/// noreturn will return. 279205408Srdivackystatic void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, 280205408Srdivacky QualType BlockTy, 281205408Srdivacky const CheckFallThroughDiagnostics& CD, 282205408Srdivacky AnalysisContext &AC) { 283205408Srdivacky 284205408Srdivacky bool ReturnsVoid = false; 285205408Srdivacky bool HasNoReturn = false; 286205408Srdivacky 287205408Srdivacky if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 288205408Srdivacky ReturnsVoid = FD->getResultType()->isVoidType(); 289205408Srdivacky HasNoReturn = FD->hasAttr<NoReturnAttr>() || 290206084Srdivacky FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); 291205408Srdivacky } 292205408Srdivacky else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 293205408Srdivacky ReturnsVoid = MD->getResultType()->isVoidType(); 294205408Srdivacky HasNoReturn = MD->hasAttr<NoReturnAttr>(); 295205408Srdivacky } 296205408Srdivacky else if (isa<BlockDecl>(D)) { 297206084Srdivacky if (const FunctionType *FT = 298205408Srdivacky BlockTy->getPointeeType()->getAs<FunctionType>()) { 299205408Srdivacky if (FT->getResultType()->isVoidType()) 300205408Srdivacky ReturnsVoid = true; 301205408Srdivacky if (FT->getNoReturnAttr()) 302205408Srdivacky HasNoReturn = true; 303205408Srdivacky } 304205408Srdivacky } 305205408Srdivacky 306205408Srdivacky Diagnostic &Diags = S.getDiagnostics(); 307205408Srdivacky 308205408Srdivacky // Short circuit for compilation speed. 309205408Srdivacky if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) 310205408Srdivacky return; 311206084Srdivacky 312205408Srdivacky // FIXME: Function try block 313205408Srdivacky if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { 314205408Srdivacky switch (CheckFallThrough(AC)) { 315208600Srdivacky case UnknownFallThrough: 316208600Srdivacky break; 317208600Srdivacky 318205408Srdivacky case MaybeFallThrough: 319205408Srdivacky if (HasNoReturn) 320205408Srdivacky S.Diag(Compound->getRBracLoc(), 321205408Srdivacky CD.diag_MaybeFallThrough_HasNoReturn); 322205408Srdivacky else if (!ReturnsVoid) 323205408Srdivacky S.Diag(Compound->getRBracLoc(), 324205408Srdivacky CD.diag_MaybeFallThrough_ReturnsNonVoid); 325205408Srdivacky break; 326205408Srdivacky case AlwaysFallThrough: 327205408Srdivacky if (HasNoReturn) 328205408Srdivacky S.Diag(Compound->getRBracLoc(), 329205408Srdivacky CD.diag_AlwaysFallThrough_HasNoReturn); 330205408Srdivacky else if (!ReturnsVoid) 331205408Srdivacky S.Diag(Compound->getRBracLoc(), 332205408Srdivacky CD.diag_AlwaysFallThrough_ReturnsNonVoid); 333205408Srdivacky break; 334205408Srdivacky case NeverFallThroughOrReturn: 335207619Srdivacky if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) 336205408Srdivacky S.Diag(Compound->getLBracLoc(), 337205408Srdivacky CD.diag_NeverFallThroughOrReturn); 338205408Srdivacky break; 339205408Srdivacky case NeverFallThrough: 340205408Srdivacky break; 341205408Srdivacky } 342205408Srdivacky } 343205408Srdivacky} 344205408Srdivacky 345205408Srdivacky//===----------------------------------------------------------------------===// 346205408Srdivacky// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based 347205408Srdivacky// warnings on a function, method, or block. 348205408Srdivacky//===----------------------------------------------------------------------===// 349205408Srdivacky 350206084Srdivackyclang::sema::AnalysisBasedWarnings::Policy::Policy() { 351206084Srdivacky enableCheckFallThrough = 1; 352206084Srdivacky enableCheckUnreachable = 0; 353206084Srdivacky} 354206084Srdivacky 355205408Srdivackyclang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { 356205408Srdivacky Diagnostic &D = S.getDiagnostics(); 357206084Srdivacky DefaultPolicy.enableCheckUnreachable = (unsigned) 358205408Srdivacky (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); 359205408Srdivacky} 360205408Srdivacky 361206084Srdivackyvoid clang::sema:: 362206084SrdivackyAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 363207619Srdivacky const Decl *D, QualType BlockTy) { 364206084Srdivacky 365205408Srdivacky assert(BlockTy.isNull() || isa<BlockDecl>(D)); 366205408Srdivacky 367205408Srdivacky // We avoid doing analysis-based warnings when there are errors for 368205408Srdivacky // two reasons: 369205408Srdivacky // (1) The CFGs often can't be constructed (if the body is invalid), so 370205408Srdivacky // don't bother trying. 371205408Srdivacky // (2) The code already has problems; running the analysis just takes more 372205408Srdivacky // time. 373207619Srdivacky Diagnostic &Diags = S.getDiagnostics(); 374207619Srdivacky 375207619Srdivacky if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) 376206084Srdivacky return; 377206084Srdivacky 378206084Srdivacky // Do not do any analysis for declarations in system headers if we are 379206084Srdivacky // going to just ignore them. 380207619Srdivacky if (Diags.getSuppressSystemWarnings() && 381206084Srdivacky S.SourceMgr.isInSystemHeader(D->getLocation())) 382206084Srdivacky return; 383206084Srdivacky 384212904Sdim // For code in dependent contexts, we'll do this at instantiation time. 385212904Sdim if (cast<DeclContext>(D)->isDependentContext()) 386212904Sdim return; 387205408Srdivacky 388205408Srdivacky const Stmt *Body = D->getBody(); 389205408Srdivacky assert(Body); 390205408Srdivacky 391205408Srdivacky // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 392205408Srdivacky // explosion for destrutors that can result and the compile time hit. 393212904Sdim AnalysisContext AC(D, 0, false); 394205408Srdivacky 395205408Srdivacky // Warning: check missing 'return' 396206084Srdivacky if (P.enableCheckFallThrough) { 397205408Srdivacky const CheckFallThroughDiagnostics &CD = 398205408Srdivacky (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() 399207619Srdivacky : CheckFallThroughDiagnostics::MakeForFunction(D)); 400205408Srdivacky CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); 401205408Srdivacky } 402205408Srdivacky 403205408Srdivacky // Warning: check for unreachable code 404207619Srdivacky if (P.enableCheckUnreachable) 405205408Srdivacky CheckUnreachable(S, AC); 406205408Srdivacky} 407212904Sdim 408212904Sdimvoid clang::sema:: 409212904SdimAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 410212904Sdim const BlockExpr *E) { 411212904Sdim return IssueWarnings(P, E->getBlockDecl(), E->getType()); 412212904Sdim} 413212904Sdim 414212904Sdimvoid clang::sema:: 415212904SdimAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 416212904Sdim const ObjCMethodDecl *D) { 417212904Sdim return IssueWarnings(P, D, QualType()); 418212904Sdim} 419212904Sdim 420212904Sdimvoid clang::sema:: 421212904SdimAnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 422212904Sdim const FunctionDecl *D) { 423212904Sdim return IssueWarnings(P, D, QualType()); 424212904Sdim} 425