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