From 1baedeccd6989bcf270f1fcd2e6b37d5dcb9f46e Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Fri, 22 Jan 2016 22:32:46 +0000 Subject: [PATCH] [analyzer] Utility to match function calls. This patch adds a small utility to match function calls. This utility abstracts away the mutable keywords and the lazy initialization and caching logic of identifiers from the checkers. The SimpleStreamChecker is ported over this utility within this patch to show the reduction of code and to test this change. Differential Revision: http://reviews.llvm.org/D15921 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@258572 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Core/PathSensitive/CallEvent.h | 28 +++++++++++++++++++ .../Checkers/SimpleStreamChecker.cpp | 25 +++-------------- lib/StaticAnalyzer/Core/CallEvent.cpp | 10 +++++++ 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index b09dffaf4e..a67204c3bd 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -49,6 +49,27 @@ enum CallEventKind { class CallEvent; class CallEventManager; +/// This class represents a description of a function call using the number of +/// arguments and the name of the function. +class CallDescription { + friend CallEvent; + mutable IdentifierInfo *II; + StringRef FuncName; + unsigned RequiredArgs; + +public: + const static unsigned NoArgRequirement = ~0; + /// \brief Constructs a CallDescription object. + /// + /// @param FuncName The name of the function that will be matched. + /// + /// @param RequiredArgs The number of arguments that is expected to match a + /// call. Omit this parameter to match every occurance of call with a given + /// name regardless the number of arguments. + CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement) + : FuncName(FuncName), RequiredArgs(RequiredArgs) {} +}; + template class CallEventRef : public IntrusiveRefCntPtr { public: @@ -227,6 +248,13 @@ public: return false; } + /// \brief Returns true if the CallEvent is a call to a function that matches + /// the CallDescription. + /// + /// Note that this function is not intended to be used to match Obj-C method + /// calls. + bool isCalled(const CallDescription &CD) const; + /// \brief Returns a source range for the entire call, suitable for /// outputting in diagnostics. virtual SourceRange getSourceRange() const { diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index 7026a2ec16..62e6f02fe3 100644 --- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -51,14 +51,11 @@ class SimpleStreamChecker : public Checker { - - mutable IdentifierInfo *IIfopen, *IIfclose; + CallDescription OpenFn, CloseFn; std::unique_ptr DoubleCloseBugType; std::unique_ptr LeakBugType; - void initIdentifierInfo(ASTContext &Ctx) const; - void reportDoubleClose(SymbolRef FileDescSym, const CallEvent &Call, CheckerContext &C) const; @@ -106,7 +103,7 @@ public: } // end anonymous namespace SimpleStreamChecker::SimpleStreamChecker() - : IIfopen(nullptr), IIfclose(nullptr) { + : OpenFn("fopen"), CloseFn("fclose", 1) { // Initialize the bug types. DoubleCloseBugType.reset( new BugType(this, "Double fclose", "Unix Stream API Error")); @@ -119,12 +116,10 @@ SimpleStreamChecker::SimpleStreamChecker() void SimpleStreamChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { - initIdentifierInfo(C.getASTContext()); - if (!Call.isGlobalCFunction()) return; - if (Call.getCalleeIdentifier() != IIfopen) + if (!Call.isCalled(OpenFn)) return; // Get the symbolic value corresponding to the file handle. @@ -140,15 +135,10 @@ void SimpleStreamChecker::checkPostCall(const CallEvent &Call, void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - initIdentifierInfo(C.getASTContext()); - if (!Call.isGlobalCFunction()) return; - if (Call.getCalleeIdentifier() != IIfclose) - return; - - if (Call.getNumArgs() != 1) + if (!Call.isCalled(CloseFn)) return; // Get the symbolic value corresponding to the file handle. @@ -275,13 +265,6 @@ SimpleStreamChecker::checkPointerEscape(ProgramStateRef State, return State; } -void SimpleStreamChecker::initIdentifierInfo(ASTContext &Ctx) const { - if (IIfopen) - return; - IIfopen = &Ctx.Idents.get("fopen"); - IIfclose = &Ctx.Idents.get("fclose"); -} - void ento::registerSimpleStreamChecker(CheckerManager &mgr) { mgr.registerChecker(); } diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 69af09b25b..59b90b5ce9 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -210,6 +210,16 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, return PostImplicitCall(D, Loc, getLocationContext(), Tag); } +bool CallEvent::isCalled(const CallDescription &CD) const { + assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported"); + if (!CD.II) + CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); + if (getCalleeIdentifier() != CD.II) + return false; + return (CD.RequiredArgs == CallDescription::NoArgRequirement || + CD.RequiredArgs == getNumArgs()); +} + SVal CallEvent::getArgSVal(unsigned Index) const { const Expr *ArgE = getArgExpr(Index); if (!ArgE) -- 2.40.0