AnalysisBasedWarnings.cpp revision 205408
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 16205408Srdivacky#include "Sema.h" 17205408Srdivacky#include "AnalysisBasedWarnings.h" 18205408Srdivacky#include "clang/Basic/SourceManager.h" 19205408Srdivacky#include "clang/AST/ExprObjC.h" 20205408Srdivacky#include "clang/AST/ExprCXX.h" 21205408Srdivacky#include "clang/AST/StmtObjC.h" 22205408Srdivacky#include "clang/AST/StmtCXX.h" 23205408Srdivacky#include "clang/Analysis/AnalysisContext.h" 24205408Srdivacky#include "clang/Analysis/CFG.h" 25205408Srdivacky#include "clang/Analysis/Analyses/ReachableCode.h" 26205408Srdivacky#include "llvm/ADT/BitVector.h" 27205408Srdivacky#include "llvm/Support/Casting.h" 28205408Srdivacky#include <queue> 29205408Srdivacky 30205408Srdivackyusing namespace clang; 31205408Srdivacky 32205408Srdivacky//===----------------------------------------------------------------------===// 33205408Srdivacky// Unreachable code analysis. 34205408Srdivacky//===----------------------------------------------------------------------===// 35205408Srdivacky 36205408Srdivackynamespace { 37205408Srdivacky class UnreachableCodeHandler : public reachable_code::Callback { 38205408Srdivacky Sema &S; 39205408Srdivacky public: 40205408Srdivacky UnreachableCodeHandler(Sema &s) : S(s) {} 41205408Srdivacky 42205408Srdivacky void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { 43205408Srdivacky S.Diag(L, diag::warn_unreachable) << R1 << R2; 44205408Srdivacky } 45205408Srdivacky }; 46205408Srdivacky} 47205408Srdivacky 48205408Srdivacky/// CheckUnreachable - Check for unreachable code. 49205408Srdivackystatic void CheckUnreachable(Sema &S, AnalysisContext &AC) { 50205408Srdivacky UnreachableCodeHandler UC(S); 51205408Srdivacky reachable_code::FindUnreachableCode(AC, UC); 52205408Srdivacky} 53205408Srdivacky 54205408Srdivacky//===----------------------------------------------------------------------===// 55205408Srdivacky// Check for missing return value. 56205408Srdivacky//===----------------------------------------------------------------------===// 57205408Srdivacky 58205408Srdivackyenum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, 59205408Srdivacky AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; 60205408Srdivacky 61205408Srdivacky/// CheckFallThrough - Check that we don't fall off the end of a 62205408Srdivacky/// Statement that should return a value. 63205408Srdivacky/// 64205408Srdivacky/// \returns AlwaysFallThrough iff we always fall off the end of the statement, 65205408Srdivacky/// MaybeFallThrough iff we might or might not fall off the end, 66205408Srdivacky/// NeverFallThroughOrReturn iff we never fall off the end of the statement or 67205408Srdivacky/// return. We assume NeverFallThrough iff we never fall off the end of the 68205408Srdivacky/// statement but we may return. We assume that functions not marked noreturn 69205408Srdivacky/// will return. 70205408Srdivackystatic ControlFlowKind CheckFallThrough(AnalysisContext &AC) { 71205408Srdivacky CFG *cfg = AC.getCFG(); 72205408Srdivacky if (cfg == 0) 73205408Srdivacky // FIXME: This should be NeverFallThrough 74205408Srdivacky return NeverFallThroughOrReturn; 75205408Srdivacky 76205408Srdivacky // The CFG leaves in dead things, and we don't want the dead code paths to 77205408Srdivacky // confuse us, so we mark all live things first. 78205408Srdivacky std::queue<CFGBlock*> workq; 79205408Srdivacky llvm::BitVector live(cfg->getNumBlockIDs()); 80205408Srdivacky unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), 81205408Srdivacky live); 82205408Srdivacky 83205408Srdivacky bool AddEHEdges = AC.getAddEHEdges(); 84205408Srdivacky if (!AddEHEdges && count != cfg->getNumBlockIDs()) 85205408Srdivacky // When there are things remaining dead, and we didn't add EH edges 86205408Srdivacky // from CallExprs to the catch clauses, we have to go back and 87205408Srdivacky // mark them as live. 88205408Srdivacky for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { 89205408Srdivacky CFGBlock &b = **I; 90205408Srdivacky if (!live[b.getBlockID()]) { 91205408Srdivacky if (b.pred_begin() == b.pred_end()) { 92205408Srdivacky if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) 93205408Srdivacky // When not adding EH edges from calls, catch clauses 94205408Srdivacky // can otherwise seem dead. Avoid noting them as dead. 95205408Srdivacky count += reachable_code::ScanReachableFromBlock(b, live); 96205408Srdivacky continue; 97205408Srdivacky } 98205408Srdivacky } 99205408Srdivacky } 100205408Srdivacky 101205408Srdivacky // Now we know what is live, we check the live precessors of the exit block 102205408Srdivacky // and look for fall through paths, being careful to ignore normal returns, 103205408Srdivacky // and exceptional paths. 104205408Srdivacky bool HasLiveReturn = false; 105205408Srdivacky bool HasFakeEdge = false; 106205408Srdivacky bool HasPlainEdge = false; 107205408Srdivacky bool HasAbnormalEdge = false; 108205408Srdivacky for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), 109205408Srdivacky E = cfg->getExit().pred_end(); 110205408Srdivacky I != E; 111205408Srdivacky ++I) { 112205408Srdivacky CFGBlock& B = **I; 113205408Srdivacky if (!live[B.getBlockID()]) 114205408Srdivacky continue; 115205408Srdivacky if (B.size() == 0) { 116205408Srdivacky if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { 117205408Srdivacky HasAbnormalEdge = true; 118205408Srdivacky continue; 119205408Srdivacky } 120205408Srdivacky 121205408Srdivacky // A labeled empty statement, or the entry block... 122205408Srdivacky HasPlainEdge = true; 123205408Srdivacky continue; 124205408Srdivacky } 125205408Srdivacky Stmt *S = B[B.size()-1]; 126205408Srdivacky if (isa<ReturnStmt>(S)) { 127205408Srdivacky HasLiveReturn = true; 128205408Srdivacky continue; 129205408Srdivacky } 130205408Srdivacky if (isa<ObjCAtThrowStmt>(S)) { 131205408Srdivacky HasFakeEdge = true; 132205408Srdivacky continue; 133205408Srdivacky } 134205408Srdivacky if (isa<CXXThrowExpr>(S)) { 135205408Srdivacky HasFakeEdge = true; 136205408Srdivacky continue; 137205408Srdivacky } 138205408Srdivacky if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { 139205408Srdivacky if (AS->isMSAsm()) { 140205408Srdivacky HasFakeEdge = true; 141205408Srdivacky HasLiveReturn = true; 142205408Srdivacky continue; 143205408Srdivacky } 144205408Srdivacky } 145205408Srdivacky if (isa<CXXTryStmt>(S)) { 146205408Srdivacky HasAbnormalEdge = true; 147205408Srdivacky continue; 148205408Srdivacky } 149205408Srdivacky 150205408Srdivacky bool NoReturnEdge = false; 151205408Srdivacky if (CallExpr *C = dyn_cast<CallExpr>(S)) { 152205408Srdivacky if (B.succ_begin()[0] != &cfg->getExit()) { 153205408Srdivacky HasAbnormalEdge = true; 154205408Srdivacky continue; 155205408Srdivacky } 156205408Srdivacky Expr *CEE = C->getCallee()->IgnoreParenCasts(); 157205408Srdivacky if (CEE->getType().getNoReturnAttr()) { 158205408Srdivacky NoReturnEdge = true; 159205408Srdivacky HasFakeEdge = true; 160205408Srdivacky } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { 161205408Srdivacky ValueDecl *VD = DRE->getDecl(); 162205408Srdivacky if (VD->hasAttr<NoReturnAttr>()) { 163205408Srdivacky NoReturnEdge = true; 164205408Srdivacky HasFakeEdge = true; 165205408Srdivacky } 166205408Srdivacky } 167205408Srdivacky } 168205408Srdivacky // FIXME: Add noreturn message sends. 169205408Srdivacky if (NoReturnEdge == false) 170205408Srdivacky HasPlainEdge = true; 171205408Srdivacky } 172205408Srdivacky if (!HasPlainEdge) { 173205408Srdivacky if (HasLiveReturn) 174205408Srdivacky return NeverFallThrough; 175205408Srdivacky return NeverFallThroughOrReturn; 176205408Srdivacky } 177205408Srdivacky if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) 178205408Srdivacky return MaybeFallThrough; 179205408Srdivacky // This says AlwaysFallThrough for calls to functions that are not marked 180205408Srdivacky // noreturn, that don't return. If people would like this warning to be more 181205408Srdivacky // accurate, such functions should be marked as noreturn. 182205408Srdivacky return AlwaysFallThrough; 183205408Srdivacky} 184205408Srdivacky 185205408Srdivackystruct CheckFallThroughDiagnostics { 186205408Srdivacky unsigned diag_MaybeFallThrough_HasNoReturn; 187205408Srdivacky unsigned diag_MaybeFallThrough_ReturnsNonVoid; 188205408Srdivacky unsigned diag_AlwaysFallThrough_HasNoReturn; 189205408Srdivacky unsigned diag_AlwaysFallThrough_ReturnsNonVoid; 190205408Srdivacky unsigned diag_NeverFallThroughOrReturn; 191205408Srdivacky bool funMode; 192205408Srdivacky 193205408Srdivacky static CheckFallThroughDiagnostics MakeForFunction() { 194205408Srdivacky CheckFallThroughDiagnostics D; 195205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 196205408Srdivacky diag::warn_falloff_noreturn_function; 197205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 198205408Srdivacky diag::warn_maybe_falloff_nonvoid_function; 199205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 200205408Srdivacky diag::warn_falloff_noreturn_function; 201205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 202205408Srdivacky diag::warn_falloff_nonvoid_function; 203205408Srdivacky D.diag_NeverFallThroughOrReturn = 204205408Srdivacky diag::warn_suggest_noreturn_function; 205205408Srdivacky D.funMode = true; 206205408Srdivacky return D; 207205408Srdivacky } 208205408Srdivacky 209205408Srdivacky static CheckFallThroughDiagnostics MakeForBlock() { 210205408Srdivacky CheckFallThroughDiagnostics D; 211205408Srdivacky D.diag_MaybeFallThrough_HasNoReturn = 212205408Srdivacky diag::err_noreturn_block_has_return_expr; 213205408Srdivacky D.diag_MaybeFallThrough_ReturnsNonVoid = 214205408Srdivacky diag::err_maybe_falloff_nonvoid_block; 215205408Srdivacky D.diag_AlwaysFallThrough_HasNoReturn = 216205408Srdivacky diag::err_noreturn_block_has_return_expr; 217205408Srdivacky D.diag_AlwaysFallThrough_ReturnsNonVoid = 218205408Srdivacky diag::err_falloff_nonvoid_block; 219205408Srdivacky D.diag_NeverFallThroughOrReturn = 220205408Srdivacky diag::warn_suggest_noreturn_block; 221205408Srdivacky D.funMode = false; 222205408Srdivacky return D; 223205408Srdivacky } 224205408Srdivacky 225205408Srdivacky bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, 226205408Srdivacky bool HasNoReturn) const { 227205408Srdivacky if (funMode) { 228205408Srdivacky return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) 229205408Srdivacky == Diagnostic::Ignored || ReturnsVoid) 230205408Srdivacky && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) 231205408Srdivacky == Diagnostic::Ignored || !HasNoReturn) 232205408Srdivacky && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) 233205408Srdivacky == Diagnostic::Ignored || !ReturnsVoid); 234205408Srdivacky } 235205408Srdivacky 236205408Srdivacky // For blocks. 237205408Srdivacky return ReturnsVoid && !HasNoReturn 238205408Srdivacky && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) 239205408Srdivacky == Diagnostic::Ignored || !ReturnsVoid); 240205408Srdivacky } 241205408Srdivacky}; 242205408Srdivacky 243205408Srdivacky/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a 244205408Srdivacky/// function that should return a value. Check that we don't fall off the end 245205408Srdivacky/// of a noreturn function. We assume that functions and blocks not marked 246205408Srdivacky/// noreturn will return. 247205408Srdivackystatic void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, 248205408Srdivacky QualType BlockTy, 249205408Srdivacky const CheckFallThroughDiagnostics& CD, 250205408Srdivacky AnalysisContext &AC) { 251205408Srdivacky 252205408Srdivacky bool ReturnsVoid = false; 253205408Srdivacky bool HasNoReturn = false; 254205408Srdivacky 255205408Srdivacky if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 256205408Srdivacky ReturnsVoid = FD->getResultType()->isVoidType(); 257205408Srdivacky HasNoReturn = FD->hasAttr<NoReturnAttr>() || 258205408Srdivacky FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); 259205408Srdivacky } 260205408Srdivacky else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 261205408Srdivacky ReturnsVoid = MD->getResultType()->isVoidType(); 262205408Srdivacky HasNoReturn = MD->hasAttr<NoReturnAttr>(); 263205408Srdivacky } 264205408Srdivacky else if (isa<BlockDecl>(D)) { 265205408Srdivacky if (const FunctionType *FT = 266205408Srdivacky BlockTy->getPointeeType()->getAs<FunctionType>()) { 267205408Srdivacky if (FT->getResultType()->isVoidType()) 268205408Srdivacky ReturnsVoid = true; 269205408Srdivacky if (FT->getNoReturnAttr()) 270205408Srdivacky HasNoReturn = true; 271205408Srdivacky } 272205408Srdivacky } 273205408Srdivacky 274205408Srdivacky Diagnostic &Diags = S.getDiagnostics(); 275205408Srdivacky 276205408Srdivacky // Short circuit for compilation speed. 277205408Srdivacky if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) 278205408Srdivacky return; 279205408Srdivacky 280205408Srdivacky // FIXME: Function try block 281205408Srdivacky if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { 282205408Srdivacky switch (CheckFallThrough(AC)) { 283205408Srdivacky case MaybeFallThrough: 284205408Srdivacky if (HasNoReturn) 285205408Srdivacky S.Diag(Compound->getRBracLoc(), 286205408Srdivacky CD.diag_MaybeFallThrough_HasNoReturn); 287205408Srdivacky else if (!ReturnsVoid) 288205408Srdivacky S.Diag(Compound->getRBracLoc(), 289205408Srdivacky CD.diag_MaybeFallThrough_ReturnsNonVoid); 290205408Srdivacky break; 291205408Srdivacky case AlwaysFallThrough: 292205408Srdivacky if (HasNoReturn) 293205408Srdivacky S.Diag(Compound->getRBracLoc(), 294205408Srdivacky CD.diag_AlwaysFallThrough_HasNoReturn); 295205408Srdivacky else if (!ReturnsVoid) 296205408Srdivacky S.Diag(Compound->getRBracLoc(), 297205408Srdivacky CD.diag_AlwaysFallThrough_ReturnsNonVoid); 298205408Srdivacky break; 299205408Srdivacky case NeverFallThroughOrReturn: 300205408Srdivacky if (ReturnsVoid && !HasNoReturn) 301205408Srdivacky S.Diag(Compound->getLBracLoc(), 302205408Srdivacky CD.diag_NeverFallThroughOrReturn); 303205408Srdivacky break; 304205408Srdivacky case NeverFallThrough: 305205408Srdivacky break; 306205408Srdivacky } 307205408Srdivacky } 308205408Srdivacky} 309205408Srdivacky 310205408Srdivacky//===----------------------------------------------------------------------===// 311205408Srdivacky// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based 312205408Srdivacky// warnings on a function, method, or block. 313205408Srdivacky//===----------------------------------------------------------------------===// 314205408Srdivacky 315205408Srdivackyclang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { 316205408Srdivacky Diagnostic &D = S.getDiagnostics(); 317205408Srdivacky 318205408Srdivacky enableCheckFallThrough = 1; 319205408Srdivacky 320205408Srdivacky enableCheckUnreachable = (unsigned) 321205408Srdivacky (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); 322205408Srdivacky} 323205408Srdivacky 324205408Srdivackyvoid clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, 325205408Srdivacky QualType BlockTy) { 326205408Srdivacky 327205408Srdivacky assert(BlockTy.isNull() || isa<BlockDecl>(D)); 328205408Srdivacky 329205408Srdivacky // Do not do any analysis for declarations in system headers if we are 330205408Srdivacky // going to just ignore them. 331205408Srdivacky if (S.getDiagnostics().getSuppressSystemWarnings() && 332205408Srdivacky S.SourceMgr.isInSystemHeader(D->getLocation())) 333205408Srdivacky return; 334205408Srdivacky 335205408Srdivacky // We avoid doing analysis-based warnings when there are errors for 336205408Srdivacky // two reasons: 337205408Srdivacky // (1) The CFGs often can't be constructed (if the body is invalid), so 338205408Srdivacky // don't bother trying. 339205408Srdivacky // (2) The code already has problems; running the analysis just takes more 340205408Srdivacky // time. 341205408Srdivacky if (S.getDiagnostics().hasErrorOccurred()) 342205408Srdivacky return; 343205408Srdivacky 344205408Srdivacky if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 345205408Srdivacky // For function templates, class templates and member function templates 346205408Srdivacky // we'll do the analysis at instantiation time. 347205408Srdivacky if (FD->isDependentContext()) 348205408Srdivacky return; 349205408Srdivacky } 350205408Srdivacky 351205408Srdivacky const Stmt *Body = D->getBody(); 352205408Srdivacky assert(Body); 353205408Srdivacky 354205408Srdivacky // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 355205408Srdivacky // explosion for destrutors that can result and the compile time hit. 356205408Srdivacky AnalysisContext AC(D, false); 357205408Srdivacky 358205408Srdivacky // Warning: check missing 'return' 359205408Srdivacky if (enableCheckFallThrough) { 360205408Srdivacky const CheckFallThroughDiagnostics &CD = 361205408Srdivacky (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() 362205408Srdivacky : CheckFallThroughDiagnostics::MakeForFunction()); 363205408Srdivacky CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); 364205408Srdivacky } 365205408Srdivacky 366205408Srdivacky // Warning: check for unreachable code 367205408Srdivacky if (enableCheckUnreachable) 368205408Srdivacky CheckUnreachable(S, AC); 369205408Srdivacky} 370