From: Ted Kremenek Date: Fri, 14 Mar 2008 17:31:00 +0000 (+0000) Subject: Path-sensitive analyses no longer take a FunctionDecl, but any Decl representing X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=63bbe5312cd89ce0ceb684bff68c5baef636e93c;p=clang Path-sensitive analyses no longer take a FunctionDecl, but any Decl representing a block of "code". Patched various ASTConsumers (such as ASTDumper) to have more support for processing ObjCMethodDecl. CFGVisitor now builds CFGs for ObjCMethodDecls. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48363 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/CFRefCount.cpp b/Analysis/CFRefCount.cpp index c87ca673b9..5088ff7ecb 100644 --- a/Analysis/CFRefCount.cpp +++ b/Analysis/CFRefCount.cpp @@ -777,7 +777,7 @@ CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym, namespace clang { - void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx, + void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx, Diagnostic& Diag) { if (Diag.hasErrorOccurred()) @@ -785,7 +785,7 @@ namespace clang { // FIXME: Refactor some day so this becomes a single function invocation. - GRCoreEngine Eng(cfg, FD, Ctx); + GRCoreEngine Eng(cfg, CD, Ctx); GRExprEngine* CS = &Eng.getCheckerState(); CFRefCount TF; CS->setTransferFunctions(TF); diff --git a/Analysis/GRSimpleVals.cpp b/Analysis/GRSimpleVals.cpp index a03303c079..ee5a44c48c 100644 --- a/Analysis/GRSimpleVals.cpp +++ b/Analysis/GRSimpleVals.cpp @@ -89,13 +89,13 @@ void EmitWarning(Diagnostic& Diag, SourceManager& SrcMgr, } } -unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx, +unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, Diagnostic& Diag, bool Visualize, bool TrimGraph) { if (Diag.hasErrorOccurred()) return 0; - GRCoreEngine Eng(cfg, FD, Ctx); + GRCoreEngine Eng(cfg, CD, Ctx); GRExprEngine* CheckerState = &Eng.getCheckerState(); GRSimpleVals GRSV; CheckerState->setTransferFunctions(GRSV); diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp index 8e99878f66..20fd18cd06 100644 --- a/Driver/ASTConsumers.cpp +++ b/Driver/ASTConsumers.cpp @@ -409,7 +409,13 @@ namespace { Out << "Read objc fwd class decl\n"; } else if (isa(D)) { Out << "Read file scope asm decl\n"; - } else { + } else if (ObjCMethodDecl* MD = dyn_cast(D)) { + Out << "Read objc method decl: '" << MD->getSelector().getName() + << "'\n"; + } else if (isa(D)) { + Out << "Read objc implementation decl\n"; + } + else { assert(0 && "Unknown decl type!"); } } @@ -439,6 +445,15 @@ namespace { llvm::cerr << '\n'; } } + else if (ObjCMethodDecl *MD = dyn_cast(D)) { + DeclPrinter().PrintObjCMethodDecl(MD); + + if (MD->getBody()) { + llvm::cerr << '\n'; + MD->getBody()->viewAST(); + llvm::cerr << '\n'; + } + } } }; } @@ -459,7 +474,7 @@ public: CFGVisitor() : FName("") {} // CFG Visitor interface to be implemented by subclass. - virtual void VisitCFG(CFG& C, FunctionDecl& FD) = 0; + virtual void VisitCFG(CFG& C, Decl& CD) = 0; virtual bool printFuncDeclStart() { return true; } virtual void HandleTopLevelDecl(Decl *D); @@ -468,27 +483,41 @@ public: } // end anonymous namespace void CFGVisitor::HandleTopLevelDecl(Decl *D) { - FunctionDecl *FD = dyn_cast(D); + + CFG *C = NULL; + + if (FunctionDecl *FD = dyn_cast(D)) { - if (!FD || !FD->getBody()) - return; + if (!FD->getBody()) + return; - if (FName.size() > 0 && FName != FD->getIdentifier()->getName()) - return; + if (FName.size() > 0 && FName != FD->getIdentifier()->getName()) + return; + + if (printFuncDeclStart()) { + DeclPrinter().PrintFunctionDeclStart(FD); + llvm::cerr << '\n'; + } - if (printFuncDeclStart()) { - DeclPrinter().PrintFunctionDeclStart(FD); - llvm::cerr << '\n'; + C = CFG::buildCFG(FD->getBody()); } + else if (ObjCMethodDecl *MD = dyn_cast(D)) { + + if (!MD->getBody()) + return; + + if (printFuncDeclStart()) { + DeclPrinter().PrintObjCMethodDecl(MD); + llvm::cerr << '\n'; + } - CFG *C = CFG::buildCFG(FD->getBody()); + C = CFG::buildCFG(MD->getBody()); + } if (C) { - VisitCFG(*C, *FD); + VisitCFG(*C, *D); delete C; } - else - llvm::cerr << "warning: CFG could not be constructed.\n"; } //===----------------------------------------------------------------------===// @@ -501,7 +530,7 @@ namespace { CFGDumper(bool use_graphviz, const std::string& fname) : CFGVisitor(fname), UseGraphviz(use_graphviz) {} - virtual void VisitCFG(CFG& C, FunctionDecl&) { + virtual void VisitCFG(CFG& C, Decl&) { if (UseGraphviz) C.viewCFG(); else @@ -527,7 +556,7 @@ namespace { SM = &Context.getSourceManager(); } - virtual void VisitCFG(CFG& C, FunctionDecl& FD) { + virtual void VisitCFG(CFG& C, Decl& CD) { LiveVariables L(C); L.runOnCFG(C); L.dumpBlockLiveness(*SM); @@ -552,7 +581,7 @@ namespace { Ctx = &Context; } - virtual void VisitCFG(CFG& C, FunctionDecl& FD) { + virtual void VisitCFG(CFG& C, Decl& CD) { CheckDeadStores(C, *Ctx, Diags); } @@ -578,7 +607,7 @@ namespace { Ctx = &Context; } - virtual void VisitCFG(CFG& C, FunctionDecl&) { + virtual void VisitCFG(CFG& C, Decl&) { CheckUninitializedValues(C, *Ctx, Diags); } @@ -605,7 +634,7 @@ namespace { : CFGVisitor(fname), Diags(diags), Visualize(visualize), TrimGraph(trim){} virtual void Initialize(ASTContext &Context) { Ctx = &Context; } - virtual void VisitCFG(CFG& C, FunctionDecl&); + virtual void VisitCFG(CFG& C, Decl&); virtual bool printFuncDeclStart() { return false; } }; } // end anonymous namespace @@ -617,28 +646,37 @@ ASTConsumer* clang::CreateGRSimpleVals(Diagnostic &Diags, return new GRSimpleValsVisitor(Diags, FunctionName, Visualize, TrimGraph); } -void GRSimpleValsVisitor::VisitCFG(CFG& C, FunctionDecl& FD) { +void GRSimpleValsVisitor::VisitCFG(CFG& C, Decl& CD) { - SourceLocation Loc = FD.getLocation(); + SourceLocation Loc = CD.getLocation(); if (!Loc.isFileID() || Loc.getFileID() != Ctx->getSourceManager().getMainFileID()) return; if (!Visualize) { - llvm::cerr << "ANALYZE: " << FD.getIdentifier()->getName() << ' ' - << Ctx->getSourceManager().getSourceName(FD.getLocation()) - << ' '; + + if (FunctionDecl *FD = dyn_cast(&CD)) { + llvm::cerr << "ANALYZE: " << FD->getIdentifier()->getName() << ' ' + << Ctx->getSourceManager().getSourceName(FD->getLocation()) + << ' '; + } + else if (ObjCMethodDecl *MD = dyn_cast(&CD)) { + llvm::cerr << "ANALYZE (ObjC Method): " + << MD->getSelector().getName() << ' ' + << Ctx->getSourceManager().getSourceName(MD->getLocation()) + << ' '; + } llvm::Timer T("GRSimpleVals"); T.startTimer(); - unsigned size = RunGRSimpleVals(C, FD, *Ctx, Diags, false, false); + unsigned size = RunGRSimpleVals(C, CD, *Ctx, Diags, false, false); T.stopTimer(); llvm::cerr << size << ' ' << T.getWallTime() << '\n'; } else { llvm::cerr << '\n'; - RunGRSimpleVals(C, FD, *Ctx, Diags, Visualize, TrimGraph); + RunGRSimpleVals(C, CD, *Ctx, Diags, Visualize, TrimGraph); } } @@ -656,7 +694,7 @@ namespace { : CFGVisitor(fname), Diags(diags) {} virtual void Initialize(ASTContext &Context) { Ctx = &Context; } - virtual void VisitCFG(CFG& C, FunctionDecl&); + virtual void VisitCFG(CFG& C, Decl&); virtual bool printFuncDeclStart() { return false; } }; } // end anonymous namespace @@ -668,15 +706,15 @@ ASTConsumer* clang::CreateCFRefChecker(Diagnostic &Diags, return new CFRefCountCheckerVisitor(Diags, FunctionName); } -void CFRefCountCheckerVisitor::VisitCFG(CFG& C, FunctionDecl& FD) { +void CFRefCountCheckerVisitor::VisitCFG(CFG& C, Decl& CD) { - SourceLocation Loc = FD.getLocation(); + SourceLocation Loc = CD.getLocation(); if (!Loc.isFileID() || Loc.getFileID() != Ctx->getSourceManager().getMainFileID()) return; - CheckCFRefCount(C, FD, *Ctx, Diags); + CheckCFRefCount(C, CD, *Ctx, Diags); } //===----------------------------------------------------------------------===// diff --git a/include/clang/Analysis/Analyses/GRSimpleVals.h b/include/clang/Analysis/Analyses/GRSimpleVals.h index c8054ff253..2e772ef536 100644 --- a/include/clang/Analysis/Analyses/GRSimpleVals.h +++ b/include/clang/Analysis/Analyses/GRSimpleVals.h @@ -24,7 +24,7 @@ namespace clang { /// on a provided CFG. This interface will eventually be replaced with /// something more elaborate as the requirements on the interface become /// clearer. The value returned is the number of nodes in the ExplodedGraph. - unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx, + unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, Diagnostic& Diag, bool Visualize, bool TrimGraph); } // end clang namespace diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h index 3ae41f4ce9..0966ffc039 100644 --- a/include/clang/Analysis/LocalCheckers.h +++ b/include/clang/Analysis/LocalCheckers.h @@ -18,7 +18,7 @@ namespace clang { class CFG; -class FunctionDecl; +class Decl; class Diagnostic; class ASTContext; @@ -27,7 +27,7 @@ void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags); void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, bool FullUninitTaint=false); -void CheckCFRefCount(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx, +void CheckCFRefCount(CFG& cfg, Decl& CodeDecl, ASTContext& Ctx, Diagnostic& Diag); } // end namespace clang diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index b8c66368da..79a4c85f07 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH #include "clang/Analysis/ProgramPoint.h" +#include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallPtrSet.h" @@ -23,6 +24,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/Support/Casting.h" namespace clang { @@ -34,9 +36,7 @@ class GRIndirectGotoNodeBuilderImpl; class GRSwitchNodeBuilderImpl; class CFG; class ASTContext; -class FunctionDecl; - class ExplodedNodeImpl : public llvm::FoldingSetNode { protected: friend class ExplodedGraphImpl; @@ -220,10 +220,11 @@ protected: /// cfg - The CFG associated with this analysis graph. CFG& cfg; - /// FD - The function declaration of the function being analyzed. - FunctionDecl& FD; + /// CodeDecl - The declaration containing the code being analyzed. This + /// can be a FunctionDecl or and ObjCMethodDecl. + Decl& CodeDecl; - /// Ctx - The ASTContext used to "interpret" FD. + /// Ctx - The ASTContext used to "interpret" CodeDecl. ASTContext& Ctx; /// NumNodes - The number of nodes in the graph. @@ -250,8 +251,8 @@ protected: } // ctor. - ExplodedGraphImpl(CFG& c, FunctionDecl& f, ASTContext& ctx) - : cfg(c), FD(f), Ctx(ctx), NumNodes(0) {} + ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx) + : cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {} public: virtual ~ExplodedGraphImpl() {} @@ -265,7 +266,12 @@ public: llvm::BumpPtrAllocator& getAllocator() { return Allocator; } CFG& getCFG() { return cfg; } ASTContext& getContext() { return Ctx; } - FunctionDecl& getFunctionDecl() { return FD; } + + const Decl& getCodeDecl() const { return CodeDecl; } + + const FunctionDecl* getFunctionDecl() const { + return llvm::dyn_cast(&CodeDecl); + } ExplodedGraphImpl* Trim(ExplodedNodeImpl** NBeg, ExplodedNodeImpl** NEnd) const; @@ -294,12 +300,12 @@ protected: } virtual ExplodedGraphImpl* MakeEmptyGraph() const { - return new ExplodedGraph(cfg, FD, Ctx); + return new ExplodedGraph(cfg, CodeDecl, Ctx); } public: - ExplodedGraph(CFG& c, FunctionDecl& fd, ASTContext& ctx) - : ExplodedGraphImpl(c, fd, ctx), CheckerState(new CheckerTy(*this)) {} + ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx) + : ExplodedGraphImpl(c, cd, ctx), CheckerState(new CheckerTy(*this)) {} /// getCheckerState - Returns the internal checker state associated /// with the exploded graph. Ownership remains with the ExplodedGraph diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index bb0e209552..5ca15542ba 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -505,15 +505,15 @@ protected: public: /// Construct a GRCoreEngine object to analyze the provided CFG using /// a DFS exploration of the exploded graph. - GRCoreEngine(CFG& cfg, FunctionDecl& fd, ASTContext& ctx) - : GRCoreEngineImpl(new GraphTy(cfg, fd, ctx), GRWorkList::MakeDFS()), + GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx) + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), GRWorkList::MakeDFS()), Checker(static_cast(G.get())->getCheckerState()) {} /// Construct a GRCoreEngine object to analyze the provided CFG and to /// use the provided worklist object to execute the worklist algorithm. /// The GRCoreEngine object assumes ownership of 'wlist'. - GRCoreEngine(CFG& cfg, FunctionDecl& fd, ASTContext& ctx, GRWorkList* wlist) - : GRCoreEngineImpl(new GraphTy(cfg, fd, ctx), wlist), + GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist) + : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist), Checker(static_cast(G.get())->getCheckerState()) {} virtual ~GRCoreEngine() {}