Refactor the AnalysisConsumer to analyze functions after the whole

translation unit is parsed. This enables us to inline some calls when still
analyzing one function at a time.

Actions are classified into Function, CXXMethod, ObjCMethod, 
ObjCImplementation.

This does not hurt performance much. The analysis time for sqlite3.c:

before:
real    17m52.440s
user    17m49.460s
sys    0m2.010s

after:
real    18m0.500s
user    17m56.900s
sys    0m2.330s

DisplayProgress option is broken now. -inine-call action is removed. It
will be reenabled in another form, perhaps as an indenpendant option.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102689 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Zhongxing Xu 2010-04-30 04:14:20 +00:00
Родитель 51e2a5d45d
Коммит ed8afacb81
7 изменённых файлов: 84 добавлений и 150 удалений

Просмотреть файл

@ -15,22 +15,21 @@
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
#endif #endif
ANALYSIS(CFGDump, "cfg-dump", ANALYSIS(CFGDump, "cfg-dump",
"Display Control-Flow Graphs", Code) "Display Control-Flow Graphs", Code)
ANALYSIS(CFGView, "cfg-view", ANALYSIS(CFGView, "cfg-view",
"View Control-Flow Graphs using GraphViz", Code) "View Control-Flow Graphs using GraphViz", Code)
ANALYSIS(DisplayLiveVariables, "dump-live-variables", ANALYSIS(DisplayLiveVariables, "dump-live-variables",
"Print results of live variable analysis", Code) "Print results of live variable analysis", Code)
ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic", ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic",
"Perform quick security checks that require no data flow", "Perform quick security checks that require no data flow", Code)
Code)
ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions", ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions",
"Check code for LLVM codebase conventions (domain-specific)", "Check code for LLVM codebase conventions (domain-specific)",
TranslationUnit) TranslationUnit)
ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores", ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores",
"Warn about stores to dead variables", Code) "Warn about stores to dead variables", Code)
@ -39,15 +38,15 @@ ANALYSIS(WarnUninitVals, "warn-uninit-values",
"Warn about uses of uninitialized variables", Code) "Warn about uses of uninitialized variables", Code)
ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs", ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs",
"Warn about Objective-C method signatures with type incompatibilities", "Warn about Objective-C method signatures with type incompatibilities",
ObjCImplementation) ObjCImplementation)
ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc", ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc",
"Warn about Objective-C classes that lack a correct implementation of -dealloc", "Warn about Objective-C classes that lack a correct implementation of -dealloc",
ObjCImplementation) ObjCImplementation)
ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars", ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars",
"Warn about private ivars that are never used", ObjCImplementation) "Warn about private ivars that are never used", ObjCImplementation)
ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem", ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem",
"Run the [Core] Foundation reference count checker", Code) "Run the [Core] Foundation reference count checker", Code)
@ -55,10 +54,6 @@ ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem",
ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer", ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer",
"Warn about unintended use of sizeof() on pointer expressions", Code) "Warn about unintended use of sizeof() on pointer expressions", Code)
ANALYSIS(InlineCall, "inline-call",
"Experimental transfer function inling callees when its definition"
" is available.", TranslationUnit)
#ifndef ANALYSIS_STORE #ifndef ANALYSIS_STORE
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
#endif #endif

Просмотреть файл

