[PATCH] D37663: [AST] Make RecursiveASTVisitor visit CXXOperatorCallExpr in source order

2017-09-13 Thread Johannes Altmanninger via Phabricator via cfe-commits
johannes added inline comments.



Comment at: include/clang/AST/RecursiveASTVisitor.h:327
+
+  SmallVector getStmtChildren(CXXOperatorCallExpr *CE) {
+SmallVector Children(CE->children());

rsmith wrote:
> The copy here is more expensive than I'd like. Instead of returning a list of 
> children, please make this function *traverse* the children (which is what 
> its one and only caller is going to do anyway) to avoid the copy.
I wasn't sure whether there is a way to do this in a function without writing a 
custom iterator that checks whether it should be swapped; I used a different 
approach.



Comment at: include/clang/AST/RecursiveASTVisitor.h:334
+case OO_Arrow:
+case OO_Call:
+case OO_Subscript:

rsmith wrote:
> johannes wrote:
> > klimek wrote:
> > > Why do we need to swap for calls?
> > The idea is that the opening parenthesis/bracket  comes after the caller, 
> > for example in this call with two arguments.
> > 
> > ```
> > `-CXXOperatorCallExpr
> >   |-ImplicitCastExpr
> >   | `-DeclRefExpr operator()
> >   |-DeclRefExpr caller
> >   |-IntegerLiteral
> >   `-IntegerLiteral
> > ```
> > 
> >  Of course we fail to capture the fact that there is also a closing 
> > parenthesis or bracket. So this is no perfect solution.
> > Of course we fail to capture the fact that there is also a closing 
> > parenthesis or bracket.
> 
> One way we could handle this would be to effectively order by the start 
> location for preorder traversal, and by the end location for postorder 
> traversal. So for a case like your `caller(1,2)`, we would visit 
> `CXXOperatorCallExpr`, `caller`, `operator()`, `1`, then `2` when doing 
> preorder visitation, and `caller`, `1`, `2`, `operator()`, then 
> `CXXOperatorCallExpr` when doing postorder visitation (because the notional 
> source location for the `operator()` invocation extends across both `1` and 
> `2` subexpressions).
> 
> But I think it's probably not worthwhile to go to this level of detail, and 
> treating the `(` as the location of the `operator()` call and ignoring the 
> `)` seems like a reasonable approach to me.
Yeah, we can do that if someone needs it.

Another way would be to model the operator as parent of the operands, although 
I assume that this would not compose well.
I don't expect it to be feasible but I imagine CXXOperatorCallExpr could also 
inherit from DeclRefExpr.


https://reviews.llvm.org/D37663



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


[PATCH] D37663: [AST] Make RecursiveASTVisitor visit CXXOperatorCallExpr in source order

2017-09-13 Thread Johannes Altmanninger via Phabricator via cfe-commits
johannes updated this revision to Diff 115018.
johannes added a comment.

use CXXOperatorCallExpr::isPrefixOp() to determine whether it's infix or postfix
directly traverse statement children instead of copying


https://reviews.llvm.org/D37663

Files:
  include/clang/AST/ExprCXX.h
  include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
  include/clang/AST/RecursiveASTVisitor.h
  lib/AST/ExprCXX.cpp

Index: lib/AST/ExprCXX.cpp
===
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -41,6 +41,12 @@
   }
 }
 
+bool CXXOperatorCallExpr::isPrefixOp() const {
+  return getNumArgs() == 1 && getOperator() != OO_Call &&
+ getOperator() != OO_Arrow;
+}
+
+
 bool CXXTypeidExpr::isPotentiallyEvaluated() const {
   if (isTypeOperand())
 return false;
Index: include/clang/AST/RecursiveASTVisitor.h
===
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -315,8 +315,6 @@
 
 //  Methods on Stmts 
 
-  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
-
 private:
   template
   struct has_same_member_pointer_type : std::false_type {};
@@ -2080,15 +2078,26 @@
   TRY_TO(WalkUpFrom##STMT(S)); \
 { CODE; }  \
 if (ShouldVisitChildren) { \
-  for (Stmt * SubStmt : getDerived().getStmtChildren(S)) { \
-TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt);  \
+  auto ChildIterator = S->child_begin();   \
+  /* Make the operator come second for infix and postfix overloaded\
+   * operators. */ \
+  if (auto *CE = dyn_cast(S)) {   \
+if (CE->isInfixBinaryOp() || !CE->isPrefixOp()) {  \
+  Stmt *Operator = *ChildIterator; \
+  TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(*++ChildIterator);   \
+  TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Operator);   \
+  ++ChildIterator; \
+}  \
+  }\
+  for (auto ChildEnd = S->child_end(); ChildIterator != ChildEnd;  \
+   ++ChildIterator) {  \
+TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(*ChildIterator);   \
   }\
 }  \
 if (!Queue && ReturnValue && getDerived().shouldTraversePostOrder())   \
   TRY_TO(WalkUpFrom##STMT(S)); \
 return ReturnValue;\
   }
-
 DEF_TRAVERSE_STMT(GCCAsmStmt, {
   TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmString());
   for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
Index: include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
===
--- include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
+++ include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
@@ -111,33 +111,6 @@
 return true;
   }
 
-  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
-
-  SmallVector getStmtChildren(CXXOperatorCallExpr *CE) {
-SmallVector Children(CE->children());
-bool Swap;
-// Switch the operator and the first operand for all infix and postfix
-// operations.
-switch (CE->getOperator()) {
-case OO_Arrow:
-case OO_Call:
-case OO_Subscript:
-  Swap = true;
-  break;
-case OO_PlusPlus:
-case OO_MinusMinus:
-  // These are postfix unless there is exactly one argument.
-  Swap = Children.size() != 2;
-  break;
-default:
-  Swap = CE->isInfixBinaryOp();
-  break;
-}
-if (Swap && Children.size() > 1)
-  std::swap(Children[0], Children[1]);
-return Children;
-  }
-
 private:
   bool TraverseAdditionalLexicallyNestedDeclarations() {
 // FIXME: Ideally the gathered declarations and the declarations in the
Index: include/clang/AST/ExprCXX.h
===
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -87,6 +87,8 @@
   /// \brief Is this written as an infix binary operator?
   bool isInfixBinaryOp() const;
 
+  bool isPrefixOp() const;
+
   /// \brief Returns the location of the operator symbol in the expression.
   ///
   /// When \c getOperator()==O

[PATCH] D37663: [AST] Make RecursiveASTVisitor visit CXXOperatorCallExpr in source order

2017-09-11 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: include/clang/AST/RecursiveASTVisitor.h:327
+
+  SmallVector getStmtChildren(CXXOperatorCallExpr *CE) {
+SmallVector Children(CE->children());

The copy here is more expensive than I'd like. Instead of returning a list of 
children, please make this function *traverse* the children (which is what its 
one and only caller is going to do anyway) to avoid the copy.



Comment at: include/clang/AST/RecursiveASTVisitor.h:334
+case OO_Arrow:
+case OO_Call:
+case OO_Subscript:

johannes wrote:
> klimek wrote:
> > Why do we need to swap for calls?
> The idea is that the opening parenthesis/bracket  comes after the caller, for 
> example in this call with two arguments.
> 
> ```
> `-CXXOperatorCallExpr
>   |-ImplicitCastExpr
>   | `-DeclRefExpr operator()
>   |-DeclRefExpr caller
>   |-IntegerLiteral
>   `-IntegerLiteral
> ```
> 
>  Of course we fail to capture the fact that there is also a closing 
> parenthesis or bracket. So this is no perfect solution.
> Of course we fail to capture the fact that there is also a closing 
> parenthesis or bracket.

One way we could handle this would be to effectively order by the start 
location for preorder traversal, and by the end location for postorder 
traversal. So for a case like your `caller(1,2)`, we would visit 
`CXXOperatorCallExpr`, `caller`, `operator()`, `1`, then `2` when doing 
preorder visitation, and `caller`, `1`, `2`, `operator()`, then 
`CXXOperatorCallExpr` when doing postorder visitation (because the notional 
source location for the `operator()` invocation extends across both `1` and `2` 
subexpressions).

But I think it's probably not worthwhile to go to this level of detail, and 
treating the `(` as the location of the `operator()` call and ignoring the `)` 
seems like a reasonable approach to me.



Comment at: include/clang/AST/RecursiveASTVisitor.h:340-341
+case OO_MinusMinus:
+  // These are postfix unless there is exactly one argument.
+  Swap = Children.size() != 2;
+  break;

This would be clearer as `Children.size() == 3`.

However, instead of changing that, please add a 
`CXXOperatorCallExpr::isPrefixOp()` function (`getNumArgs() == 1 && Op != 
OO_Call && Op != OO_Arrow`); we should visit the callee after visiting the 
first argument if and only if we have a prefix operator.


https://reviews.llvm.org/D37663



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


[PATCH] D37663: [AST] Make RecursiveASTVisitor visit CXXOperatorCallExpr in source order

2017-09-11 Thread Johannes Altmanninger via Phabricator via cfe-commits
johannes added inline comments.



Comment at: include/clang/AST/RecursiveASTVisitor.h:334
+case OO_Arrow:
+case OO_Call:
+case OO_Subscript:

klimek wrote:
> Why do we need to swap for calls?
The idea is that the opening parenthesis/bracket  comes after the caller, for 
example in this call with two arguments.

```
`-CXXOperatorCallExpr
  |-ImplicitCastExpr
  | `-DeclRefExpr operator()
  |-DeclRefExpr caller
  |-IntegerLiteral
  `-IntegerLiteral
```

 Of course we fail to capture the fact that there is also a closing parenthesis 
or bracket. So this is no perfect solution.


https://reviews.llvm.org/D37663



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


[PATCH] D37663: [AST] Make RecursiveASTVisitor visit CXXOperatorCallExpr in source order

2017-09-11 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added inline comments.



Comment at: include/clang/AST/RecursiveASTVisitor.h:334
+case OO_Arrow:
+case OO_Call:
+case OO_Subscript:

Why do we need to swap for calls?


https://reviews.llvm.org/D37663



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


[PATCH] D37663: [AST] Make RecursiveASTVisitor visit CXXOperatorCallExpr in source order

2017-09-09 Thread Johannes Altmanninger via Phabricator via cfe-commits
johannes created this revision.

This adds a special case for traversing CXXOperatorCallExpr. Its
children are traversed in the order in which they appear in the source
code, so infix and postfix operators are visited after their first
argument.

This behavior was previously only in
LexicallyOrderedRecursiveASTVisitor, moving it here could avoid bugs in
the future. It is still tested in
LexicallyOrderedRecursiveASTVisitorTest.cpp in VisitTemplateDecl.
Clients that somehow rely on the original traversal order will have to
be updated though.


https://reviews.llvm.org/D37663

Files:
  include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
  include/clang/AST/RecursiveASTVisitor.h


Index: include/clang/AST/RecursiveASTVisitor.h
===
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -315,15 +315,40 @@
 
 //  Methods on Stmts 
 
-  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
-
 private:
   template
   struct has_same_member_pointer_type : std::false_type {};
   template
   struct has_same_member_pointer_type
   : std::true_type {};
 
+  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
+
+  SmallVector getStmtChildren(CXXOperatorCallExpr *CE) {
+SmallVector Children(CE->children());
+bool Swap;
+// Swap the operator and the first operand for all infix and postfix
+// operations.
+switch (CE->getOperator()) {
+case OO_Arrow:
+case OO_Call:
+case OO_Subscript:
+  Swap = true;
+  break;
+case OO_PlusPlus:
+case OO_MinusMinus:
+  // These are postfix unless there is exactly one argument.
+  Swap = Children.size() != 2;
+  break;
+default:
+  Swap = CE->isInfixBinaryOp();
+  break;
+}
+if (Swap && Children.size() > 1)
+  std::swap(Children[0], Children[1]);
+return Children;
+  }
+
   // Traverse the given statement. If the most-derived traverse function takes 
a
   // data recursion queue, pass it on; otherwise, discard it. Note that the
   // first branch of this conditional must compile whether or not the derived
Index: include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
===
--- include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
+++ include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
@@ -111,33 +111,6 @@
 return true;
   }
 
-  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
-
-  SmallVector getStmtChildren(CXXOperatorCallExpr *CE) {
-SmallVector Children(CE->children());
-bool Swap;
-// Switch the operator and the first operand for all infix and postfix
-// operations.
-switch (CE->getOperator()) {
-case OO_Arrow:
-case OO_Call:
-case OO_Subscript:
-  Swap = true;
-  break;
-case OO_PlusPlus:
-case OO_MinusMinus:
-  // These are postfix unless there is exactly one argument.
-  Swap = Children.size() != 2;
-  break;
-default:
-  Swap = CE->isInfixBinaryOp();
-  break;
-}
-if (Swap && Children.size() > 1)
-  std::swap(Children[0], Children[1]);
-return Children;
-  }
-
 private:
   bool TraverseAdditionalLexicallyNestedDeclarations() {
 // FIXME: Ideally the gathered declarations and the declarations in the


Index: include/clang/AST/RecursiveASTVisitor.h
===
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -315,15 +315,40 @@
 
 //  Methods on Stmts 
 
-  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
-
 private:
   template
   struct has_same_member_pointer_type : std::false_type {};
   template
   struct has_same_member_pointer_type
   : std::true_type {};
 
+  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
+
+  SmallVector getStmtChildren(CXXOperatorCallExpr *CE) {
+SmallVector Children(CE->children());
+bool Swap;
+// Swap the operator and the first operand for all infix and postfix
+// operations.
+switch (CE->getOperator()) {
+case OO_Arrow:
+case OO_Call:
+case OO_Subscript:
+  Swap = true;
+  break;
+case OO_PlusPlus:
+case OO_MinusMinus:
+  // These are postfix unless there is exactly one argument.
+  Swap = Children.size() != 2;
+  break;
+default:
+  Swap = CE->isInfixBinaryOp();
+  break;
+}
+if (Swap && Children.size() > 1)
+  std::swap(Children[0], Children[1]);
+return Children;
+  }
+
   // Traverse the given statement. If the most-derived traverse function takes a
   // data recursion queue, pass it on; otherwise, discard it. Note that the
   // first branch of this conditional must compile whether or not the derived
Index: include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
==