aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/AnalysisBasedWarnings.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-03-23 00:13:23 +0000
committerTed Kremenek <kremenek@apple.com>2010-03-23 00:13:23 +0000
commitd064fdc4b7b64ca55b40b70490c79d6f569df78e (patch)
tree07a0c6fb87b558bbfb070a1aba01717486b9fe47 /lib/Sema/AnalysisBasedWarnings.cpp
parent22f757b38da3fc9f17ea9e99524064fdfbca3456 (diff)
Only perform CFG-based warnings on 'static inline' functions that
are called (transitively) by regular functions/blocks within a translation untion. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99233 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp92
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);
+ }
+ }
+ }
+ }
+ }
}