@ -62,20 +62,21 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace { namespace {
class AnalysisConsumer : public ASTConsumer { class AnalysisConsumer : public ASTConsumer {
public: public:
typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
TranslationUnitDecl &TU); TranslationUnitDecl &TU);
private: private:
typedef std::vector<CodeAction> Actions; typedef std::vector<CodeAction> Actions;
typedef std::vector<TUAction> TUActions; typedef std::vector<TUAction> TUActions;
Actions FunctionActions; Actions FunctionActions;
Actions ObjCMethodActions; Actions ObjCMethodActions;
Actions ObjCImplementationActions; Actions ObjCImplementationActions;
TUActions TranslationUnitActions; Actions CXXMethodActions;
TUActions TranslationUnitActions; // Remove this.
public: public:
ASTContext* Ctx; ASTContext* Ctx;
@ -161,16 +162,17 @@ public:
void addCodeAction(CodeAction action) { void addCodeAction(CodeAction action) {
FunctionActions.push_back(action); FunctionActions.push_back(action);
ObjCMethodActions.push_back(action); ObjCMethodActions.push_back(action);
} CXXMethodActions.push_back(action);
void addObjCImplementationAction(CodeAction action) {
ObjCImplementationActions.push_back(action);
} }
void addTranslationUnitAction(TUAction action) { void addTranslationUnitAction(TUAction action) {
TranslationUnitActions.push_back(action); TranslationUnitActions.push_back(action);
} }
void addObjCImplementationAction(CodeAction action) {
ObjCImplementationActions.push_back(action);
}
virtual void Initialize(ASTContext &Context) { virtual void Initialize(ASTContext &Context) {
Ctx = &Context; Ctx = &Context;
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
@ -182,16 +184,8 @@ public:
Opts.TrimGraph)); Opts.TrimGraph));
} }
virtual void HandleTopLevelDecl(DeclGroupRef D) {
declDisplayed = false;
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
HandleTopLevelSingleDecl(*I);
}
void HandleTopLevelSingleDecl(Decl *D);
virtual void HandleTranslationUnit(ASTContext &C); virtual void HandleTranslationUnit(ASTContext &C);
void HandleCode(Decl *D, Stmt* Body, Actions& actions);
void HandleCode(Decl* D, Stmt* Body, Actions& actions);
}; };
} // end anonymous namespace } // end anonymous namespace
@ -208,57 +202,69 @@ namespace llvm {
// AnalysisConsumer implementation. // AnalysisConsumer implementation.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
switch (D->getKind()) {
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion:
case Decl::CXXMethod:
case Decl::Function: {
FunctionDecl* FD = cast<FunctionDecl>(D);
if (!Opts.AnalyzeSpecificFunction.empty() &&
FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
break;
if (Stmt *Body = FD->getBody())
HandleCode(FD, Body, FunctionActions);
break;
}
case Decl::ObjCMethod: {
ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
if (!Opts.AnalyzeSpecificFunction.empty() &&
Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
return;
if (Stmt* Body = MD->getBody())
HandleCode(MD, Body, ObjCMethodActions);
break;
}
default:
break;
}
}
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
TranslationUnitDecl *TU = C.getTranslationUnitDecl(); TranslationUnitDecl *TU = C.getTranslationUnitDecl();
for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
I != E; ++I) {
Decl *D = *I;
switch (D->getKind()) {
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion:
case Decl::CXXMethod:
case Decl::Function: {
FunctionDecl* FD = cast<FunctionDecl>(D);
if (FD->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
break;
HandleCode(FD, FD->getBody(), FunctionActions);
}
break;
}
case Decl::ObjCMethod: {
ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
if (MD->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
break;
HandleCode(MD, MD->getBody(), ObjCMethodActions);
}
break;
}
case Decl::ObjCImplementation: {
ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
HandleCode(ID, 0, ObjCImplementationActions);
for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
ME = ID->meth_end(); MI != ME; ++MI) {
if ((*MI)->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
break;
HandleCode(*MI, (*MI)->getBody(), ObjCMethodActions);
}
}
break;
}
default:
break;
}
}
for (TUActions::iterator I = TranslationUnitActions.begin(), for (TUActions::iterator I = TranslationUnitActions.begin(),
E = TranslationUnitActions.end(); I != E; ++I) { E = TranslationUnitActions.end(); I != E; ++I) {
(*I)(*this, *Mgr, *TU); (*I)(*this, *Mgr, *TU);
} }
if (!ObjCImplementationActions.empty()) {
for (DeclContext::decl_iterator I = TU->decls_begin(),
E = TU->decls_end();
I != E; ++I)
if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
HandleCode(ID, 0, ObjCImplementationActions);
}
// Explicitly destroy the PathDiagnosticClient. This will flush its output. // Explicitly destroy the PathDiagnosticClient. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on // FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticClient's destructor. This is required when // side-effects in PathDiagnosticClient's destructor. This is required when
@ -311,7 +317,6 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) { Decl *D) {
if (LiveVariables *L = mgr.getLiveVariables(D)) { if (LiveVariables *L = mgr.getLiveVariables(D)) {
C.DisplayFunction(D);
BugReporter BR(mgr); BugReporter BR(mgr);
CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR); CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
} }
@ -320,7 +325,6 @@ static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) { Decl *D) {
if (CFG* c = mgr.getCFG(D)) { if (CFG* c = mgr.getCFG(D)) {
C.DisplayFunction(D);
CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
} }
} }
@ -332,15 +336,11 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
llvm::OwningPtr<GRTransferFuncs> TF(tf); llvm::OwningPtr<GRTransferFuncs> TF(tf);
// Display progress.
C.DisplayFunction(D);
// Construct the analysis engine. We first query for the LiveVariables // Construct the analysis engine. We first query for the LiveVariables
// information to see if the CFG is valid. // information to see if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs. // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
if (!mgr.getLiveVariables(D)) if (!mgr.getLiveVariables(D))
return; return;
GRExprEngine Eng(mgr, TF.take()); GRExprEngine Eng(mgr, TF.take());
if (C.Opts.EnableExperimentalInternalChecks) if (C.Opts.EnableExperimentalInternalChecks)
@ -407,28 +407,24 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionDisplayLiveVariables(AnalysisConsumer &C, static void ActionDisplayLiveVariables(AnalysisConsumer &C,
AnalysisManager& mgr, Decl *D) { AnalysisManager& mgr, Decl *D) {
if (LiveVariables* L = mgr.getLiveVariables(D)) { if (LiveVariables* L = mgr.getLiveVariables(D)) {
C.DisplayFunction(D);
L->dumpBlockLiveness(mgr.getSourceManager()); L->dumpBlockLiveness(mgr.getSourceManager());
} }
} }
static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
if (CFG *cfg = mgr.getCFG(D)) { if (CFG *cfg = mgr.getCFG(D)) {
C.DisplayFunction(D);
cfg->dump(mgr.getLangOptions()); cfg->dump(mgr.getLangOptions());
} }
} }
static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
if (CFG *cfg = mgr.getCFG(D)) { if (CFG *cfg = mgr.getCFG(D)) {
C.DisplayFunction(D);
cfg->viewCFG(mgr.getLangOptions()); cfg->viewCFG(mgr.getLangOptions());
} }
} }
static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
AnalysisManager &mgr, Decl *D) { AnalysisManager &mgr, Decl *D) {
C.DisplayFunction(D);
BugReporter BR(mgr); BugReporter BR(mgr);
CheckSecuritySyntaxOnly(D, BR); CheckSecuritySyntaxOnly(D, BR);
} }
@ -444,86 +440,28 @@ static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) { Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
return; return;
C.DisplayFunction(D);
BugReporter BR(mgr); BugReporter BR(mgr);
CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
} }
static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) { Decl *D) {
C.DisplayFunction(D);
BugReporter BR(mgr); BugReporter BR(mgr);
CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
} }
static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) { Decl *D) {
C.DisplayFunction(D);
BugReporter BR(mgr); BugReporter BR(mgr);
CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
} }
static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
Decl *D) { Decl *D) {
C.DisplayFunction(D);
BugReporter BR(mgr); BugReporter BR(mgr);
CheckSizeofPointer(D, BR); CheckSizeofPointer(D, BR);
} }
static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
TranslationUnitDecl &TU) {
// Find the entry function definition (if any).
FunctionDecl *D = 0;
// Must specify an entry function.
if (!C.Opts.AnalyzeSpecificFunction.empty()) {
for (DeclContext::decl_iterator I=TU.decls_begin(), E=TU.decls_end();
I != E; ++I) {
if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
if (fd->isThisDeclarationADefinition() &&
fd->getNameAsString() == C.Opts.AnalyzeSpecificFunction) {
D = fd;
break;
}
}
}
if (!D)
return;
// FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
// Display progress.
C.DisplayFunction(D);
// FIXME: Make a fake transfer function. The GRTransferFunc interface
// eventually will be removed.
GRExprEngine Eng(mgr, new GRTransferFuncs());
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
RegisterAppleChecks(Eng, *D);
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
// Register call inliner as the last checker.
RegisterCallInliner(Eng);
// Execute the worklist algorithm.
Eng.ExecuteWorkList(mgr.getStackFrame(D));
// Visualize the exploded graph.
if (mgr.shouldVisualizeGraphviz())
Eng.ViewGraph(mgr.shouldTrimGraph());
// Display warnings.
Eng.getBugReporter().FlushReports();
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// AnalysisConsumer creation. // AnalysisConsumer creation.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

Просмотреть файл

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s // RUN: false
// XFAIL: *
int f1() { int f1() {
int y = 1; int y = 1;
y++; y++;

Просмотреть файл

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s // RUN: false
// XFAIL: *
// Test parameter 'a' is registered to LiveVariables analysis data although it // Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body. // is not referenced in the function body.

Просмотреть файл

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s // RUN: false
// XFAIL: *
// Test when entering f1(), we set the right AnalysisContext to Environment. // Test when entering f1(), we set the right AnalysisContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level. // Otherwise, block-level expr '1 && a' would not be block-level.

Просмотреть файл

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f -verify %s // RUN: false
// XFAIL: *
int g(int a) { int g(int a) {
return a; return a;
} }

Просмотреть файл

@ -72,11 +72,11 @@ int handleVoidInComma() {
int marker(void) { // control reaches end of non-void function int marker(void) { // control reaches end of non-void function
} }
// CHECK-darwin8: control reaches end of non-void function
// CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage // CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage // CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage // CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage // CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
// CHECK-darwin8: control reaches end of non-void function
// CHECK-darwin8: 5 warnings generated // CHECK-darwin8: 5 warnings generated
// CHECK-darwin9: control reaches end of non-void function // CHECK-darwin9: control reaches end of non-void function
// CHECK-darwin9: 1 warning generated // CHECK-darwin9: 1 warning generated