xazax.hun created this revision.
xazax.hun added reviewers: zaks.anna, dcoughlin.
xazax.hun added subscribers: cfe-commits, dkrupp.

This patch adds a small utility to match function calls and Obj-C messages. 
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.

http://reviews.llvm.org/D15921

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
  lib/StaticAnalyzer/Core/CheckerContext.cpp

Index: lib/StaticAnalyzer/Core/CheckerContext.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Lex/Lexer.h"
 
@@ -35,6 +36,26 @@
   return funI->getName();
 }
 
+bool CheckerContext::isCalled(const CallEvent &Call,
+                              const CallDescription &CD) {
+  assert(Call.getKind() != CE_ObjCMessage);
+  if (!CD.II)
+    CD.II = &getASTContext().Idents.get(CD.FuncName);
+  if (CD.RequiredArgs != CallDescription::NoArgRequirement &&
+      CD.RequiredArgs != Call.getNumArgs())
+    return false;
+  return Call.getCalleeIdentifier() == CD.II;
+}
+
+bool CheckerContext::isCalled(const ObjCMethodCall &Call,
+                              const CallDescription &CD) {
+  if (!CD.II)
+    CD.II = &getASTContext().Idents.get(CD.FuncName);
+  if (CD.RequiredArgs != CallDescription::NoArgRequirement &&
+      CD.RequiredArgs != Call.getNumArgs())
+    return false;
+  return Call.getSelector() == getASTContext().Selectors.getSelector(0, &CD.II);
+}
 
 bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
                                         StringRef Name) {
@@ -91,4 +112,3 @@
   SmallVector<char, 16> buf;
   return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts());
 }
-
Index: lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ 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<BugType> DoubleCloseBugType;
   std::unique_ptr<BugType> 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 (!C.isCalled(Call, 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 (!C.isCalled(Call, 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<SimpleStreamChecker>();
 }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -66,6 +66,28 @@
   #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
 
+/// This class represents a description of a function call using the number of
+/// arguments and the name of the function. It can also represent descriptions
+/// of Obj-C message expressions.
+class CallDescription {
+  friend class CheckerContext;
+  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 or the selector 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) {}
+};
 
 class CheckerContext {
   ExprEngine &Eng;
@@ -284,6 +306,17 @@
     return getCalleeName(FunDecl);
   }
 
+  /// \brief Returns true if the CallEvent is call to a function that matches
+  /// the CallDescription.
+  ///
+  /// Note that this overload is not intended to be used to match Obj-C method
+  /// calls. Use the corresponding overload for that case.
+  bool isCalled(const CallEvent &Call, const CallDescription &CD);
+
+  /// \brief Returns true if the ObjCMethodCall is call to a method that matches
+  /// the CallDescription.
+  bool isCalled(const ObjCMethodCall &Call, const CallDescription &CD);
+
   /// \brief Returns true if the callee is an externally-visible function in the
   /// top-level namespace, such as \c malloc.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to