<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Fri, Jul 27, 2018 at 10:39 AM Gabor Marton via Phabricator <<a href="mailto:reviews@reviews.llvm.org">reviews@reviews.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">martong added a comment.<br>
<br>
> MatchFinder::match allows you to match a node. Wrapping your matcher code with:<br>
>  auto m = <my cool matcher>;<br>
>  ast_matchers::match(anyOf(m, hashDescendant(m)), node, context);<br>
<br>
Okay, I understand and accept that.<br>
However, I consider that a different level of abstraction. `ast_matchers::match` uses `internal::CollectMatchesCallback` in its implementation. If I already have my own custom MatchCallback implemented then there is no way to achieve the desired behavior.<br>
<br>
For example, in `ASTImporter` tests we use the following customized callback class:<br>
<br>
  enum class DeclMatcherKind { First, Last };<br>
<br>
  // Matcher class to retrieve the first/last matched node under a given AST.<br>
  template <typename NodeType, DeclMatcherKind MatcherKind><br>
  class DeclMatcher : public MatchFinder::MatchCallback {<br>
    NodeType *Node = nullptr;<br>
    void run(const MatchFinder::MatchResult &Result) override {<br>
      if ((MatcherKind == DeclMatcherKind::First && Node == nullptr) ||<br>
          MatcherKind == DeclMatcherKind::Last) {<br>
        Node = const_cast<NodeType *>(Result.Nodes.getNodeAs<NodeType>(""));<br>
      }<br>
    }<br>
  public:<br>
    // Returns the first/last matched node under the tree rooted in `D`.<br>
    template <typename MatcherType><br>
    NodeType *match(const Decl *D, const MatcherType &AMatcher) {<br>
      MatchFinder Finder;<br>
      Finder.addMatcher(AMatcher.bind(""), this);<br>
      Finder.matchAST(D->getASTContext());<br>
      assert(Node);<br>
      return Node;<br>
    }<br>
  };<br>
  template <typename NodeType><br>
  using LastDeclMatcher = DeclMatcher<NodeType, DeclMatcherKind::Last>;<br>
  template <typename NodeType><br>
  using FirstDeclMatcher = DeclMatcher<NodeType, DeclMatcherKind::First>;<br>
<br>
And this is how we use it in the tests:<br>
<br>
  Decl *FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX);<br>
  auto Pattern = functionDecl(hasName("f"));<br>
  auto *D0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);<br>
  auto *D2 = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);<br>
<br>
At this point we would like to extend this `DeclMatcher` to be able to match a subtree, and be able to start the traverse from a specific `Decl`, something like this :<br>
<br>
  auto *DV = FirsDeclMatcher<VarDecl>().match(D2, SomeOtherPattern);<br>
<br>
Currently, I don't see how we could do this extension without the proposed `matchSubtree`. <br>
(Perhaps, we could refactor our `DeclMatcher` to not use a customized MatchCallback, rather use `ast_matchers::match`, but that sounds like a bad workaround to me.)<br>
<br>
Hope this makes the the goal of this patch cleaner.<br></blockquote><div><br></div><div>Finder.match also has an overload that takes the node. Can you wrap "Pattern" above in the anyOf(hasDescendant(...), ...) and match on the node instead of the full AST?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
Repository:<br>
  rC Clang<br>
<br>
<a href="https://reviews.llvm.org/D49840" rel="noreferrer" target="_blank">https://reviews.llvm.org/D49840</a><br>
<br>
<br>
<br>
</blockquote></div></div>