baloghadamsoftware created this revision.
baloghadamsoftware added a reviewer: sbenza.
baloghadamsoftware added subscribers: cfe-commits, xazax.hun, o.gyorgy.
Herald added a subscriber: klimek.
Matcher proposed in the review of checker misc-assign-operator (name pending). 
Its goal is to find the direct enclosing function declaration of a statement 
and run the inner matcher on it. Two version is attached in this patch (thus it 
will not compile), to be decided which approach to take. The first one always 
chooses one single parent, the other one does a depth-first search upwards 
(thus a height-first search) and returns the first positive match of the inner 
matcher (thus it always returns zero or one matches, not more). Further 
questions: is it enough to implement it in-place, or ASTMatchersInternals or 
maybe ASTMatchFinder should be involved?

http://reviews.llvm.org/D19357

Files:
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -5568,5 +5568,38 @@
   EXPECT_FALSE(matches("void F() { return; }", RetVal));
 }
 
+TEST(StatementMatcher, ForFunction) {
+  const auto CppString =
+    "namespace std {"
+    "template<typename IIter, typename OIter, typename Pred>"
+    "OIter copy_if(IIter sb, IIter se, OIter db, Pred pr);"
+    "}"
+    "class PosVec {"
+    "  int n;"
+    "public:"
+    "  typedef PosVec *iterator;"
+    "  typedef const PosVec *const_iterator;"
+    "  iterator begin();"
+    "  iterator end();"
+    "  const_iterator begin() const;"
+    "  const_iterator end() const;"
+    "  PosVec& operator= (const PosVec& o) {"
+    "    std::copy_if(o.begin(), o.end(), begin(), [](PosVec& v) { return v.n > 0; });"
+    "    return *this;"
+    "  }"
+    "};";
+  EXPECT_TRUE(
+    matches(
+      CppString,
+      returnStmt(forFunction(hasName("operator=")),
+                 has(unaryOperator(hasOperatorName("*"))))));
+  EXPECT_FALSE(
+    matches(
+      CppString,
+      returnStmt(forFunction(hasName("operator=")),
+                 has(binaryOperator(hasOperatorName(">"))))));
+                 llvm::errs()<<"d";
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -184,6 +184,7 @@
   REGISTER_MATCHER(forEachDescendant);
   REGISTER_MATCHER(forEachSwitchCase);
   REGISTER_MATCHER(forField);
+  REGISTER_MATCHER(forFunction);
   REGISTER_MATCHER(forStmt);
   REGISTER_MATCHER(friendDecl);
   REGISTER_MATCHER(functionDecl);
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -5108,6 +5108,66 @@
       gnuNullExpr(), cxxNullPtrLiteralExpr(),
       integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
 }
+
+/// \brief Matches declaration of the function the statemenet belongs to
+///
+/// Given:
+/// \code
+/// F& operator=(const F& o) {
+///   std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
+///   return *this;
+/// }
+/// \endcode
+/// returnStmt(forFunction(hasName("operator=")))
+///   matches 'return *this'
+///   but does match 'return > 0'
+AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
+              InnerMatcher) {
+  const auto &Parents = Finder->getASTContext().getParents(Node);
+  assert(!Parents.empty() && "Found node that is not in the parent map.");
+
+  std::deque<ast_type_traits::DynTypedNode> Stack(Parents.begin(),
+                                                  Parents.end());
+  while(!Stack.empty()) {
+    const auto &CurNode = Stack.back();
+    Stack.pop_back();
+    if(const auto *DeclNode = CurNode.get<Decl>()) {
+      if(const auto *FuncDeclNode = dyn_cast<FunctionDecl>(DeclNode)) {
+        if(InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) {
+          return true;
+        }
+      }
+    }
+    const auto *StmtNode = CurNode.get<Stmt>();
+    if(StmtNode&&!isa<LambdaExpr>(StmtNode)) {
+      for(const auto &Parent: Finder->getASTContext().getParents(*StmtNode))
+        Stack.push_back(Parent);
+    }
+  }
+  return false;
+}
+
+AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
+              InnerMatcher) {
+  const auto *CurNode = &Node;
+  while(CurNode) {
+    const auto &Parents = Finder->getASTContext().getParents(*CurNode);
+    assert(!Parents.empty() && "Found node that is not in the parent map.");
+    const auto &Parent = Parents[0];
+    if(const auto *DeclNode = Parent.get<Decl>()) {
+      if(const auto *FuncDeclNode = dyn_cast<FunctionDecl>(DeclNode)) {
+        return InnerMatcher.matches(*FuncDeclNode, Finder, Builder);
+      }
+      return false;
+    }
+    CurNode = Parent.get<Stmt>();
+    if(CurNode&&isa<LambdaExpr>(CurNode)) {
+      return false;
+    }
+  }
+  return false;
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to