[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2020-05-28 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel added inline comments.



Comment at: include/clang/ASTMatchers/ASTMatchersInternal.h:286
+
+  virtual llvm::Optional TraversalKind() const 
{
+return {};

aaron.ballman wrote:
> `traversalKind()`
Stephen -- What was the resolution on this comment? I came across this when 
writing my recent fixes and it stood out for going against the style guide and 
the surrounding style. Is this intentional or an oversight?

Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-12-06 Thread Stephen Kelly via Phabricator via cfe-commits
steveire added a comment.

I tried using DenseMap, but couldn't make it compile. I stuck with std::map for 
now.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-12-06 Thread Stephen Kelly via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG0a717d5b5d31: Make it possible control matcher traversal 
kind with ASTContext (authored by stephenkelly).

Changed prior to commit:
  https://reviews.llvm.org/D61837?vs=230678&id=232661#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/ASTMatchers/ASTMatchFinder.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1595,6 +1595,91 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(
+  notMatches(VarDeclCode, traverse(ast_type_traits::TK_AsIs, Matcher)));
+  EXPECT_TRUE(
+  matches(VarDeclCode,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   Matcher)));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+  Code,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   callExpr(has(callExpr(traverse(
+   ast_type_traits::TK_AsIs,
+   callExpr(has(implicitCastExpr(has(floatLiteral(;
+}
+
+TEST(Traversal, traverseMatcherThroughImplicit) {
+  StringRef Code = R"cpp(
+struct S {
+  S(int x);
+};
+
+void constructImplicit() {
+  int a = 8;
+  S s(a);
+}
+  )cpp";
+
+  auto Matcher = traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+  implicitCastExpr());
+
+  // Verfiy that it does not segfault
+  EXPECT_FALSE(matches(Code, Matcher));
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(matches(
+  Code, functionDecl(anyOf(
+hasDescendant(Matcher),
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+ functionDecl(hasDescendant(Matcher)));
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -189,6 +189,14 @@
   llvm_unreachable("Invalid Op value.");
 }
 
+DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper(
+const DynTypedMatcher &InnerMatcher,
+ast_type_traits::ASTNodeKind RestrictKind) {
+  DynTypedMatcher Copy = InnerMatcher;
+  Copy.RestrictKind = RestrictKind;
+  return Copy;
+}
+
 DynTypedMatcher DynTypedMatcher::trueMatcher(
 ast_type_traits::ASTNodeKind NodeKind) {
   return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance);
@@ -211,8 +219,13 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  TraversalKindScope RAII(Finder->getASTContext(),
+  Implementation->TraversalKind());
+
+  auto N = Finder->getASTContext().traverseIgnored(DynNode);
+
+  if (RestrictKind.isBaseOf(N.getNodeKind()) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
@@ -225,8 +238,13 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, AS

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-11-23 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman accepted this revision.
aaron.ballman added a comment.
This revision is now accepted and ready to land.

LGTM with a few minor nits.




Comment at: clang/include/clang/AST/ASTContext.h:3009
   class ParentMap;
-  std::unique_ptr Parents;
+  std::map> Parents;
 

Do we need to use `std::map` here, or could we use an `IndexedMap` or 
`DenseMap`?

(`std::map` tends to perform poorly under some circumstances and the keys in 
this case look like they should be small and dense, but if we can't use one of 
the more specialized containers for some reason, it's fine to stick with 
`std::map`.)



Comment at: clang/lib/AST/ASTContext.cpp:120
+ASTContext::traverseIgnored(const ast_type_traits::DynTypedNode &N) const {
+  if (auto *E = N.get()) {
+return ast_type_traits::DynTypedNode::create(*traverseIgnored(E));

Because `N` is const, does its `get<>` method return a `const` pointer? If so, 
switch to `const auto *` for clarity.



Comment at: clang/lib/ASTMatchers/ASTMatchersInternal.cpp:222
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  TraversalKindScope raii(Finder->getASTContext(),
+  Implementation->TraversalKind());

`raii` -> `RAII` per naming conventions.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-11-22 Thread Stephen Kelly via Phabricator via cfe-commits
steveire updated this revision to Diff 230678.
steveire added a comment.

Rebase and update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/ASTMatchers/ASTMatchFinder.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1595,6 +1595,91 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(
+  notMatches(VarDeclCode, traverse(ast_type_traits::TK_AsIs, Matcher)));
+  EXPECT_TRUE(
+  matches(VarDeclCode,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   Matcher)));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+  Code,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   callExpr(has(callExpr(traverse(
+   ast_type_traits::TK_AsIs,
+   callExpr(has(implicitCastExpr(has(floatLiteral(;
+}
+
+TEST(Traversal, traverseMatcherThroughImplicit) {
+  StringRef Code = R"cpp(
+struct S {
+  S(int x);
+};
+
+void constructImplicit() {
+  int a = 8;
+  S s(a);
+}
+  )cpp";
+
+  auto Matcher = traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+  implicitCastExpr());
+
+  // Verfiy that it does not segfault
+  EXPECT_FALSE(matches(Code, Matcher));
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(matches(
+  Code, functionDecl(anyOf(
+hasDescendant(Matcher),
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+ functionDecl(hasDescendant(Matcher)));
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -189,6 +189,14 @@
   llvm_unreachable("Invalid Op value.");
 }
 
+DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper(
+const DynTypedMatcher &InnerMatcher,
+ast_type_traits::ASTNodeKind RestrictKind) {
+  DynTypedMatcher Copy = InnerMatcher;
+  Copy.RestrictKind = RestrictKind;
+  return Copy;
+}
+
 DynTypedMatcher DynTypedMatcher::trueMatcher(
 ast_type_traits::ASTNodeKind NodeKind) {
   return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance);
@@ -211,8 +219,13 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  TraversalKindScope raii(Finder->getASTContext(),
+  Implementation->TraversalKind());
+
+  auto N = Finder->getASTContext().traverseIgnored(DynNode);
+
+  if (RestrictKind.isBaseOf(N.getNodeKind()) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
@@ -225,8 +238,13 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  T

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-17 Thread Stephen Kelly via Phabricator via cfe-commits
steveire marked an inline comment as done.
steveire added inline comments.



Comment at: lib/ASTMatchers/ASTMatchersInternal.cpp:240
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {

aaron.ballman wrote:
> steveire wrote:
> > aaron.ballman wrote:
> > > Add an assertion message?
> > Saying what? The original code doesn't have one. Let's avoid round trips in 
> > review comments :).
> This isn't a "round trip"; it's not unreasonable to ask people to NFC improve 
> the code they're touching (it's akin to saying "Because you figured out this 
> complex piece of code does X, can you add a comment to it so others don't 
> have to do that work next time.").
> 
> As best I can tell, this assertion exists because this function is meant to 
> mirror `matches()` without this base check in release mode. You've lost that 
> mirroring with your refactoring, which looks suspicious. Is there a reason 
> this function deviates from `matches()` now?
> 
> As for the assertion message itself, how about "matched a node of an 
> unexpected derived kind"?
Hmm, maybe that was a misunderstanding. Your note about an assertion message 
was not clear, so I asked you what you suggest the message should be. No need 
for offense :)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-17 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: lib/AST/ASTContext.cpp:120
+ASTContext::TraverseIgnored(const ast_type_traits::DynTypedNode &N) {
+  if (auto E = N.get()) {
+return ast_type_traits::DynTypedNode::create(*TraverseIgnored(E));

aaron.ballman wrote:
> `auto *`
The formatting is wrong here -- be sure to run the patch through clang-format 
before committing.



Comment at: lib/ASTMatchers/ASTMatchersInternal.cpp:240
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {

steveire wrote:
> aaron.ballman wrote:
> > Add an assertion message?
> Saying what? The original code doesn't have one. Let's avoid round trips in 
> review comments :).
This isn't a "round trip"; it's not unreasonable to ask people to NFC improve 
the code they're touching (it's akin to saying "Because you figured out this 
complex piece of code does X, can you add a comment to it so others don't have 
to do that work next time.").

As best I can tell, this assertion exists because this function is meant to 
mirror `matches()` without this base check in release mode. You've lost that 
mirroring with your refactoring, which looks suspicious. Is there a reason this 
function deviates from `matches()` now?

As for the assertion message itself, how about "matched a node of an unexpected 
derived kind"?


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-17 Thread Stephen Kelly via Phabricator via cfe-commits
steveire marked an inline comment as done.
steveire added inline comments.



Comment at: lib/ASTMatchers/ASTMatchersInternal.cpp:240
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {

aaron.ballman wrote:
> Add an assertion message?
Saying what? The original code doesn't have one. Let's avoid round trips in 
review comments :).


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: include/clang/ASTMatchers/ASTMatchers.h:718
+template 
+internal::Matcher traverse(ast_type_traits::TraversalKind TK,
+  const internal::Matcher &InnerMatcher) {

steveire wrote:
> aaron.ballman wrote:
> > steveire wrote:
> > > aaron.ballman wrote:
> > > > Is this an API we should be exposing to clang-query as well? Will those 
> > > > users be able to use a string literal for the traversal kind, like they 
> > > > already do for attribute kinds (etc)?
> > > Yes, I thought about that, but in a follow-up patch. First, I aim to 
> > > extend the `TraversalKind` enum with `TK_IgnoreInvisble`.
> > This is new functionality, so why do you want to wait for a follow-up patch 
> > (is it somehow more involved)? We typically add support for dynamic 
> > matchers at the same time we add support for the static matchers because 
> > otherwise the two get frustratingly out of sync.
> Perhaps I can add the support in DynamicASTMatchers. Can you give some 
> direction on that? I don't recall where the attr strings are handled.
> 
> A corresponding change to `clang-query` will be in another patch anyway 
> because it's a different repo.
> Perhaps I can add the support in DynamicASTMatchers. Can you give some 
> direction on that? I don't recall where the attr strings are handled.

I always wind up having to use svn blame to figure it out, so you're not alone 
in your recollections. ;-) You add a new specialization of `ArgTypeTraits` to 
Marshallers.h for the enumeration type. See around line 123 or so for how it's 
done for `attr::Kind`.

> A corresponding change to clang-query will be in another patch anyway because 
> it's a different repo.

Once you have the enumeration being marshaled, I believe all you have to do is 
expose the new API via Registry.cpp like any other matcher, though I'd also 
request tests be added to Dynamic/RegistryTest.cpp since this is adding a small 
amount of new marshaling code.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Stephen Kelly via Phabricator via cfe-commits
steveire marked 2 inline comments as done.
steveire added inline comments.



Comment at: include/clang/ASTMatchers/ASTMatchers.h:718
+template 
+internal::Matcher traverse(ast_type_traits::TraversalKind TK,
+  const internal::Matcher &InnerMatcher) {

aaron.ballman wrote:
> steveire wrote:
> > aaron.ballman wrote:
> > > Is this an API we should be exposing to clang-query as well? Will those 
> > > users be able to use a string literal for the traversal kind, like they 
> > > already do for attribute kinds (etc)?
> > Yes, I thought about that, but in a follow-up patch. First, I aim to extend 
> > the `TraversalKind` enum with `TK_IgnoreInvisble`.
> This is new functionality, so why do you want to wait for a follow-up patch 
> (is it somehow more involved)? We typically add support for dynamic matchers 
> at the same time we add support for the static matchers because otherwise the 
> two get frustratingly out of sync.
Perhaps I can add the support in DynamicASTMatchers. Can you give some 
direction on that? I don't recall where the attr strings are handled.

A corresponding change to `clang-query` will be in another patch anyway because 
it's a different repo.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Stephen Kelly via Phabricator via cfe-commits
steveire updated this revision to Diff 199884.
steveire added a comment.

Update


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/ASTNodeTraverser.h
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/AST/ASTContext.cpp
  lib/ASTMatchers/ASTMatchFinder.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1510,6 +1510,72 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(
+  notMatches(VarDeclCode, traverse(ast_type_traits::TK_AsIs, Matcher)));
+  EXPECT_TRUE(
+  matches(VarDeclCode,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   Matcher)));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+  Code,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   callExpr(has(callExpr(traverse(
+   ast_type_traits::TK_AsIs,
+   callExpr(has(implicitCastExpr(has(floatLiteral(;
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(matches(
+  Code, functionDecl(anyOf(
+hasDescendant(Matcher),
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+ functionDecl(hasDescendant(Matcher)));
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -211,10 +211,19 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto PreviousTraversalKind = Finder->getASTContext().GetTraversalKind();
+  auto OptTK = Implementation->TraversalKind();
+  if (OptTK)
+Finder->getASTContext().SetTraversalKind(*OptTK);
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  if (RestrictKind.isBaseOf(NodeKind) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
+Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
 return true;
   }
+  Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
   // Delete all bindings when a matcher does not match.
   // This prevents unexpected exposure of bound nodes in unmatches
   // branches of the match tree.
@@ -225,8 +234,11 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -59,10 +59,12 @@
   DynTypedMatcher::MatcherIDType MatcherID;
   ast_type_traits::DynTypedNode Node;
   BoundNodesTreeBuilder BoundNodes;
+  ast_type_traits::TraversalKin

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: include/clang/AST/ASTContext.h:562-563
 public:
+  ast_type_traits::TraversalKind GetTraversalKind() const { return Traversal; }
+  void SetTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
+

steveire wrote:
> aaron.ballman wrote:
> > This doesn't match our coding guidelines. Should be `getTraversalKind()`, 
> > etc. Same below.
> I think clang still uses uppercase names everywhere. Can you be more specific?
No, Clang doesn't use uppercase names everywhere -- we're consistently 
inconsistent and it depends mostly on the age of when the code was introduced 
and what the surrounding code looks like. We still follow the usual coding 
style guidelines for naming conventions -- stick with the convention used by 
nearby code if it's already consistent, otherwise follow the coding style rules.



Comment at: include/clang/ASTMatchers/ASTMatchers.h:716
+/// \endcode
+/// matches the return statement with "ret" bound to "a".
+template 

aaron.ballman wrote:
> Copy pasta?
You dropped the interesting bit from the documentation here -- you should add 
in what the matcher is matching (which makes the preceding "The matcher \code 
... \endcode" grammatical again).



Comment at: include/clang/ASTMatchers/ASTMatchers.h:718
+template 
+internal::Matcher traverse(ast_type_traits::TraversalKind TK,
+  const internal::Matcher &InnerMatcher) {

steveire wrote:
> aaron.ballman wrote:
> > Is this an API we should be exposing to clang-query as well? Will those 
> > users be able to use a string literal for the traversal kind, like they 
> > already do for attribute kinds (etc)?
> Yes, I thought about that, but in a follow-up patch. First, I aim to extend 
> the `TraversalKind` enum with `TK_IgnoreInvisble`.
This is new functionality, so why do you want to wait for a follow-up patch (is 
it somehow more involved)? We typically add support for dynamic matchers at the 
same time we add support for the static matchers because otherwise the two get 
frustratingly out of sync.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Stephen Kelly via Phabricator via cfe-commits
steveire added inline comments.



Comment at: include/clang/AST/ASTContext.h:562-563
 public:
+  ast_type_traits::TraversalKind GetTraversalKind() const { return Traversal; }
+  void SetTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
+

aaron.ballman wrote:
> This doesn't match our coding guidelines. Should be `getTraversalKind()`, 
> etc. Same below.
I think clang still uses uppercase names everywhere. Can you be more specific?



Comment at: include/clang/AST/ASTContext.h:565-568
+  const Expr *TraverseIgnored(const Expr *E);
+  Expr *TraverseIgnored(Expr *E);
+  ast_type_traits::DynTypedNode
+  TraverseIgnored(const ast_type_traits::DynTypedNode &N);

aaron.ballman wrote:
> Is there a reason we don't want these functions to be marked `const`?
It looks like they can be const.



Comment at: include/clang/ASTMatchers/ASTMatchers.h:718
+template 
+internal::Matcher traverse(ast_type_traits::TraversalKind TK,
+  const internal::Matcher &InnerMatcher) {

aaron.ballman wrote:
> Is this an API we should be exposing to clang-query as well? Will those users 
> be able to use a string literal for the traversal kind, like they already do 
> for attribute kinds (etc)?
Yes, I thought about that, but in a follow-up patch. First, I aim to extend the 
`TraversalKind` enum with `TK_IgnoreInvisble`.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Stephen Kelly via Phabricator via cfe-commits
steveire updated this revision to Diff 199875.
steveire marked 10 inline comments as done.
steveire added a comment.

Update


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/ASTNodeTraverser.h
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/AST/ASTContext.cpp
  lib/ASTMatchers/ASTMatchFinder.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1510,6 +1510,72 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(
+  notMatches(VarDeclCode, traverse(ast_type_traits::TK_AsIs, Matcher)));
+  EXPECT_TRUE(
+  matches(VarDeclCode,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   Matcher)));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+  Code,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   callExpr(has(callExpr(traverse(
+   ast_type_traits::TK_AsIs,
+   callExpr(has(implicitCastExpr(has(floatLiteral(;
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(matches(
+  Code, functionDecl(anyOf(
+hasDescendant(Matcher),
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+ functionDecl(hasDescendant(Matcher)));
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -211,10 +211,19 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto PreviousTraversalKind = Finder->getASTContext().GetTraversalKind();
+  auto OptTK = Implementation->TraversalKind();
+  if (OptTK)
+Finder->getASTContext().SetTraversalKind(*OptTK);
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  if (RestrictKind.isBaseOf(NodeKind) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
+Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
 return true;
   }
+  Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
   // Delete all bindings when a matcher does not match.
   // This prevents unexpected exposure of bound nodes in unmatches
   // branches of the match tree.
@@ -225,8 +234,11 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -59,10 +59,12 @@
   DynTypedMatcher::MatcherIDType MatcherID;
   ast_type_traits::DynTypedNode Node;
   BoundNodesTreeBuilder 

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-16 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added a comment.

Thanks for this -- it looks like really interesting functionality! I've mostly 
found nits thus far, but did have a question about clang-query support for it.




Comment at: include/clang/AST/ASTContext.h:562-563
 public:
+  ast_type_traits::TraversalKind GetTraversalKind() const { return Traversal; }
+  void SetTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
+

This doesn't match our coding guidelines. Should be `getTraversalKind()`, etc. 
Same below.



Comment at: include/clang/AST/ASTContext.h:565-568
+  const Expr *TraverseIgnored(const Expr *E);
+  Expr *TraverseIgnored(Expr *E);
+  ast_type_traits::DynTypedNode
+  TraverseIgnored(const ast_type_traits::DynTypedNode &N);

Is there a reason we don't want these functions to be marked `const`?



Comment at: include/clang/AST/ASTNodeTraverser.h:80
 
+  void SetTraversalKind(ast_type_traits::TraversalKind TK) { Traversal = TK; }
+

`setTraversalKind()`



Comment at: include/clang/AST/ASTNodeTraverser.h:105
 
-  void Visit(const Stmt *S, StringRef Label = {}) {
+  void Visit(const Stmt *S_, StringRef Label = {}) {
 getNodeDelegate().AddChild(Label, [=] {

Let's not make underscores important like this -- how about `Node` or something 
generic instead?



Comment at: include/clang/AST/ASTNodeTraverser.h:113-114
+  break;
+case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses:
+  S = E->IgnoreParenImpCasts();
+  break;

What an unfortunate name for this. `IgnoreParenImpCasts()` ignores parens, 
implicit casts, full expressions, temporary materialization, and non-type 
template substitutions, and those extra nodes have surprised people in the past.

Not much to be done about it here, just loudly lamenting the existing name of 
the trait.



Comment at: include/clang/ASTMatchers/ASTMatchers.h:701
 
+/// Causes all nested matchers to be matched with the specified traversal kind
+///

Missing a full stop at the end of the comment.



Comment at: include/clang/ASTMatchers/ASTMatchers.h:716
+/// \endcode
+/// matches the return statement with "ret" bound to "a".
+template 

Copy pasta?



Comment at: include/clang/ASTMatchers/ASTMatchers.h:718
+template 
+internal::Matcher traverse(ast_type_traits::TraversalKind TK,
+  const internal::Matcher &InnerMatcher) {

Is this an API we should be exposing to clang-query as well? Will those users 
be able to use a string literal for the traversal kind, like they already do 
for attribute kinds (etc)?



Comment at: include/clang/ASTMatchers/ASTMatchersInternal.h:286
+
+  virtual llvm::Optional TraversalKind() const 
{
+return {};

`traversalKind()`



Comment at: include/clang/ASTMatchers/ASTMatchersInternal.h:287
+  virtual llvm::Optional TraversalKind() const 
{
+return {};
+  }

`return llvm::None;`



Comment at: lib/AST/ASTContext.cpp:120
+ASTContext::TraverseIgnored(const ast_type_traits::DynTypedNode &N) {
+  if (auto E = N.get()) {
+return ast_type_traits::DynTypedNode::create(*TraverseIgnored(E));

`auto *`



Comment at: lib/AST/ASTContext.cpp:10358
   bool TraverseStmt(Stmt *StmtNode) {
+auto FilteredNode = StmtNode;
+if (auto *ExprNode = dyn_cast_or_null(FilteredNode))

`Stmt *`



Comment at: lib/ASTMatchers/ASTMatchFinder.cpp:148
 Stmt *StmtToTraverse = StmtNode;
+if (Expr *ExprNode = dyn_cast_or_null(StmtNode))
+  StmtToTraverse = Finder->getASTContext().TraverseIgnored(ExprNode);

`auto *`



Comment at: lib/ASTMatchers/ASTMatchersInternal.cpp:214-215
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto PreviousTraversalKind = Finder->getASTContext().GetTraversalKind();
+  auto OptTK = Implementation->TraversalKind();
+  if (OptTK)

Please do not use `auto` here.



Comment at: lib/ASTMatchers/ASTMatchersInternal.cpp:218-219
+Finder->getASTContext().SetTraversalKind(*OptTK);
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+

Or here...



Comment at: lib/ASTMatchers/ASTMatchersInternal.cpp:237-238
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-12 Thread Stephen Kelly via Phabricator via cfe-commits
steveire updated this revision to Diff 199185.
steveire added a comment.

Format


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/ASTNodeTraverser.h
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/AST/ASTContext.cpp
  lib/ASTMatchers/ASTMatchFinder.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1510,6 +1510,72 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(
+  notMatches(VarDeclCode, traverse(ast_type_traits::TK_AsIs, Matcher)));
+  EXPECT_TRUE(
+  matches(VarDeclCode,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   Matcher)));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+  Code,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   callExpr(has(callExpr(traverse(
+   ast_type_traits::TK_AsIs,
+   callExpr(has(implicitCastExpr(has(floatLiteral(;
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(matches(
+  Code, functionDecl(anyOf(
+hasDescendant(Matcher),
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+ functionDecl(hasDescendant(Matcher)));
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -211,10 +211,19 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto PreviousTraversalKind = Finder->getASTContext().GetTraversalKind();
+  auto OptTK = Implementation->TraversalKind();
+  if (OptTK)
+Finder->getASTContext().SetTraversalKind(*OptTK);
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  if (RestrictKind.isBaseOf(NodeKind) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
+Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
 return true;
   }
+  Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
   // Delete all bindings when a matcher does not match.
   // This prevents unexpected exposure of bound nodes in unmatches
   // branches of the match tree.
@@ -225,8 +234,11 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -59,10 +59,12 @@
   DynTypedMatcher::MatcherIDType MatcherID;
   ast_type_traits::DynTypedNode Node;
   BoundNodesTreeBuilder BoundNodes;
+  ast_type_traits::TraversalKin

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-12 Thread Stephen Kelly via Phabricator via cfe-commits
steveire updated this revision to Diff 199181.
steveire added a comment.

Format


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/ASTNodeTraverser.h
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/AST/ASTContext.cpp
  lib/ASTMatchers/ASTMatchFinder.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1510,6 +1510,72 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(
+  notMatches(VarDeclCode, traverse(ast_type_traits::TK_AsIs, Matcher)));
+  EXPECT_TRUE(
+  matches(VarDeclCode,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   Matcher)));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+  Code,
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+   callExpr(has(callExpr(traverse(
+   ast_type_traits::TK_AsIs,
+   callExpr(has(implicitCastExpr(has(floatLiteral(;
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(matches(
+  Code, functionDecl(anyOf(
+hasDescendant(Matcher),
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+ functionDecl(hasDescendant(Matcher)));
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -211,10 +211,17 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto PreviousTraversalKind = Finder->getASTContext().GetTraversalKind();
+  Finder->getASTContext().SetTraversalKind(Implementation->TraversalKind());
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  if (RestrictKind.isBaseOf(NodeKind) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
+Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
 return true;
   }
+  Finder->getASTContext().SetTraversalKind(PreviousTraversalKind);
   // Delete all bindings when a matcher does not match.
   // This prevents unexpected exposure of bound nodes in unmatches
   // branches of the match tree.
@@ -225,8 +232,11 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -59,10 +59,12 @@
   DynTypedMatcher::MatcherIDType MatcherID;
   ast_type_traits::DynTypedNode Node;
   BoundNodesTreeBuilder BoundNodes;
+  ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs;

[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-12 Thread Stephen Kelly via Phabricator via cfe-commits
steveire added a comment.

@klimek This includes a test for the memoization case you were interested in at 
EuroLLVM.

In this iteration of the API, the traversal kind is changed by using a new 
`traverse` matcher, which gives the user control over whether 
invisible/implicit nodes are skipped or not.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61837/new/

https://reviews.llvm.org/D61837



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61837: Make it possible control matcher traversal kind with ASTContext

2019-05-12 Thread Stephen Kelly via Phabricator via cfe-commits
steveire created this revision.
steveire added reviewers: klimek, aaron.ballman.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This will eventually allow traversal of an AST while ignoring invisible
AST nodes.  Currently it depends on the available enum values for
TraversalKinds.  That can be extended to ignore all invisible nodes in
the future.


Repository:
  rC Clang

https://reviews.llvm.org/D61837

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/ASTNodeTraverser.h
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/AST/ASTContext.cpp
  lib/ASTMatchers/ASTMatchFinder.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1510,6 +1510,96 @@
   notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr();
 }
 
+TEST(Traversal, traverseMatcher) {
+
+  StringRef VarDeclCode = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+)cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  EXPECT_TRUE(notMatches(
+VarDeclCode,
+traverse(ast_type_traits::TK_AsIs,
+  Matcher
+  )
+  ));
+  EXPECT_TRUE(matches(
+VarDeclCode,
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+  Matcher
+  )
+  ));
+}
+
+TEST(Traversal, traverseMatcherNesting) {
+
+  StringRef Code = R"cpp(
+float bar(int i)
+{
+  return i;
+}
+
+void foo()
+{
+  bar(bar(3.0));
+}
+)cpp";
+
+  EXPECT_TRUE(matches(
+Code,
+traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+  callExpr(has(
+callExpr(
+  traverse(ast_type_traits::TK_AsIs,
+callExpr(has(implicitCastExpr(has(floatLiteral()
+)
+  )
+))
+  )
+  ));
+}
+
+TEST(Traversal, traverseMatcherThroughMemoization) {
+
+  StringRef Code = R"cpp(
+void foo()
+{
+  int i = 3.0;
+}
+  )cpp";
+
+  auto Matcher = varDecl(hasInitializer(floatLiteral()));
+
+  // Matchers such as hasDescendant memoize their result regarding AST
+  // nodes. In the matcher below, the first use of hasDescendant(Matcher)
+  // fails, and the use of it inside the traverse() matcher should pass
+  // causing the overall matcher to be a true match.
+  // This test verifies that the first false result is not re-used, which
+  // would cause the overall matcher to be incorrectly false.
+
+  EXPECT_TRUE(
+matches(
+Code,
+functionDecl(anyOf(
+  hasDescendant(
+Matcher
+),
+  traverse(ast_type_traits::TK_IgnoreImplicitCastsAndParentheses,
+functionDecl(
+  hasDescendant(
+Matcher
+)
+  )
+)
+  ))
+)
+  );
+}
+
 TEST(IgnoringImpCasts, MatchesImpCasts) {
   // This test checks that ignoringImpCasts matches when implicit casts are
   // present and its inner matcher alone does not match.
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -211,8 +211,11 @@
 bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
   ASTMatchFinder *Finder,
   BoundNodesTreeBuilder *Builder) const {
-  if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
-  Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  if (RestrictKind.isBaseOf(NodeKind) &&
+  Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
@@ -225,8 +228,11 @@
 bool DynTypedMatcher::matchesNoKindCheck(
 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
 BoundNodesTreeBuilder *Builder) const {
-  assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
-  if (Implementation->dynMatches(DynNode, Finder, Builder)) {
+  auto N = Finder->getASTContext().TraverseIgnored(DynNode);
+  auto NodeKind = N.getNodeKind();
+
+  assert(RestrictKind.isBaseOf(NodeKind));
+  if (Implementation->dynMatches(N, Finder, Builder)) {
 return true;
   }
   // Delete all bindings when a matcher does not match.
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -59,10 +59,11 @@
   DynTypedMatcher::MatcherIDType MatcherID;
   ast_type_traits::DynTypedNode Node;
   BoundNodesTreeBuilder BoundNodes;
+  ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs;
 
   bool operator<(const MatchKey &Other) const {
-return