diff options
author | Zhongxing Xu <xuzhongxing@gmail.com> | 2010-04-30 04:14:20 +0000 |
---|---|---|
committer | Zhongxing Xu <xuzhongxing@gmail.com> | 2010-04-30 04:14:20 +0000 |
commit | ed8afacb8118b71bcfa8017059e51da325e7691b (patch) | |
tree | 26bda88b50b82e4652328bdc39920769052afd4b | |
parent | 51e2a5d45d321c53355fe038b3a3e7a2f502afa4 (diff) |
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
-rw-r--r-- | include/clang/Frontend/Analyses.def | 25 | ||||
-rw-r--r-- | lib/Frontend/AnalysisConsumer.cpp | 188 | ||||
-rw-r--r-- | test/Analysis/inline.c | 4 | ||||
-rw-r--r-- | test/Analysis/inline2.c | 3 | ||||
-rw-r--r-- | test/Analysis/inline3.c | 4 | ||||
-rw-r--r-- | test/Analysis/inline4.c | 4 | ||||
-rw-r--r-- | test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m | 2 |
7 files changed, 82 insertions, 148 deletions
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index 287c67ebb7..aaa3920cee 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -15,22 +15,21 @@ #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) #endif -ANALYSIS(CFGDump, "cfg-dump", +ANALYSIS(CFGDump, "cfg-dump", "Display Control-Flow Graphs", Code) -ANALYSIS(CFGView, "cfg-view", +ANALYSIS(CFGView, "cfg-view", "View Control-Flow Graphs using GraphViz", Code) ANALYSIS(DisplayLiveVariables, "dump-live-variables", "Print results of live variable analysis", Code) ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic", - "Perform quick security checks that require no data flow", - Code) + "Perform quick security checks that require no data flow", Code) ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions", - "Check code for LLVM codebase conventions (domain-specific)", - TranslationUnit) + "Check code for LLVM codebase conventions (domain-specific)", + TranslationUnit) ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores", "Warn about stores to dead variables", Code) @@ -39,15 +38,15 @@ ANALYSIS(WarnUninitVals, "warn-uninit-values", "Warn about uses of uninitialized variables", Code) ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs", - "Warn about Objective-C method signatures with type incompatibilities", - ObjCImplementation) + "Warn about Objective-C method signatures with type incompatibilities", + ObjCImplementation) ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc", - "Warn about Objective-C classes that lack a correct implementation of -dealloc", - ObjCImplementation) +"Warn about Objective-C classes that lack a correct implementation of -dealloc", + ObjCImplementation) 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", "Run the [Core] Foundation reference count checker", Code) @@ -55,10 +54,6 @@ ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem", ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer", "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 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index d55fbc1a21..6e23e16b51 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -62,20 +62,21 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix, namespace { - class AnalysisConsumer : public ASTConsumer { - public: +class AnalysisConsumer : public ASTConsumer { +public: typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, TranslationUnitDecl &TU); - private: +private: typedef std::vector<CodeAction> Actions; typedef std::vector<TUAction> TUActions; Actions FunctionActions; Actions ObjCMethodActions; Actions ObjCImplementationActions; - TUActions TranslationUnitActions; + Actions CXXMethodActions; + TUActions TranslationUnitActions; // Remove this. public: ASTContext* Ctx; @@ -161,16 +162,17 @@ public: void addCodeAction(CodeAction action) { FunctionActions.push_back(action); ObjCMethodActions.push_back(action); - } - - void addObjCImplementationAction(CodeAction action) { - ObjCImplementationActions.push_back(action); + CXXMethodActions.push_back(action); } void addTranslationUnitAction(TUAction action) { TranslationUnitActions.push_back(action); } + void addObjCImplementationAction(CodeAction action) { + ObjCImplementationActions.push_back(action); + } + virtual void Initialize(ASTContext &Context) { Ctx = &Context; Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), @@ -182,16 +184,8 @@ public: 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); - - void HandleCode(Decl* D, Stmt* Body, Actions& actions); + void HandleCode(Decl *D, Stmt* Body, Actions& actions); }; } // end anonymous namespace @@ -208,57 +202,69 @@ namespace llvm { // 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); +void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { - if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) - return; + TranslationUnitDecl *TU = C.getTranslationUnitDecl(); - if (Stmt* Body = MD->getBody()) - HandleCode(MD, Body, ObjCMethodActions); - break; - } + 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; + } - default: - 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; + } -void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { + 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; + } - TranslationUnitDecl *TU = C.getTranslationUnitDecl(); + default: + break; + } + } for (TUActions::iterator I = TranslationUnitActions.begin(), E = TranslationUnitActions.end(); I != E; ++I) { (*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. // FIXME: This should be replaced with something that doesn't rely on // 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, Decl *D) { if (LiveVariables *L = mgr.getLiveVariables(D)) { - C.DisplayFunction(D); BugReporter BR(mgr); 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, Decl *D) { if (CFG* c = mgr.getCFG(D)) { - C.DisplayFunction(D); CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); } } @@ -332,15 +336,11 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, llvm::OwningPtr<GRTransferFuncs> TF(tf); - // Display progress. - C.DisplayFunction(D); - // Construct the analysis engine. We first query for the LiveVariables // information to see if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. if (!mgr.getLiveVariables(D)) return; - GRExprEngine Eng(mgr, TF.take()); if (C.Opts.EnableExperimentalInternalChecks) @@ -407,28 +407,24 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionDisplayLiveVariables(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (LiveVariables* L = mgr.getLiveVariables(D)) { - C.DisplayFunction(D); L->dumpBlockLiveness(mgr.getSourceManager()); } } static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (CFG *cfg = mgr.getCFG(D)) { - C.DisplayFunction(D); cfg->dump(mgr.getLangOptions()); } } static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (CFG *cfg = mgr.getCFG(D)) { - C.DisplayFunction(D); cfg->viewCFG(mgr.getLangOptions()); } } static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckSecuritySyntaxOnly(D, BR); } @@ -444,86 +440,28 @@ static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) return; - - C.DisplayFunction(D); BugReporter BR(mgr); CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); } static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); } static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); } static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); 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. //===----------------------------------------------------------------------===// diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c index 952de737f7..acaf74ded9 100644 --- a/test/Analysis/inline.c +++ b/test/Analysis/inline.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s - +// RUN: false +// XFAIL: * int f1() { int y = 1; y++; diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c index e2758c160a..ec965a69c6 100644 --- a/test/Analysis/inline2.c +++ b/test/Analysis/inline2.c @@ -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 // is not referenced in the function body. diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c index 3661263b6b..8f45858bb9 100644 --- a/test/Analysis/inline3.c +++ b/test/Analysis/inline3.c @@ -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. // Otherwise, block-level expr '1 && a' would not be block-level. diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c index dd2379f043..b2b3c346e3 100644 --- a/test/Analysis/inline4.c +++ b/test/Analysis/inline4.c @@ -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) { return a; } diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m index 2e9c528612..5f5187194d 100644 --- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -72,11 +72,11 @@ int handleVoidInComma() { 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 '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 '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-darwin9: control reaches end of non-void function // CHECK-darwin9: 1 warning generated |