Newer
Older
AccessKind AK, SourceLocation Loc) {
Caitlin Sadowski
committed
assert((POK == POK_VarAccess || POK == POK_VarDereference)
&& "Only works for variables");
unsigned DiagID = POK == POK_VarAccess?
diag::warn_variable_requires_any_lock:
diag::warn_var_deref_requires_any_lock;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
<< D->getName() << getLockKindFromAccessKind(AK));
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
Name LockName, LockKind LK, SourceLocation Loc) {
Caitlin Sadowski
committed
unsigned DiagID = 0;
switch (POK) {
case POK_VarAccess:
DiagID = diag::warn_variable_requires_lock;
break;
case POK_VarDereference:
DiagID = diag::warn_var_deref_requires_lock;
break;
case POK_FunctionCall:
DiagID = diag::warn_fun_requires_lock;
break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
<< D->getName() << LockName << LK);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
PartialDiagnosticAt Warning(Loc,
S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
};
}
}
David Blaikie
committed
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
clang::sema::AnalysisBasedWarnings::Policy::Policy() {
Ted Kremenek
committed
enableCheckFallThrough = 1;
enableCheckUnreachable = 0;
enableThreadSafetyAnalysis = 0;
Ted Kremenek
committed
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
: S(s),
NumFunctionsAnalyzed(0),
NumFunctionsWithBadCFGs(0),
NumCFGBlocks(0),
MaxCFGBlocksPerFunction(0),
NumUninitAnalysisFunctions(0),
NumUninitAnalysisVariables(0),
MaxUninitAnalysisVariablesPerFunction(0),
NumUninitAnalysisBlockVisits(0),
MaxUninitAnalysisBlockVisitsPerFunction(0) {
DiagnosticsEngine &D = S.getDiagnostics();
DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
DiagnosticsEngine::Ignored);
DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
(D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
DiagnosticsEngine::Ignored);
Ted Kremenek
committed
}
Ted Kremenek
committed
static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) {
Chris Lattner
committed
for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
Ted Kremenek
committed
i = fscope->PossiblyUnreachableDiags.begin(),
e = fscope->PossiblyUnreachableDiags.end();
i != e; ++i) {
const sema::PossiblyUnreachableDiag &D = *i;
S.Diag(D.Loc, D.PD);
}
}
void clang::sema::
AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
sema::FunctionScopeInfo *fscope,
const Decl *D, const BlockExpr *blkExpr) {
Ted Kremenek
committed
// We avoid doing analysis-based warnings when there are errors for
// two reasons:
// (1) The CFGs often can't be constructed (if the body is invalid), so
// don't bother trying.
// (2) The code already has problems; running the analysis just takes more
// time.
DiagnosticsEngine &Diags = S.getDiagnostics();
Ted Kremenek
committed
// Do not do any analysis for declarations in system headers if we are
// going to just ignore them.
Ted Kremenek
committed
if (Diags.getSuppressSystemWarnings() &&
S.SourceMgr.isInSystemHeader(D->getLocation()))
return;
// For code in dependent contexts, we'll do this at instantiation time.
if (cast<DeclContext>(D)->isDependentContext())
return;
Ted Kremenek
committed
Ted Kremenek
committed
if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) {
// Flush out any possibly unreachable diagnostics.
flushDiagnostics(S, fscope);
return;
}
Ted Kremenek
committed
const Stmt *Body = D->getBody();
assert(Body);
Jordy Rose
committed
AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D);
Ted Kremenek
committed
Ted Kremenek
committed
// 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.
Ted Kremenek
committed
AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
AC.getCFGBuildOptions().AddEHEdges = false;
AC.getCFGBuildOptions().AddInitializers = true;
AC.getCFGBuildOptions().AddImplicitDtors = true;
Ted Kremenek
committed
// Force that certain expressions appear as CFGElements in the CFG. This
// is used to speed up various analyses.
// FIXME: This isn't the right factoring. This is here for initial
// prototyping, but we need a way for analyses to say what expressions they
// expect to always be CFGElements and then fill in the BuildOptions
// appropriately. This is essentially a layering violation.
DeLesley Hutchins
committed
if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis) {
// Unreachable code analysis and thread safety require a linearized CFG.
Ted Kremenek
committed
AC.getCFGBuildOptions().setAllAlwaysAdd();
}
else {
AC.getCFGBuildOptions()
.setAlwaysAdd(Stmt::BinaryOperatorClass)
.setAlwaysAdd(Stmt::BlockExprClass)
.setAlwaysAdd(Stmt::CStyleCastExprClass)
.setAlwaysAdd(Stmt::DeclRefExprClass)
.setAlwaysAdd(Stmt::ImplicitCastExprClass)
.setAlwaysAdd(Stmt::UnaryOperatorClass)
.setAlwaysAdd(Stmt::AttributedStmtClass);
Ted Kremenek
committed
}
Ted Kremenek
committed
// Construct the analysis context with the specified CFG build options.
Ted Kremenek
committed
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
Ted Kremenek
committed
bool analyzed = false;
// Register the expressions with the CFGBuilder.
Chris Lattner
committed
for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
i = fscope->PossiblyUnreachableDiags.begin(),
e = fscope->PossiblyUnreachableDiags.end();
i != e; ++i) {
if (const Stmt *stmt = i->stmt)
AC.registerForcedBlockExpression(stmt);
}
if (AC.getCFG()) {
analyzed = true;
Chris Lattner
committed
for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
i = fscope->PossiblyUnreachableDiags.begin(),
e = fscope->PossiblyUnreachableDiags.end();
i != e; ++i)
{
const sema::PossiblyUnreachableDiag &D = *i;
bool processed = false;
if (const Stmt *stmt = i->stmt) {
const CFGBlock *block = AC.getBlockForRegisteredExpression(stmt);
Eli Friedman
committed
CFGReverseBlockReachabilityAnalysis *cra =
AC.getCFGReachablityAnalysis();
// FIXME: We should be able to assert that block is non-null, but
// the CFG analysis can skip potentially-evaluated expressions in
// edge cases; see test/Sema/vla-2.c.
if (block && cra) {
Ted Kremenek
committed
// Can this block be reached from the entrance?
if (cra->isReachable(&AC.getCFG()->getEntry(), block))
Ted Kremenek
committed
S.Diag(D.Loc, D.PD);
processed = true;
Ted Kremenek
committed
}
}
if (!processed) {
// Emit the warning anyway if we cannot map to a basic block.
S.Diag(D.Loc, D.PD);
Ted Kremenek
committed
}
}
Ted Kremenek
committed
if (!analyzed)
flushDiagnostics(S, fscope);
}
Ted Kremenek
committed
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
Ted Kremenek
committed
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
: (isa<CXXMethodDecl>(D) &&
cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
cast<CXXMethodDecl>(D)->getParent()->isLambda())
? CheckFallThroughDiagnostics::MakeForLambda()
: CheckFallThroughDiagnostics::MakeForFunction(D));
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
Ted Kremenek
committed
}
// Warning: check for unreachable code
if (P.enableCheckUnreachable) {
// Only check for unreachable code on non-template instantiations.
// Different template instantiations can effectively change the control-flow
// and it is very difficult to prove that a snippet of code in a template
// is unreachable for all instantiations.
Ted Kremenek
committed
bool isTemplateInstantiation = false;
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
isTemplateInstantiation = Function->isTemplateInstantiation();
if (!isTemplateInstantiation)
CheckUnreachable(S, AC);
}
// Check for thread safety violations
if (P.enableThreadSafetyAnalysis) {
SourceLocation FL = AC.getDecl()->getLocation();
SourceLocation FEL = AC.getDecl()->getLocEnd();
thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
thread_safety::runThreadSafetyAnalysis(AC, Reporter);
Reporter.emitDiagnostics();
}
if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
Richard Smith
committed
!= DiagnosticsEngine::Ignored ||
Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
!= DiagnosticsEngine::Ignored ||
Ted Kremenek
committed
Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart())
!= DiagnosticsEngine::Ignored) {
Ted Kremenek
committed
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
Benjamin Kramer
committed
std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats));
runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
reporter, stats);
if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
++NumUninitAnalysisFunctions;
NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
MaxUninitAnalysisVariablesPerFunction =
std::max(MaxUninitAnalysisVariablesPerFunction,
stats.NumVariablesAnalyzed);
MaxUninitAnalysisBlockVisitsPerFunction =
std::max(MaxUninitAnalysisBlockVisitsPerFunction,
stats.NumBlockVisits);
}
}
}
if (Diags.getDiagnosticLevel(diag::warn_unannotated_fallthrough,
D->getLocStart()) != DiagnosticsEngine::Ignored) {
DiagnoseSwitchLabelsFallthrough(S, AC);
}
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
if (CFG *cfg = AC.getCFG()) {
// If we successfully built a CFG for this context, record some more
// detail information about it.
NumCFGBlocks += cfg->getNumBlockIDs();
MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
cfg->getNumBlockIDs());
} else {
++NumFunctionsWithBadCFGs;
Ted Kremenek
committed
}
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
void clang::sema::AnalysisBasedWarnings::PrintStats() const {
llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
unsigned AvgCFGBlocksPerFunction =
!NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
<< NumFunctionsWithBadCFGs << " w/o CFGs).\n"
<< " " << NumCFGBlocks << " CFG blocks built.\n"
<< " " << AvgCFGBlocksPerFunction
<< " average CFG blocks per function.\n"
<< " " << MaxCFGBlocksPerFunction
<< " max CFG blocks per function.\n";
unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
: NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
: NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
llvm::errs() << NumUninitAnalysisFunctions
<< " functions analyzed for uninitialiazed variables\n"
<< " " << NumUninitAnalysisVariables << " variables analyzed.\n"
<< " " << AvgUninitVariablesPerFunction
<< " average variables per function.\n"
<< " " << MaxUninitAnalysisVariablesPerFunction
<< " max variables per function.\n"
<< " " << NumUninitAnalysisBlockVisits << " block visits.\n"
<< " " << AvgUninitBlockVisitsPerFunction
<< " average block visits per function.\n"
<< " " << MaxUninitAnalysisBlockVisitsPerFunction
<< " max block visits per function.\n";
}