diff options
Diffstat (limited to 'lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 92 |
1 files changed, 69 insertions, 23 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index c4ceec0f81..a044576f5d 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -189,7 +189,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; bool funMode; - + static CheckFallThroughDiagnostics MakeForFunction() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -205,7 +205,7 @@ struct CheckFallThroughDiagnostics { D.funMode = true; return D; } - + static CheckFallThroughDiagnostics MakeForBlock() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -221,7 +221,7 @@ struct CheckFallThroughDiagnostics { D.funMode = false; return D; } - + bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { @@ -232,7 +232,7 @@ struct CheckFallThroughDiagnostics { && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) == Diagnostic::Ignored || !ReturnsVoid); } - + // For blocks. return ReturnsVoid && !HasNoReturn && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) @@ -262,7 +262,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, HasNoReturn = MD->hasAttr<NoReturnAttr>(); } else if (isa<BlockDecl>(D)) { - if (const FunctionType *FT = + if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) { if (FT->getResultType()->isVoidType()) ReturnsVoid = true; @@ -276,7 +276,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - + // FIXME: Function try block if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { switch (CheckFallThrough(AC)) { @@ -312,25 +312,23 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // warnings on a function, method, or block. //===----------------------------------------------------------------------===// -clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { - Diagnostic &D = S.getDiagnostics(); - +clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckFallThrough = 1; + enableCheckUnreachable = 0; +} - enableCheckUnreachable = (unsigned) +clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { + Diagnostic &D = S.getDiagnostics(); + DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); } -void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, - QualType BlockTy) { - +void clang::sema:: +AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, + const Decl *D, QualType BlockTy, + const bool analyzeStaticInline) { + assert(BlockTy.isNull() || isa<BlockDecl>(D)); - - // Do not do any analysis for declarations in system headers if we are - // going to just ignore them. - if (S.getDiagnostics().getSuppressSystemWarnings() && - S.SourceMgr.isInSystemHeader(D->getLocation())) - return; // We avoid doing analysis-based warnings when there are errors for // two reasons: @@ -339,13 +337,24 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, // (2) The code already has problems; running the analysis just takes more // time. if (S.getDiagnostics().hasErrorOccurred()) - return; - + return; + + // Do not do any analysis for declarations in system headers if we are + // going to just ignore them. + if (S.getDiagnostics().getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(D->getLocation())) + return; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // For function templates, class templates and member function templates // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; + + // Only analyze 'static inline' functions when explicitly asked. + if (!analyzeStaticInline && FD->isInlineSpecified() && + FD->getStorageClass() == FunctionDecl::Static) + return; } const Stmt *Body = D->getBody(); @@ -354,16 +363,53 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. AnalysisContext AC(D, false); + bool performedCheck = false; // Warning: check missing 'return' - if (enableCheckFallThrough) { + if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() : CheckFallThroughDiagnostics::MakeForFunction()); CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); + performedCheck = true; } // Warning: check for unreachable code - if (enableCheckUnreachable) + if (P.enableCheckUnreachable) { CheckUnreachable(S, AC); + performedCheck = true; + } + + // If this block or function calls a 'static inline' function, + // we should analyze those functions as well. + if (performedCheck) { + // The CFG should already be constructed, so this should not + // incur any extra cost. We might not have a CFG, however, for + // invalid code. + if (const CFG *cfg = AC.getCFG()) { + // All CallExprs are block-level expressions in the CFG. This means + // that walking the basic blocks in the CFG is more efficient + // than walking the entire AST to find all calls. + for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) { + const CFGBlock *B = *I; + for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI) + if (const CallExpr *CE = dyn_cast<CallExpr>(*BI)) + if (const DeclRefExpr *DR = + dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts())) + if (const FunctionDecl *calleeD = + dyn_cast<FunctionDecl>(DR->getDecl())) + if (calleeD->isInlineSpecified() && + calleeD->getStorageClass() == FunctionDecl::Static) { + // Have we analyzed this static inline function before? + unsigned &visited = VisitedFD[calleeD]; + if (!visited) { + // Mark the callee visited prior to analyzing it + // so we terminate in case of recursion. + visited = 1; + IssueWarnings(DefaultPolicy, calleeD, QualType(), true); + } + } + } + } + } } |