r312633 - [AST] Traverse CXXOperatorCallExpr in LexicallyOrderedRecursiveASTVisitor

Johannes Altmanninger via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 6 06:12:11 PDT 2017


Author: krobelus
Date: Wed Sep  6 06:12:11 2017
New Revision: 312633

URL: http://llvm.org/viewvc/llvm-project?rev=312633&view=rev
Log:
[AST] Traverse CXXOperatorCallExpr in LexicallyOrderedRecursiveASTVisitor

Summary:
This affects overloaded operators, which are represented by a
CXXOperatorCallExpr whose first child is always a DeclRefExpr referring to the
operator. For infix, postfix and call operators we want the first argument
to be traversed before the operator.

Reviewers: arphaman

Subscribers: klimek, cfe-commits

Differential Revision: https://reviews.llvm.org/D37200

Modified:
    cfe/trunk/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp

Modified: cfe/trunk/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h?rev=312633&r1=312632&r2=312633&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h Wed Sep  6 06:12:11 2017
@@ -113,6 +113,33 @@ public:
 
   bool shouldTraverseTemplateArgumentsBeforeDecl() const { return true; }
 
+  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
+
+  SmallVector<Stmt *, 8> getStmtChildren(CXXOperatorCallExpr *CE) {
+    SmallVector<Stmt *, 8> 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

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=312633&r1=312632&r2=312633&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed Sep  6 06:12:11 2017
@@ -315,6 +315,8 @@ public:
 
 // ---- Methods on Stmts ----
 
+  Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
+
 private:
   template<typename T, typename U>
   struct has_same_member_pointer_type : std::false_type {};
@@ -2084,7 +2086,7 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
       TRY_TO(WalkUpFrom##STMT(S));                                             \
     { CODE; }                                                                  \
     if (ShouldVisitChildren) {                                                 \
-      for (Stmt *SubStmt : S->children()) {                                    \
+      for (Stmt * SubStmt : getDerived().getStmtChildren(S)) {                 \
         TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt);                              \
       }                                                                        \
     }                                                                          \

Modified: cfe/trunk/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp?rev=312633&r1=312632&r2=312633&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp Wed Sep  6 06:12:11 2017
@@ -21,9 +21,10 @@ class LexicallyOrderedDeclVisitor
     : public LexicallyOrderedRecursiveASTVisitor<LexicallyOrderedDeclVisitor> {
 public:
   LexicallyOrderedDeclVisitor(DummyMatchVisitor &Matcher,
-                              const SourceManager &SM, bool EmitIndices)
+                              const SourceManager &SM, bool EmitDeclIndices,
+                              bool EmitStmtIndices)
       : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher),
-        EmitIndices(EmitIndices) {}
+        EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
 
   bool TraverseDecl(Decl *D) {
     TraversalStack.push_back(D);
@@ -32,31 +33,43 @@ public:
     return true;
   }
 
+  bool TraverseStmt(Stmt *S);
+
   bool VisitNamedDecl(const NamedDecl *D);
+  bool VisitDeclRefExpr(const DeclRefExpr *D);
 
 private:
   DummyMatchVisitor &Matcher;
-  bool EmitIndices;
+  bool EmitDeclIndices, EmitStmtIndices;
   unsigned Index = 0;
   llvm::SmallVector<Decl *, 8> TraversalStack;
 };
 
 class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
-  bool EmitIndices;
+  bool EmitDeclIndices, EmitStmtIndices;
 
 public:
-  DummyMatchVisitor(bool EmitIndices = false) : EmitIndices(EmitIndices) {}
+  DummyMatchVisitor(bool EmitDeclIndices = false, bool EmitStmtIndices = false)
+      : EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
   bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
     const ASTContext &Context = TU->getASTContext();
     const SourceManager &SM = Context.getSourceManager();
-    LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitIndices);
+    LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitDeclIndices,
+                                           EmitStmtIndices);
     SubVisitor.TraverseDecl(TU);
     return false;
   }
 
-  void match(StringRef Path, const Decl *D) { Match(Path, D->getLocStart()); }
+  template <class T> void match(StringRef Path, const T *D) {
+    Match(Path, D->getLocStart());
+  }
 };
 
+bool LexicallyOrderedDeclVisitor::TraverseStmt(Stmt *S) {
+  Matcher.match("overridden TraverseStmt", S);
+  return LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
+}
+
 bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
   std::string Path;
   llvm::raw_string_ostream OS(Path);
@@ -73,7 +86,16 @@ bool LexicallyOrderedDeclVisitor::VisitN
     if (isa<DeclContext>(D) or isa<TemplateDecl>(D))
       OS << "/";
   }
-  if (EmitIndices)
+  if (EmitDeclIndices)
+    OS << "@" << Index++;
+  Matcher.match(OS.str(), D);
+  return true;
+}
+
+bool LexicallyOrderedDeclVisitor::VisitDeclRefExpr(const DeclRefExpr *D) {
+  std::string Name = D->getFoundDecl()->getNameAsString();
+  llvm::raw_string_ostream OS(Name);
+  if (EmitStmtIndices)
     OS << "@" << Index++;
   Matcher.match(OS.str(), D);
   return true;
@@ -160,4 +182,46 @@ template <class U, class = void> class C
   EXPECT_TRUE(Visitor.runOver(Source));
 }
 
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitCXXOperatorCallExpr) {
+  StringRef Source = R"(
+struct S {
+  S &operator+(S&);
+  S *operator->();
+  S &operator++();
+  S operator++(int);
+  void operator()(int, int);
+  void operator[](int);
+  void f();
+};
+S a, b, c;
+
+void test() {
+  a = b + c;
+  a->f();
+  a(1, 2);
+  b[0];
+  ++a;
+  b++;
+}
+)";
+  DummyMatchVisitor Visitor(/*EmitDeclIndices=*/false,
+                            /*EmitStmtIndices=*/true);
+  // There are two overloaded operators that start at this point
+  // This makes sure they are both traversed using the overridden
+  // TraverseStmt, as the traversal is implemented by us for
+  // CXXOperatorCallExpr.
+  Visitor.ExpectMatch("overridden TraverseStmt", 14, 3, 2);
+  Visitor.ExpectMatch("a at 0", 14, 3);
+  Visitor.ExpectMatch("operator=@1", 14, 5);
+  Visitor.ExpectMatch("b at 2", 14, 7);
+  Visitor.ExpectMatch("operator+ at 3", 14, 9);
+  Visitor.ExpectMatch("c at 4", 14, 11);
+  Visitor.ExpectMatch("operator->@6", 15, 4);
+  Visitor.ExpectMatch("operator()@8", 16, 4);
+  Visitor.ExpectMatch("operator[]@10", 17, 4);
+  Visitor.ExpectMatch("operator++ at 11", 18, 3);
+  Visitor.ExpectMatch("operator++ at 14", 19, 4);
+  EXPECT_TRUE(Visitor.runOver(Source));
+}
+
 } // end anonymous namespace




More information about the cfe-commits mailing list