Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -49,6 +49,27 @@ 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 @@ 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 { Index: cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -51,14 +51,11 @@ check::PreCall, check::DeadSymbols, check::PointerEscape> { - - 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 @@ } // 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 @@ 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::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 @@ 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(); } Index: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -210,6 +210,16 @@ 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)