Index: include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h =================================================================== --- include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h +++ include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h @@ -60,10 +60,20 @@ class LexicallyOrderedRecursiveASTVisitor : public RecursiveASTVisitor { using BaseType = RecursiveASTVisitor; + using typename BaseType::DataRecursionQueue; + + using RecursiveASTVisitor = BaseType; + template + struct has_same_member_pointer_type : std::false_type {}; + template + struct has_same_member_pointer_type + : std::true_type {}; public: LexicallyOrderedRecursiveASTVisitor(const SourceManager &SM) : SM(SM) {} + Derived &getDerived() { return *static_cast(this); } + bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { // Objective-C @implementation declarations should not trigger early exit // until the additional decls are traversed as their children are not @@ -126,6 +136,36 @@ DEF_TRAVERSE_TEMPLATE_DECL(Function) #undef DEF_TRAVERSE_TEMPLATE_DECL + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE, + DataRecursionQueue *Queue = nullptr) { + SmallVector Children(CE->children()); + bool Swap = false; + if (CE->isInfixBinaryOp()) + Swap = true; + // Switch the operator and the first operand for all infix and postfix + // operations. + switch (CE->getOperator()) { + default: + break; + case OO_Arrow: + case OO_Call: + case OO_Subscript: + Swap = true; + break; + case OO_PlusPlus: + case OO_MinusMinus: + auto Offset = [&](Stmt *S) { return SM.getFileOffset(S->getLocStart()); }; + Swap = Offset(Children[0]) > Offset(Children[1]); + break; + } + if (Swap && Children.size() > 1) + std::swap(Children[0], Children[1]); + for (Stmt *SubStmt : Children) + if (!TRAVERSE_STMT_BASE(Stmt, Stmt, SubStmt, Queue)) + return false; + return true; + } + 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 @@ -3209,7 +3209,6 @@ #undef DEF_TRAVERSE_STMT #undef TRAVERSE_STMT -#undef TRAVERSE_STMT_BASE #undef TRY_TO Index: unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp =================================================================== --- unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp +++ unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp @@ -21,9 +21,10 @@ : public LexicallyOrderedRecursiveASTVisitor { 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); @@ -33,28 +34,33 @@ } bool VisitNamedDecl(const NamedDecl *D); + bool VisitDeclRefExpr(const DeclRefExpr *D); private: DummyMatchVisitor &Matcher; - bool EmitIndices; + bool EmitDeclIndices, EmitStmtIndices; unsigned Index = 0; llvm::SmallVector TraversalStack; }; class DummyMatchVisitor : public ExpectedLocationVisitor { - 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 void match(StringRef Path, const T *D) { + Match(Path, D->getLocStart()); + } }; bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) { @@ -73,7 +79,16 @@ if (isa(D) or isa(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; @@ -151,7 +166,7 @@ template T f(); template class Class {}; )"; - DummyMatchVisitor Visitor(/*EmitIndices=*/true); + DummyMatchVisitor Visitor(/*EmitDeclIndices=*/true); Visitor.ExpectMatch("/f/T@0", 2, 11); Visitor.ExpectMatch("/f/f/@1", 2, 20); Visitor.ExpectMatch("/Class/U@2", 3, 11); @@ -160,4 +175,41 @@ 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); + Visitor.ExpectMatch("a@0", 14, 3); + Visitor.ExpectMatch("operator=@1", 14, 5); + Visitor.ExpectMatch("b@2", 14, 7); + Visitor.ExpectMatch("operator+@3", 14, 9); + Visitor.ExpectMatch("c@4", 14, 11); + Visitor.ExpectMatch("operator->@6", 15, 4); + Visitor.ExpectMatch("operator()@8", 16, 4); + Visitor.ExpectMatch("operator[]@10", 17, 4); + Visitor.ExpectMatch("operator++@11", 18, 3); + Visitor.ExpectMatch("operator++@14", 19, 4); + EXPECT_TRUE(Visitor.runOver(Source)); +} + } // end anonymous namespace