2008-07-02 08:03:09 +08:00
|
|
|
//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// "Meta" ASTConsumer for running different source analyses.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-03-09 07:16:38 +08:00
|
|
|
#define DEBUG_TYPE "AnalysisConsumer"
|
|
|
|
|
2011-02-15 02:13:11 +08:00
|
|
|
#include "AnalysisConsumer.h"
|
2008-07-02 08:03:09 +08:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
2009-12-16 13:29:59 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2008-07-02 08:03:09 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-11-05 10:41:58 +08:00
|
|
|
#include "clang/AST/ParentMap.h"
|
2012-03-14 03:32:00 +08:00
|
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Analysis/Analyses/LiveVariables.h"
|
2009-11-05 10:41:58 +08:00
|
|
|
#include "clang/Analysis/CFG.h"
|
2012-03-09 07:16:38 +08:00
|
|
|
#include "clang/Analysis/CallGraph.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2010-12-24 03:38:26 +08:00
|
|
|
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
|
|
|
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
|
2011-02-10 09:03:03 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
|
|
|
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
|
2011-02-10 09:03:03 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
|
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
|
2012-03-09 07:16:38 +08:00
|
|
|
#include "llvm/ADT/DepthFirstIterator.h"
|
2009-08-23 20:08:50 +08:00
|
|
|
#include "llvm/ADT/OwningPtr.h"
|
2012-04-13 06:36:48 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2012-02-28 05:33:16 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#include "llvm/Support/Program.h"
|
|
|
|
#include "llvm/Support/Timer.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-03-14 03:32:13 +08:00
|
|
|
#include <queue>
|
|
|
|
|
2008-07-02 08:03:09 +08:00
|
|
|
using namespace clang;
|
2010-12-23 15:20:52 +08:00
|
|
|
using namespace ento;
|
2012-03-09 07:16:38 +08:00
|
|
|
using llvm::SmallPtrSet;
|
2008-07-02 08:03:09 +08:00
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
static ExplodedNode::Auditor* CreateUbiViz();
|
2008-12-22 09:52:37 +08:00
|
|
|
|
2012-03-10 05:14:01 +08:00
|
|
|
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
|
2012-12-08 05:51:47 +08:00
|
|
|
STATISTIC(NumFunctionsAnalyzed,
|
2012-12-18 04:08:54 +08:00
|
|
|
"The # of functions and blocks analyzed (as top level "
|
|
|
|
"with inlining turned on).");
|
2012-04-03 10:05:47 +08:00
|
|
|
STATISTIC(NumBlocksInAnalyzedFunctions,
|
2012-12-18 04:08:54 +08:00
|
|
|
"The # of basic blocks in the analyzed functions.");
|
2012-04-03 10:05:47 +08:00
|
|
|
STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
|
2012-07-06 04:44:02 +08:00
|
|
|
STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
|
2012-03-09 07:16:38 +08:00
|
|
|
|
2009-07-28 06:13:39 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2011-09-27 09:43:33 +08:00
|
|
|
// Special PathDiagnosticConsumers.
|
2009-07-28 06:13:39 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-12-19 09:35:35 +08:00
|
|
|
static void createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
|
|
|
|
PathDiagnosticConsumers &C,
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
const std::string &prefix,
|
|
|
|
const Preprocessor &PP) {
|
2012-12-19 09:35:35 +08:00
|
|
|
createHTMLDiagnosticConsumer(AnalyzerOpts, C,
|
|
|
|
llvm::sys::path::parent_path(prefix), PP);
|
|
|
|
createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
|
2009-07-28 06:13:39 +08:00
|
|
|
}
|
|
|
|
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
namespace {
|
|
|
|
class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
|
|
|
|
DiagnosticsEngine &Diag;
|
|
|
|
public:
|
|
|
|
ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {}
|
|
|
|
virtual ~ClangDiagPathDiagConsumer() {}
|
|
|
|
virtual StringRef getName() const { return "ClangDiags"; }
|
|
|
|
virtual PathGenerationScheme getGenerationScheme() const { return None; }
|
|
|
|
|
|
|
|
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
|
|
|
|
FilesMade *filesMade) {
|
|
|
|
for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
|
|
|
|
E = Diags.end(); I != E; ++I) {
|
|
|
|
const PathDiagnostic *PD = *I;
|
2012-08-31 08:36:26 +08:00
|
|
|
StringRef desc = PD->getShortDescription();
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
SmallString<512> TmpStr;
|
|
|
|
llvm::raw_svector_ostream Out(TmpStr);
|
|
|
|
for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) {
|
|
|
|
if (*I == '%')
|
|
|
|
Out << "%%";
|
|
|
|
else
|
|
|
|
Out << *I;
|
|
|
|
}
|
|
|
|
Out.flush();
|
|
|
|
unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning,
|
|
|
|
TmpStr);
|
|
|
|
SourceLocation L = PD->getLocation().asLocation();
|
|
|
|
DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag);
|
|
|
|
|
|
|
|
// Get the ranges from the last point in the path.
|
|
|
|
ArrayRef<SourceRange> Ranges = PD->path.back()->getRanges();
|
|
|
|
|
|
|
|
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
|
|
|
|
E = Ranges.end(); I != E; ++I) {
|
|
|
|
diagBuilder << *I;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2008-07-02 08:03:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// AnalysisConsumer declaration.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2012-03-14 03:32:00 +08:00
|
|
|
class AnalysisConsumer : public ASTConsumer,
|
|
|
|
public RecursiveASTVisitor<AnalysisConsumer> {
|
2012-10-11 01:55:40 +08:00
|
|
|
enum {
|
|
|
|
AM_None = 0,
|
|
|
|
AM_Syntax = 0x1,
|
|
|
|
AM_Path = 0x2
|
2012-03-14 03:32:00 +08:00
|
|
|
};
|
2012-10-11 01:55:40 +08:00
|
|
|
typedef unsigned AnalysisMode;
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
/// Mode of the analyzes while recursively visiting Decls.
|
|
|
|
AnalysisMode RecVisitorMode;
|
|
|
|
/// Bug Reporter to use while recursively visiting Decls.
|
|
|
|
BugReporter *RecVisitorBR;
|
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
public:
|
2011-08-13 07:37:29 +08:00
|
|
|
ASTContext *Ctx;
|
2009-11-11 14:28:42 +08:00
|
|
|
const Preprocessor &PP;
|
|
|
|
const std::string OutDir;
|
2012-08-31 12:36:05 +08:00
|
|
|
AnalyzerOptionsRef Opts;
|
2011-08-17 05:24:21 +08:00
|
|
|
ArrayRef<std::string> Plugins;
|
2009-08-03 11:27:37 +08:00
|
|
|
|
2012-04-13 06:36:48 +08:00
|
|
|
/// \brief Stores the declarations from the local translation unit.
|
|
|
|
/// Note, we pre-compute the local declarations at parse time as an
|
|
|
|
/// optimization to make sure we do not deserialize everything from disk.
|
|
|
|
/// The local declaration to all declarations ratio might be very small when
|
|
|
|
/// working with a PCH file.
|
|
|
|
SetOfDecls LocalTUDecls;
|
2012-04-27 08:38:33 +08:00
|
|
|
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
// Set of PathDiagnosticConsumers. Owned by AnalysisManager.
|
|
|
|
PathDiagnosticConsumers PathConsumers;
|
2009-08-03 11:27:37 +08:00
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
StoreManagerCreator CreateStoreMgr;
|
|
|
|
ConstraintManagerCreator CreateConstraintMgr;
|
2008-07-02 08:03:09 +08:00
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<CheckerManager> checkerMgr;
|
|
|
|
OwningPtr<AnalysisManager> Mgr;
|
2009-08-03 11:13:46 +08:00
|
|
|
|
2012-03-06 04:53:59 +08:00
|
|
|
/// Time the analyzes time of each translation unit.
|
|
|
|
static llvm::Timer* TUTotalTimer;
|
|
|
|
|
2012-03-30 13:48:10 +08:00
|
|
|
/// The information about analyzed functions shared throughout the
|
|
|
|
/// translation unit.
|
|
|
|
FunctionSummariesTy FunctionSummaries;
|
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
AnalysisConsumer(const Preprocessor& pp,
|
|
|
|
const std::string& outdir,
|
2012-08-31 12:36:05 +08:00
|
|
|
AnalyzerOptionsRef opts,
|
2011-08-17 05:24:21 +08:00
|
|
|
ArrayRef<std::string> plugins)
|
2012-10-11 01:55:40 +08:00
|
|
|
: RecVisitorMode(0), RecVisitorBR(0),
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
|
2009-11-11 14:28:42 +08:00
|
|
|
DigestAnalyzerOptions();
|
2012-08-31 12:36:05 +08:00
|
|
|
if (Opts->PrintStats) {
|
2012-03-06 04:53:59 +08:00
|
|
|
llvm::EnableStatistics();
|
|
|
|
TUTotalTimer = new llvm::Timer("Analyzer Total Time");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~AnalysisConsumer() {
|
2012-08-31 12:36:05 +08:00
|
|
|
if (Opts->PrintStats)
|
2012-03-06 04:53:59 +08:00
|
|
|
delete TUTotalTimer;
|
2009-11-11 14:28:42 +08:00
|
|
|
}
|
2009-07-30 17:11:52 +08:00
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
void DigestAnalyzerOptions() {
|
2011-09-26 08:51:36 +08:00
|
|
|
// Create the PathDiagnosticConsumer.
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics()));
|
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
if (!OutDir.empty()) {
|
2012-08-31 12:36:05 +08:00
|
|
|
switch (Opts->AnalysisDiagOpt) {
|
2009-11-11 14:28:42 +08:00
|
|
|
default:
|
2009-07-30 17:11:52 +08:00
|
|
|
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
|
2012-12-19 09:35:35 +08:00
|
|
|
case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\
|
|
|
|
break;
|
2012-08-31 12:35:58 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2009-07-30 17:11:52 +08:00
|
|
|
}
|
2012-08-31 12:36:05 +08:00
|
|
|
} else if (Opts->AnalysisDiagOpt == PD_TEXT) {
|
2010-12-03 09:17:19 +08:00
|
|
|
// Create the text client even without a specified output file since
|
|
|
|
// it just uses diagnostic notes.
|
2012-12-19 09:35:35 +08:00
|
|
|
createTextPathDiagnosticConsumer(*Opts.getPtr(), PathConsumers, "", PP);
|
2009-11-11 14:28:42 +08:00
|
|
|
}
|
2009-07-30 17:11:52 +08:00
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
// Create the analyzer component creators.
|
2012-08-31 12:36:05 +08:00
|
|
|
switch (Opts->AnalysisStoreOpt) {
|
2011-02-15 02:13:17 +08:00
|
|
|
default:
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Unknown store manager.");
|
2009-07-30 17:11:52 +08:00
|
|
|
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
|
2011-02-15 02:13:17 +08:00
|
|
|
case NAME##Model: CreateStoreMgr = CREATEFN; break;
|
2012-08-31 12:35:58 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2009-11-11 14:28:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-08-31 12:36:05 +08:00
|
|
|
switch (Opts->AnalysisConstraintsOpt) {
|
2011-02-15 02:13:17 +08:00
|
|
|
default:
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Unknown store manager.");
|
2009-07-30 17:11:52 +08:00
|
|
|
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
|
2011-02-15 02:13:17 +08:00
|
|
|
case NAME##Model: CreateConstraintMgr = CREATEFN; break;
|
2012-08-31 12:35:58 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2009-07-30 17:11:52 +08:00
|
|
|
}
|
2009-11-11 14:28:42 +08:00
|
|
|
}
|
2010-02-15 03:08:51 +08:00
|
|
|
|
2012-03-14 03:32:00 +08:00
|
|
|
void DisplayFunction(const Decl *D, AnalysisMode Mode) {
|
2012-08-31 12:36:05 +08:00
|
|
|
if (!Opts->AnalyzerDisplayProgress)
|
2009-11-11 14:28:42 +08:00
|
|
|
return;
|
2010-02-15 03:08:51 +08:00
|
|
|
|
2009-12-08 06:06:12 +08:00
|
|
|
SourceManager &SM = Mgr->getASTContext().getSourceManager();
|
|
|
|
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
|
2010-11-12 15:15:47 +08:00
|
|
|
if (Loc.isValid()) {
|
2012-03-14 03:32:00 +08:00
|
|
|
llvm::errs() << "ANALYZE";
|
2012-10-11 01:55:40 +08:00
|
|
|
|
|
|
|
if (Mode == AM_Syntax)
|
|
|
|
llvm::errs() << " (Syntax)";
|
|
|
|
else if (Mode == AM_Path)
|
|
|
|
llvm::errs() << " (Path)";
|
|
|
|
else
|
|
|
|
assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
|
|
|
|
|
2012-03-14 03:32:00 +08:00
|
|
|
llvm::errs() << ": " << Loc.getFilename();
|
2010-11-12 15:15:47 +08:00
|
|
|
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
|
|
|
|
const NamedDecl *ND = cast<NamedDecl>(D);
|
2011-10-15 02:45:37 +08:00
|
|
|
llvm::errs() << ' ' << *ND << '\n';
|
2010-11-12 15:15:47 +08:00
|
|
|
}
|
|
|
|
else if (isa<BlockDecl>(D)) {
|
|
|
|
llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
|
|
|
|
<< Loc.getColumn() << '\n';
|
|
|
|
}
|
|
|
|
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
|
|
|
Selector S = MD->getSelector();
|
|
|
|
llvm::errs() << ' ' << S.getAsString();
|
|
|
|
}
|
2010-10-23 06:08:29 +08:00
|
|
|
}
|
2009-11-11 14:28:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
virtual void Initialize(ASTContext &Context) {
|
|
|
|
Ctx = &Context;
|
2012-08-31 12:36:05 +08:00
|
|
|
checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
|
2011-08-17 05:24:21 +08:00
|
|
|
PP.getDiagnostics()));
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
Mgr.reset(new AnalysisManager(*Ctx,
|
|
|
|
PP.getDiagnostics(),
|
|
|
|
PP.getLangOpts(),
|
|
|
|
PathConsumers,
|
|
|
|
CreateStoreMgr,
|
|
|
|
CreateConstraintMgr,
|
2011-02-15 02:13:31 +08:00
|
|
|
checkerMgr.get(),
|
2012-08-31 12:36:05 +08:00
|
|
|
*Opts));
|
2009-11-11 14:28:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-04-13 06:36:48 +08:00
|
|
|
/// \brief Store the top level decls in the set to be processed later on.
|
|
|
|
/// (Doing this pre-processing avoids deserialization of data from PCH.)
|
|
|
|
virtual bool HandleTopLevelDecl(DeclGroupRef D);
|
|
|
|
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
|
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
virtual void HandleTranslationUnit(ASTContext &C);
|
2011-01-21 01:09:48 +08:00
|
|
|
|
2012-12-08 05:51:47 +08:00
|
|
|
/// \brief Determine which inlining mode should be used when this function is
|
|
|
|
/// analyzed. For example, determines if the callees should be inlined.
|
|
|
|
ExprEngine::InliningModes
|
2012-12-15 03:08:17 +08:00
|
|
|
getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
|
2012-12-08 05:51:47 +08:00
|
|
|
|
2012-04-13 06:36:48 +08:00
|
|
|
/// \brief Build the call graph for all the top level decls of this TU and
|
|
|
|
/// use it to define the order in which the functions should be visited.
|
2012-10-11 01:55:37 +08:00
|
|
|
void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
/// \brief Run analyzes(syntax or path sensitive) on the given function.
|
|
|
|
/// \param Mode - determines if we are requesting syntax only or path
|
|
|
|
/// sensitive only analysis.
|
|
|
|
/// \param VisitedCallees - The output parameter, which is populated with the
|
|
|
|
/// set of functions which should be considered analyzed after analyzing the
|
|
|
|
/// given root function.
|
2012-04-13 06:36:48 +08:00
|
|
|
void HandleCode(Decl *D, AnalysisMode Mode,
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes IMode = ExprEngine::Inline_None,
|
2012-04-13 06:36:48 +08:00
|
|
|
SetOfConstDecls *VisitedCallees = 0);
|
2012-03-14 03:32:00 +08:00
|
|
|
|
2012-12-08 05:51:47 +08:00
|
|
|
void RunPathSensitiveChecks(Decl *D,
|
|
|
|
ExprEngine::InliningModes IMode,
|
|
|
|
SetOfConstDecls *VisitedCallees);
|
2012-04-13 06:36:48 +08:00
|
|
|
void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes IMode,
|
2012-04-13 06:36:48 +08:00
|
|
|
SetOfConstDecls *VisitedCallees);
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
/// Visitors for the RecursiveASTVisitor.
|
2012-05-12 07:15:18 +08:00
|
|
|
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
/// Handle callbacks for arbitrary Decls.
|
|
|
|
bool VisitDecl(Decl *D) {
|
2012-10-11 01:55:40 +08:00
|
|
|
AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
|
|
|
|
if (Mode & AM_Syntax)
|
|
|
|
checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
|
2012-03-14 03:32:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VisitFunctionDecl(FunctionDecl *FD) {
|
|
|
|
IdentifierInfo *II = FD->getIdentifier();
|
|
|
|
if (II && II->getName().startswith("__inline"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// We skip function template definitions, as their semantics is
|
|
|
|
// only determined when they are instantiated.
|
|
|
|
if (FD->isThisDeclarationADefinition() &&
|
|
|
|
!FD->isDependentContext()) {
|
2012-12-08 05:51:47 +08:00
|
|
|
assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
|
2012-03-14 03:32:00 +08:00
|
|
|
HandleCode(FD, RecVisitorMode);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
|
2012-12-08 05:51:47 +08:00
|
|
|
if (MD->isThisDeclarationADefinition()) {
|
|
|
|
assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
|
2012-03-14 03:32:00 +08:00
|
|
|
HandleCode(MD, RecVisitorMode);
|
2012-12-08 05:51:47 +08:00
|
|
|
}
|
2012-03-14 03:32:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-12-21 09:19:15 +08:00
|
|
|
|
|
|
|
bool VisitBlockDecl(BlockDecl *BD) {
|
|
|
|
if (BD->hasBody()) {
|
|
|
|
assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
|
|
|
|
HandleCode(BD, RecVisitorMode);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2012-04-13 06:36:48 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
void storeTopLevelDecls(DeclGroupRef DG);
|
|
|
|
|
|
|
|
/// \brief Check if we should skip (not analyze) the given function.
|
2012-10-11 01:55:40 +08:00
|
|
|
AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
|
2012-04-13 06:36:48 +08:00
|
|
|
|
2009-11-11 14:28:42 +08:00
|
|
|
};
|
2008-07-02 08:03:09 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2012-03-14 03:32:00 +08:00
|
|
|
|
2008-07-02 08:03:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// AnalysisConsumer implementation.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2012-03-06 04:53:59 +08:00
|
|
|
llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
|
2008-07-02 08:03:09 +08:00
|
|
|
|
2012-04-13 06:36:48 +08:00
|
|
|
bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
|
|
|
|
storeTopLevelDecls(DG);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
|
|
|
|
storeTopLevelDecls(DG);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
|
|
|
|
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
|
|
|
|
|
|
|
|
// Skip ObjCMethodDecl, wait for the objc container to avoid
|
|
|
|
// analyzing twice.
|
|
|
|
if (isa<ObjCMethodDecl>(*I))
|
|
|
|
continue;
|
|
|
|
|
2012-04-27 12:54:28 +08:00
|
|
|
LocalTUDecls.push_back(*I);
|
2012-04-13 06:36:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-15 03:08:17 +08:00
|
|
|
static bool shouldSkipFunction(const Decl *D,
|
|
|
|
SetOfConstDecls Visited,
|
|
|
|
SetOfConstDecls VisitedAsTopLevel) {
|
|
|
|
if (VisitedAsTopLevel.count(D))
|
2012-12-08 05:51:47 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// We want to re-analyse the functions as top level in the following cases:
|
2012-08-31 07:42:02 +08:00
|
|
|
// - The 'init' methods should be reanalyzed because
|
|
|
|
// ObjCNonNilReturnValueChecker assumes that '[super init]' never returns
|
2012-12-08 05:51:47 +08:00
|
|
|
// 'nil' and unless we analyze the 'init' functions as top level, we will
|
|
|
|
// not catch errors within defensive code.
|
2012-08-31 07:42:02 +08:00
|
|
|
// - We want to reanalyze all ObjC methods as top level to report Retain
|
|
|
|
// Count naming convention errors more aggressively.
|
2012-12-15 03:08:17 +08:00
|
|
|
if (isa<ObjCMethodDecl>(D))
|
2012-08-31 07:42:02 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Otherwise, if we visited the function before, do not reanalyze it.
|
2012-12-15 03:08:17 +08:00
|
|
|
return Visited.count(D);
|
2012-08-31 07:42:02 +08:00
|
|
|
}
|
|
|
|
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes
|
2012-12-15 03:08:17 +08:00
|
|
|
AnalysisConsumer::getInliningModeForFunction(const Decl *D,
|
|
|
|
SetOfConstDecls Visited) {
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes HowToInline =
|
|
|
|
(Mgr->shouldInlineCall()) ? ExprEngine::Inline_All :
|
|
|
|
ExprEngine::Inline_None;
|
|
|
|
|
|
|
|
// We want to reanalyze all ObjC methods as top level to report Retain
|
|
|
|
// Count naming convention errors more aggressively. But we can turn off
|
|
|
|
// inlining when reanalyzing an already inlined function.
|
2012-12-15 03:08:17 +08:00
|
|
|
if (Visited.count(D)) {
|
|
|
|
assert(isa<ObjCMethodDecl>(D) &&
|
2012-12-08 05:51:47 +08:00
|
|
|
"We are only reanalyzing ObjCMethods.");
|
2012-12-15 03:08:17 +08:00
|
|
|
const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
|
2012-12-08 05:51:47 +08:00
|
|
|
if (ObjCM->getMethodFamily() != OMF_init)
|
|
|
|
HowToInline = ExprEngine::Inline_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
return HowToInline;
|
|
|
|
}
|
|
|
|
|
2012-10-11 01:55:37 +08:00
|
|
|
void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
|
2012-12-21 09:30:23 +08:00
|
|
|
// Otherwise, use the Callgraph to derive the order.
|
|
|
|
// Build the Call Graph.
|
|
|
|
CallGraph CG;
|
|
|
|
|
|
|
|
// Add all the top level declarations to the graph.
|
2012-06-01 02:07:55 +08:00
|
|
|
// Note: CallGraph can trigger deserialization of more items from a pch
|
|
|
|
// (though HandleInterestingDecl); triggering additions to LocalTUDecls.
|
|
|
|
// We rely on random access to add the initially processed Decls to CG.
|
|
|
|
for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
|
2012-05-31 07:14:48 +08:00
|
|
|
CG.addToCallGraph(LocalTUDecls[i]);
|
|
|
|
}
|
2012-03-09 07:16:38 +08:00
|
|
|
|
2012-12-21 09:30:23 +08:00
|
|
|
// Find the top level nodes - children of root + the unreachable (parentless)
|
|
|
|
// nodes.
|
|
|
|
llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
|
|
|
|
for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
|
|
|
|
TE = CG.parentless_end(); TI != TE; ++TI) {
|
|
|
|
TopLevelFunctions.push_back(*TI);
|
|
|
|
NumFunctionTopLevel++;
|
|
|
|
}
|
|
|
|
CallGraphNode *Entry = CG.getRoot();
|
|
|
|
for (CallGraphNode::iterator I = Entry->begin(),
|
|
|
|
E = Entry->end(); I != E; ++I) {
|
|
|
|
TopLevelFunctions.push_back(*I);
|
|
|
|
NumFunctionTopLevel++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the nodes are sorted in order reverse of their definition in the
|
|
|
|
// translation unit. This step is very important for performance. It ensures
|
|
|
|
// that we analyze the root functions before the externally available
|
|
|
|
// subroutines.
|
|
|
|
std::deque<CallGraphNode*> BFSQueue;
|
|
|
|
for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
|
|
|
|
TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
|
|
|
|
TI != TE; ++TI)
|
|
|
|
BFSQueue.push_back(*TI);
|
|
|
|
|
|
|
|
// BFS over all of the functions, while skipping the ones inlined into
|
|
|
|
// the previously processed functions. Use external Visited set, which is
|
|
|
|
// also modified when we inline a function.
|
2012-12-15 03:08:17 +08:00
|
|
|
SetOfConstDecls Visited;
|
|
|
|
SetOfConstDecls VisitedAsTopLevel;
|
2012-12-21 09:30:23 +08:00
|
|
|
while(!BFSQueue.empty()) {
|
|
|
|
CallGraphNode *N = BFSQueue.front();
|
|
|
|
BFSQueue.pop_front();
|
|
|
|
|
|
|
|
// Push the children into the queue.
|
|
|
|
for (CallGraphNode::const_iterator CI = N->begin(),
|
|
|
|
CE = N->end(); CI != CE; ++CI) {
|
|
|
|
if (!shouldSkipFunction((*CI)->getDecl(), Visited, VisitedAsTopLevel))
|
|
|
|
BFSQueue.push_back(*CI);
|
|
|
|
}
|
2012-07-03 04:21:48 +08:00
|
|
|
|
2012-12-15 03:08:17 +08:00
|
|
|
Decl *D = N->getDecl();
|
2012-12-21 09:30:23 +08:00
|
|
|
assert(D);
|
2012-12-15 03:08:17 +08:00
|
|
|
|
2012-03-14 03:32:13 +08:00
|
|
|
// Skip the functions which have been processed already or previously
|
|
|
|
// inlined.
|
2012-12-15 03:08:17 +08:00
|
|
|
if (shouldSkipFunction(D, Visited, VisitedAsTopLevel))
|
2012-03-14 03:32:13 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Analyze the function.
|
2012-04-13 06:36:48 +08:00
|
|
|
SetOfConstDecls VisitedCallees;
|
2012-12-08 05:51:47 +08:00
|
|
|
|
2012-12-15 03:08:17 +08:00
|
|
|
HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
|
2012-08-31 03:26:43 +08:00
|
|
|
(Mgr->options.InliningMode == All ? 0 : &VisitedCallees));
|
2012-03-14 03:32:13 +08:00
|
|
|
|
|
|
|
// Add the visited callees to the global visited set.
|
2012-04-27 08:38:33 +08:00
|
|
|
for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
|
|
|
|
E = VisitedCallees.end(); I != E; ++I) {
|
2012-12-15 03:08:17 +08:00
|
|
|
Visited.insert(*I);
|
2012-03-14 03:32:13 +08:00
|
|
|
}
|
2012-12-15 03:08:17 +08:00
|
|
|
VisitedAsTopLevel.insert(D);
|
2012-03-09 07:16:38 +08:00
|
|
|
}
|
2011-08-28 05:28:09 +08:00
|
|
|
}
|
|
|
|
|
2011-01-21 01:09:48 +08:00
|
|
|
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
|
2012-03-14 03:32:00 +08:00
|
|
|
// Don't run the actions if an error has occurred with parsing the file.
|
|
|
|
DiagnosticsEngine &Diags = PP.getDiagnostics();
|
|
|
|
if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
|
|
|
|
return;
|
|
|
|
|
2012-01-08 00:49:46 +08:00
|
|
|
{
|
2012-03-06 04:53:59 +08:00
|
|
|
if (TUTotalTimer) TUTotalTimer->startTimer();
|
|
|
|
|
2012-01-08 00:49:46 +08:00
|
|
|
// Introduce a scope to destroy BR before Mgr.
|
|
|
|
BugReporter BR(*Mgr);
|
|
|
|
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
|
|
|
|
checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
// Run the AST-only checks using the order in which functions are defined.
|
|
|
|
// If inlining is not turned on, use the simplest function order for path
|
|
|
|
// sensitive analyzes as well.
|
2012-10-11 01:55:40 +08:00
|
|
|
RecVisitorMode = AM_Syntax;
|
|
|
|
if (!Mgr->shouldInlineCall())
|
|
|
|
RecVisitorMode |= AM_Path;
|
2012-03-14 03:32:00 +08:00
|
|
|
RecVisitorBR = &BR;
|
2012-04-13 06:36:48 +08:00
|
|
|
|
|
|
|
// Process all the top level declarations.
|
2012-04-27 08:38:33 +08:00
|
|
|
//
|
2012-04-27 12:54:28 +08:00
|
|
|
// Note: TraverseDecl may modify LocalTUDecls, but only by appending more
|
|
|
|
// entries. Thus we don't use an iterator, but rely on LocalTUDecls
|
|
|
|
// random access. By doing so, we automatically compensate for iterators
|
|
|
|
// possibly being invalidated, although this is a bit slower.
|
2012-06-01 02:07:55 +08:00
|
|
|
const unsigned LocalTUDeclsSize = LocalTUDecls.size();
|
|
|
|
for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
|
2012-04-27 12:54:28 +08:00
|
|
|
TraverseDecl(LocalTUDecls[i]);
|
2012-04-27 08:38:33 +08:00
|
|
|
}
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
if (Mgr->shouldInlineCall())
|
2012-10-11 01:55:37 +08:00
|
|
|
HandleDeclsCallGraph(LocalTUDeclsSize);
|
2009-09-10 13:44:00 +08:00
|
|
|
|
2012-01-08 00:49:46 +08:00
|
|
|
// After all decls handled, run checkers on the entire TranslationUnit.
|
|
|
|
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
|
2012-03-14 03:32:00 +08:00
|
|
|
|
|
|
|
RecVisitorBR = 0;
|
2012-01-08 00:49:46 +08:00
|
|
|
}
|
2011-05-05 11:41:17 +08:00
|
|
|
|
2011-09-26 08:51:36 +08:00
|
|
|
// Explicitly destroy the PathDiagnosticConsumer. This will flush its output.
|
2009-08-02 13:43:14 +08:00
|
|
|
// FIXME: This should be replaced with something that doesn't rely on
|
2011-09-26 08:51:36 +08:00
|
|
|
// side-effects in PathDiagnosticConsumer's destructor. This is required when
|
2009-12-15 17:32:42 +08:00
|
|
|
// used with option -disable-free.
|
2009-08-03 11:27:37 +08:00
|
|
|
Mgr.reset(NULL);
|
2012-03-06 04:53:59 +08:00
|
|
|
|
|
|
|
if (TUTotalTimer) TUTotalTimer->stopTimer();
|
2012-04-05 10:10:21 +08:00
|
|
|
|
|
|
|
// Count how many basic blocks we have not covered.
|
|
|
|
NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
|
|
|
|
if (NumBlocksInAnalyzedFunctions > 0)
|
|
|
|
PercentReachableBlocks =
|
|
|
|
(FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
|
|
|
|
NumBlocksInAnalyzedFunctions;
|
|
|
|
|
2008-07-03 12:29:21 +08:00
|
|
|
}
|
|
|
|
|
2012-03-09 07:16:38 +08:00
|
|
|
static std::string getFunctionName(const Decl *D) {
|
|
|
|
if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
|
|
|
|
return ID->getSelector().getAsString();
|
|
|
|
}
|
|
|
|
if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
IdentifierInfo *II = ND->getIdentifier();
|
|
|
|
if (II)
|
|
|
|
return II->getName();
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2012-10-11 01:55:40 +08:00
|
|
|
AnalysisConsumer::AnalysisMode
|
|
|
|
AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
|
2012-08-31 12:36:05 +08:00
|
|
|
if (!Opts->AnalyzeSpecificFunction.empty() &&
|
|
|
|
getFunctionName(D) != Opts->AnalyzeSpecificFunction)
|
2012-10-11 01:55:40 +08:00
|
|
|
return AM_None;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-10-11 01:55:40 +08:00
|
|
|
// Unless -analyze-all is specified, treat decls differently depending on
|
|
|
|
// where they came from:
|
|
|
|
// - Main source file: run both path-sensitive and non-path-sensitive checks.
|
|
|
|
// - Header files: run non-path-sensitive checks only.
|
|
|
|
// - System headers: don't run any checks.
|
2010-06-15 08:55:40 +08:00
|
|
|
SourceManager &SM = Ctx->getSourceManager();
|
2011-07-26 00:49:02 +08:00
|
|
|
SourceLocation SL = SM.getExpansionLoc(D->getLocation());
|
2012-10-11 01:55:40 +08:00
|
|
|
if (!Opts->AnalyzeAll && !SM.isFromMainFile(SL)) {
|
|
|
|
if (SL.isInvalid() || SM.isInSystemHeader(SL))
|
|
|
|
return AM_None;
|
|
|
|
return Mode & ~AM_Path;
|
|
|
|
}
|
2012-03-14 03:31:54 +08:00
|
|
|
|
2012-10-11 01:55:40 +08:00
|
|
|
return Mode;
|
2012-03-14 03:31:54 +08:00
|
|
|
}
|
|
|
|
|
2012-03-14 03:32:00 +08:00
|
|
|
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes IMode,
|
2012-04-13 06:36:48 +08:00
|
|
|
SetOfConstDecls *VisitedCallees) {
|
2012-12-21 09:19:15 +08:00
|
|
|
if (!D->hasBody())
|
|
|
|
return;
|
2012-10-11 01:55:40 +08:00
|
|
|
Mode = getModeForDecl(D, Mode);
|
|
|
|
if (Mode == AM_None)
|
2009-09-09 23:08:12 +08:00
|
|
|
return;
|
2008-07-02 08:03:09 +08:00
|
|
|
|
2012-03-14 03:32:00 +08:00
|
|
|
DisplayFunction(D, Mode);
|
2012-07-06 04:44:02 +08:00
|
|
|
CFG *DeclCFG = Mgr->getCFG(D);
|
|
|
|
if (DeclCFG) {
|
|
|
|
unsigned CFGSize = DeclCFG->size();
|
|
|
|
MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
|
|
|
|
}
|
|
|
|
|
2011-10-24 09:32:45 +08:00
|
|
|
// Clear the AnalysisManager of old AnalysisDeclContexts.
|
2009-10-21 05:39:41 +08:00
|
|
|
Mgr->ClearContexts();
|
2011-02-18 05:39:24 +08:00
|
|
|
BugReporter BR(*Mgr);
|
2012-12-21 09:19:15 +08:00
|
|
|
|
|
|
|
if (Mode & AM_Syntax)
|
|
|
|
checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
|
|
|
|
if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
|
|
|
|
RunPathSensitiveChecks(D, IMode, VisitedCallees);
|
|
|
|
if (IMode != ExprEngine::Inline_None)
|
|
|
|
NumFunctionsAnalyzed++;
|
|
|
|
}
|
2008-07-02 08:03:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2011-03-01 03:49:17 +08:00
|
|
|
// Path-sensitive checking.
|
2008-07-02 08:03:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-03-10 05:14:01 +08:00
|
|
|
void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes IMode,
|
2012-04-13 06:36:48 +08:00
|
|
|
SetOfConstDecls *VisitedCallees) {
|
2011-10-08 06:21:02 +08:00
|
|
|
// Construct the analysis engine. First check if the CFG is valid.
|
2009-09-19 06:29:35 +08:00
|
|
|
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
|
2012-03-10 05:14:01 +08:00
|
|
|
if (!Mgr->getCFG(D))
|
2010-02-15 03:08:51 +08:00
|
|
|
return;
|
2012-03-10 05:14:01 +08:00
|
|
|
|
2012-07-03 04:21:52 +08:00
|
|
|
// See if the LiveVariables analysis scales.
|
|
|
|
if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
|
|
|
|
return;
|
|
|
|
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
|
2010-02-15 03:08:51 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
// Set the graph auditor.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ExplodedNode::Auditor> Auditor;
|
2012-08-31 03:26:53 +08:00
|
|
|
if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
|
2008-08-28 06:31:43 +08:00
|
|
|
Auditor.reset(CreateUbiViz());
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode::SetAuditor(Auditor.get());
|
2008-08-28 06:31:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-02 08:44:58 +08:00
|
|
|
// Execute the worklist algorithm.
|
2012-04-28 09:58:08 +08:00
|
|
|
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
|
2012-08-31 03:26:43 +08:00
|
|
|
Mgr->options.MaxNodes);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
// Release the auditor (if any) so that it doesn't monitor the graph
|
|
|
|
// created BugReporter.
|
2009-08-06 09:32:16 +08:00
|
|
|
ExplodedNode::SetAuditor(0);
|
2009-03-11 09:42:29 +08:00
|
|
|
|
2008-07-03 00:49:11 +08:00
|
|
|
// Visualize the exploded graph.
|
2012-08-31 03:26:53 +08:00
|
|
|
if (Mgr->options.visualizeExplodedGraphWithGraphViz)
|
2012-08-31 03:26:43 +08:00
|
|
|
Eng.ViewGraph(Mgr->options.TrimGraph);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 09:42:29 +08:00
|
|
|
// Display warnings.
|
|
|
|
Eng.getBugReporter().FlushReports();
|
2008-07-03 00:35:50 +08:00
|
|
|
}
|
|
|
|
|
2012-04-13 06:36:48 +08:00
|
|
|
void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
|
2012-12-08 05:51:47 +08:00
|
|
|
ExprEngine::InliningModes IMode,
|
2012-04-13 06:36:48 +08:00
|
|
|
SetOfConstDecls *Visited) {
|
2011-09-02 13:55:19 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
switch (Mgr->getLangOpts().getGC()) {
|
2011-09-02 13:55:19 +08:00
|
|
|
case LangOptions::NonGC:
|
2012-12-08 05:51:47 +08:00
|
|
|
ActionExprEngine(D, false, IMode, Visited);
|
2011-09-02 13:55:19 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LangOptions::GCOnly:
|
2012-12-08 05:51:47 +08:00
|
|
|
ActionExprEngine(D, true, IMode, Visited);
|
2011-09-02 13:55:19 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LangOptions::HybridGC:
|
2012-12-08 05:51:47 +08:00
|
|
|
ActionExprEngine(D, false, IMode, Visited);
|
|
|
|
ActionExprEngine(D, true, IMode, Visited);
|
2011-09-02 13:55:19 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-07-02 08:44:58 +08:00
|
|
|
}
|
|
|
|
|
2008-07-02 08:03:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// AnalysisConsumer creation.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-12-23 15:20:52 +08:00
|
|
|
ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
|
2011-08-17 05:24:21 +08:00
|
|
|
const std::string& outDir,
|
2012-08-31 12:36:05 +08:00
|
|
|
AnalyzerOptionsRef opts,
|
2011-08-17 05:24:21 +08:00
|
|
|
ArrayRef<std::string> plugins) {
|
|
|
|
// Disable the effects of '-Werror' when using the AnalysisConsumer.
|
2009-11-05 10:41:58 +08:00
|
|
|
pp.getDiagnostics().setWarningsAsErrors(false);
|
2009-02-17 12:27:41 +08:00
|
|
|
|
2011-08-17 05:24:21 +08:00
|
|
|
return new AnalysisConsumer(pp, outDir, opts, plugins);
|
2008-07-02 08:03:09 +08:00
|
|
|
}
|
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Ubigraph Visualization. FIXME: Move to separate file.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
class UbigraphViz : public ExplodedNode::Auditor {
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<raw_ostream> Out;
|
2008-08-28 11:54:51 +08:00
|
|
|
llvm::sys::Path Dir, Filename;
|
2008-08-28 06:31:43 +08:00
|
|
|
unsigned Cntr;
|
|
|
|
|
|
|
|
typedef llvm::DenseMap<void*,unsigned> VMap;
|
|
|
|
VMap M;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
public:
|
2011-08-13 07:37:29 +08:00
|
|
|
UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
|
2008-08-28 13:02:09 +08:00
|
|
|
llvm::sys::Path& filename);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
~UbigraphViz();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
|
2008-08-28 06:31:43 +08:00
|
|
|
};
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2009-08-06 09:32:16 +08:00
|
|
|
static ExplodedNode::Auditor* CreateUbiViz() {
|
2008-08-28 06:31:43 +08:00
|
|
|
std::string ErrMsg;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
|
2008-08-28 06:31:43 +08:00
|
|
|
if (!ErrMsg.empty())
|
|
|
|
return 0;
|
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
llvm::sys::Path Filename = Dir;
|
2008-08-28 06:31:43 +08:00
|
|
|
Filename.appendComponent("llvm_ubi");
|
|
|
|
Filename.makeUnique(true,&ErrMsg);
|
|
|
|
|
|
|
|
if (!ErrMsg.empty())
|
|
|
|
return 0;
|
|
|
|
|
2009-08-24 06:45:33 +08:00
|
|
|
llvm::errs() << "Writing '" << Filename.str() << "'.\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<llvm::raw_fd_ostream> Stream;
|
2009-08-25 23:36:09 +08:00
|
|
|
Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
|
2008-08-28 06:31:43 +08:00
|
|
|
|
|
|
|
if (!ErrMsg.empty())
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
return new UbigraphViz(Stream.take(), Dir, Filename);
|
2008-08-28 06:31:43 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-29 02:34:41 +08:00
|
|
|
assert (Src != Dst && "Self-edges are not allowed.");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
// Lookup the Src. If it is a new node, it's a root.
|
|
|
|
VMap::iterator SrcI= M.find(Src);
|
|
|
|
unsigned SrcID;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
if (SrcI == M.end()) {
|
|
|
|
M[Src] = SrcID = Cntr++;
|
|
|
|
*Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SrcID = SrcI->second;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 06:31:43 +08:00
|
|
|
// Lookup the Dst.
|
|
|
|
VMap::iterator DstI= M.find(Dst);
|
|
|
|
unsigned DstID;
|
|
|
|
|
|
|
|
if (DstI == M.end()) {
|
|
|
|
M[Dst] = DstID = Cntr++;
|
|
|
|
*Out << "('vertex', " << DstID << ")\n";
|
|
|
|
}
|
2008-08-28 13:02:09 +08:00
|
|
|
else {
|
|
|
|
// We have hit DstID before. Change its style to reflect a cache hit.
|
2008-08-28 06:31:43 +08:00
|
|
|
DstID = DstI->second;
|
2008-08-28 13:02:09 +08:00
|
|
|
*Out << "('change_vertex_style', " << DstID << ", 1)\n";
|
|
|
|
}
|
2008-08-28 06:31:43 +08:00
|
|
|
|
|
|
|
// Add the edge.
|
2009-09-09 23:08:12 +08:00
|
|
|
*Out << "('edge', " << SrcID << ", " << DstID
|
2008-08-28 06:46:55 +08:00
|
|
|
<< ", ('arrow','true'), ('oriented', 'true'))\n";
|
2008-08-28 06:31:43 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
UbigraphViz::UbigraphViz(raw_ostream *out, llvm::sys::Path& dir,
|
2008-08-28 13:02:09 +08:00
|
|
|
llvm::sys::Path& filename)
|
|
|
|
: Out(out), Dir(dir), Filename(filename), Cntr(0) {
|
|
|
|
|
|
|
|
*Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
|
|
|
|
*Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
|
|
|
|
" ('size', '1.5'))\n";
|
|
|
|
}
|
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
UbigraphViz::~UbigraphViz() {
|
|
|
|
Out.reset(0);
|
2009-08-23 20:08:50 +08:00
|
|
|
llvm::errs() << "Running 'ubiviz' program... ";
|
2008-08-28 11:54:51 +08:00
|
|
|
std::string ErrMsg;
|
|
|
|
llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
|
|
|
|
std::vector<const char*> args;
|
|
|
|
args.push_back(Ubiviz.c_str());
|
|
|
|
args.push_back(Filename.c_str());
|
|
|
|
args.push_back(0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
|
2009-08-23 20:08:50 +08:00
|
|
|
llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
|
2008-08-28 11:54:51 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 11:54:51 +08:00
|
|
|
// Delete the directory.
|
2009-09-09 23:08:12 +08:00
|
|
|
Dir.eraseFromDisk(true);
|
2008-08-29 11:45:59 +08:00
|
|
|
}
|