[cfe-commits] r152650 - in /cfe/trunk: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp test/Analysis/auto-obj-dtors-cfg-output.cpp
Anna Zaks
ganna at apple.com
Tue Mar 13 12:32:00 PDT 2012
Author: zaks
Date: Tue Mar 13 14:32:00 2012
New Revision: 152650
URL: http://llvm.org/viewvc/llvm-project?rev=152650&view=rev
Log:
[analyzer] Use recursive AST visitor to drive simple visitation order in
AnalysisConsumer.
As a result:
- We now analyze the C++ methods which are defined within the
class body. These were completely skipped before.
- Ensure that AST checkers are called on functions in the
order they are defined in the Translation unit.
Modified:
cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=152650&r1=152649&r2=152650&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Tue Mar 13 14:32:00 2012
@@ -19,6 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CallGraph.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
@@ -69,7 +70,19 @@
namespace {
-class AnalysisConsumer : public ASTConsumer {
+class AnalysisConsumer : public ASTConsumer,
+ public RecursiveASTVisitor<AnalysisConsumer> {
+ enum AnalysisMode {
+ ANALYSIS_SYNTAX,
+ ANALYSIS_PATH,
+ ANALYSIS_ALL
+ };
+
+ /// Mode of the analyzes while recursively visiting Decls.
+ AnalysisMode RecVisitorMode;
+ /// Bug Reporter to use while recursively visiting Decls.
+ BugReporter *RecVisitorBR;
+
public:
ASTContext *Ctx;
const Preprocessor &PP;
@@ -93,7 +106,8 @@
const std::string& outdir,
const AnalyzerOptions& opts,
ArrayRef<std::string> plugins)
- : Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
+ : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
+ Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
DigestAnalyzerOptions();
if (Opts.PrintStats) {
llvm::EnableStatistics();
@@ -139,15 +153,20 @@
}
}
- void DisplayFunction(const Decl *D) {
+ void DisplayFunction(const Decl *D, AnalysisMode Mode) {
if (!Opts.AnalyzerDisplayProgress)
return;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
if (Loc.isValid()) {
- llvm::errs() << "ANALYZE: " << Loc.getFilename();
-
+ llvm::errs() << "ANALYZE";
+ switch (Mode) {
+ case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
+ case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
+ case ANALYSIS_ALL: break;
+ };
+ llvm::errs() << ": " << Loc.getFilename();
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
llvm::errs() << ' ' << *ND << '\n';
@@ -186,41 +205,64 @@
}
virtual void HandleTranslationUnit(ASTContext &C);
- void HandleDeclContext(ASTContext &C, DeclContext *dc);
- void HandleDeclContextDecl(ASTContext &C, Decl *D);
- void HandleDeclContextDeclFunction(ASTContext &C, Decl *D);
- void HandleCode(Decl *D, SetOfDecls *VisitedCallees = 0);
+ /// \brief Build the call graph for the context and use it to define the order
+ /// in which the functions should be visited.
+ void HandleDeclContextGallGraph(ASTContext &C, DeclContext *dc);
+
+ /// \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.
+ void HandleCode(Decl *D, AnalysisMode Mode, SetOfDecls *VisitedCallees = 0);
+
+ /// \brief Check if we should skip (not analyze) the given function.
bool skipFunction(Decl *D);
+
void RunPathSensitiveChecks(Decl *D, SetOfDecls *VisitedCallees);
void ActionExprEngine(Decl *D, bool ObjCGCEnabled, SetOfDecls *VisitedCallees);
+
+ /// Visitors for the RecursiveASTVisitor.
+
+ /// Handle callbacks for arbitrary Decls.
+ bool VisitDecl(Decl *D) {
+ checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
+ 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()) {
+ HandleCode(FD, RecVisitorMode);
+ }
+ return true;
+ }
+
+ bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
+ if (MD->isThisDeclarationADefinition())
+ HandleCode(MD, RecVisitorMode);
+ return true;
+ }
};
} // end anonymous namespace
+
//===----------------------------------------------------------------------===//
// AnalysisConsumer implementation.
//===----------------------------------------------------------------------===//
llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
-void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
- // Don't run the actions if an error has occurred with parsing the file.
- DiagnosticsEngine &Diags = PP.getDiagnostics();
- if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
- return;
-
- for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
- I != E; ++I) {
- HandleDeclContextDecl(C, *I);
- }
-
- // If inlining is not turned on, use the simplest function order.
- if (!Mgr->shouldInlineCall()) {
- for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
- I != E; ++I)
- HandleDeclContextDeclFunction(C, *I);
- return;
- }
-
+void AnalysisConsumer::HandleDeclContextGallGraph(ASTContext &C,
+ DeclContext *dc) {
// Otherwise, use the Callgraph to derive the order.
// Build the Call Graph.
CallGraph CG;
@@ -256,7 +298,8 @@
SetOfDecls VisitedCallees;
Decl *D = (*DFI)->getDecl();
assert(D);
- HandleCode(D, (Mgr->InliningMode == All ? 0 : &VisitedCallees));
+ HandleCode(D, ANALYSIS_PATH,
+ (Mgr->InliningMode == All ? 0 : &VisitedCallees));
// Add the visited callees to the global visited set.
for (SetOfDecls::const_iterator I = VisitedCallees.begin(),
@@ -269,78 +312,12 @@
}
}
-void AnalysisConsumer::HandleDeclContextDecl(ASTContext &C, Decl *D) {
- { // Handle callbacks for arbitrary decls.
- BugReporter BR(*Mgr);
- checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR);
- }
-
- switch (D->getKind()) {
- case Decl::Namespace: {
- HandleDeclContext(C, cast<NamespaceDecl>(D));
- break;
- }
- case Decl::ObjCCategoryImpl:
- case Decl::ObjCImplementation: {
- ObjCImplDecl *ID = cast<ObjCImplDecl>(D);
- for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
- ME = ID->meth_end(); MI != ME; ++MI) {
- BugReporter BR(*Mgr);
- checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
- }
- break;
- }
-
- default:
- break;
- }
-}
-
-void AnalysisConsumer::HandleDeclContextDeclFunction(ASTContext &C, 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);
- IdentifierInfo *II = FD->getIdentifier();
- if (II && II->getName().startswith("__inline"))
- break;
- // We skip function template definitions, as their semantics is
- // only determined when they are instantiated.
- if (FD->isThisDeclarationADefinition() &&
- !FD->isDependentContext()) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
- break;
- HandleCode(FD);
- }
- break;
- }
-
- case Decl::ObjCCategoryImpl:
- case Decl::ObjCImplementation: {
- ObjCImplDecl *ID = cast<ObjCImplDecl>(D);
- for (ObjCContainerDecl::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())
- continue;
- HandleCode(*MI);
- }
- }
- break;
- }
-
- default:
- break;
- }
-}
-
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+ // Don't run the actions if an error has occurred with parsing the file.
+ DiagnosticsEngine &Diags = PP.getDiagnostics();
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
+ return;
+
{
if (TUTotalTimer) TUTotalTimer->startTimer();
@@ -348,10 +325,21 @@
BugReporter BR(*Mgr);
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
- HandleDeclContext(C, TU);
+
+ // 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.
+ RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
+ RecVisitorBR = &BR;
+ TraverseDecl(TU);
+
+ if (Mgr->shouldInlineCall())
+ HandleDeclContextGallGraph(C, TU);
// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
+
+ RecVisitorBR = 0;
}
// Explicitly destroy the PathDiagnosticConsumer. This will flush its output.
@@ -400,12 +388,12 @@
return false;
}
-void AnalysisConsumer::HandleCode(Decl *D, SetOfDecls *VisitedCallees) {
-
+void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
+ SetOfDecls *VisitedCallees) {
if (skipFunction(D))
return;
- DisplayFunction(D);
+ DisplayFunction(D, Mode);
// Clear the AnalysisManager of old AnalysisDeclContexts.
Mgr->ClearContexts();
@@ -421,8 +409,9 @@
for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
if ((*WI)->hasBody()) {
- checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if (checkerMgr->hasPathSensitiveCheckers())
+ if (Mode != ANALYSIS_PATH)
+ checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
+ if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers())
RunPathSensitiveChecks(*WI, VisitedCallees);
}
NumFunctionsAnalyzed++;
Modified: cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp?rev=152650&r1=152649&r2=152650&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp (original)
+++ cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp Tue Mar 13 14:32:00 2012
@@ -156,6 +156,23 @@
}
}
+// CHECK: [B1 (ENTRY)]
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B1 (ENTRY)]
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: 1
+// CHECK: 2: return [B1.1];
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
@@ -324,15 +341,6 @@
// CHECK: Succs (2): B3 B2
// CHECK: [B0 (EXIT)]
// CHECK: Preds (1): B1
-// CHECK: [B2 (ENTRY)]
-// CHECK: Succs (1): B1
-// CHECK: [B1]
-// CHECK: 1: 1
-// CHECK: 2: return [B1.1];
-// CHECK: Preds (1): B2
-// CHECK: Succs (1): B0
-// CHECK: [B0 (EXIT)]
-// CHECK: Preds (1): B1
// CHECK: [B9 (ENTRY)]
// CHECK: Succs (1): B8
// CHECK: [B1]
More information about the cfe-commits
mailing list