forked from OSchip/llvm-project
[AST] Treat semantic form of InitListExpr as implicit code in traversals
Summary: In particular, do not traverse the semantic form if shouldVisitImplicitCode() returns false. This simplifies the common case of traversals, avoiding the need to worry about some expressions being traversed twice. No tests break after the change, the change would allow to simplify at least one of the usages, i.e. r366070 which had to handle this in clangd. Reviewers: gribozavr Reviewed By: gribozavr Subscribers: kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D64762 llvm-svn: 366672
This commit is contained in:
parent
3a52e50d73
commit
0a42fe70a5
|
@ -2308,19 +2308,30 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is called once for each pair of syntactic and semantic
|
// If shouldVisitImplicitCode() returns false, this method traverses only the
|
||||||
// InitListExpr, and it traverses the subtrees defined by the two forms. This
|
// syntactic form of InitListExpr.
|
||||||
// may cause some of the children to be visited twice, if they appear both in
|
// If shouldVisitImplicitCode() return true, this method is called once for
|
||||||
// the syntactic and the semantic form.
|
// each pair of syntactic and semantic InitListExpr, and it traverses the
|
||||||
|
// subtrees defined by the two forms. This may cause some of the children to be
|
||||||
|
// visited twice, if they appear both in the syntactic and the semantic form.
|
||||||
//
|
//
|
||||||
// There is no guarantee about which form \p S takes when this method is called.
|
// There is no guarantee about which form \p S takes when this method is called.
|
||||||
template <typename Derived>
|
template <typename Derived>
|
||||||
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
|
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
|
||||||
InitListExpr *S, DataRecursionQueue *Queue) {
|
InitListExpr *S, DataRecursionQueue *Queue) {
|
||||||
|
if (S->isSemanticForm() && S->isSyntacticForm()) {
|
||||||
|
// `S` does not have alternative forms, traverse only once.
|
||||||
|
TRY_TO(TraverseSynOrSemInitListExpr(S, Queue));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
TRY_TO(TraverseSynOrSemInitListExpr(
|
TRY_TO(TraverseSynOrSemInitListExpr(
|
||||||
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
|
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
|
||||||
|
if (getDerived().shouldVisitImplicitCode()) {
|
||||||
|
// Only visit the semantic form if the clients are interested in implicit
|
||||||
|
// compiler-generated.
|
||||||
TRY_TO(TraverseSynOrSemInitListExpr(
|
TRY_TO(TraverseSynOrSemInitListExpr(
|
||||||
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
|
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,22 @@ namespace {
|
||||||
class InitListExprPreOrderVisitor
|
class InitListExprPreOrderVisitor
|
||||||
: public ExpectedLocationVisitor<InitListExprPreOrderVisitor> {
|
: public ExpectedLocationVisitor<InitListExprPreOrderVisitor> {
|
||||||
public:
|
public:
|
||||||
|
InitListExprPreOrderVisitor(bool VisitImplicitCode)
|
||||||
|
: VisitImplicitCode(VisitImplicitCode) {}
|
||||||
|
|
||||||
|
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
|
||||||
|
|
||||||
bool VisitInitListExpr(InitListExpr *ILE) {
|
bool VisitInitListExpr(InitListExpr *ILE) {
|
||||||
Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc());
|
Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getBeginLoc());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool VisitImplicitCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) {
|
TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) {
|
||||||
InitListExprPreOrderVisitor Visitor;
|
InitListExprPreOrderVisitor Visitor(/*VisitImplicitCode=*/true);
|
||||||
Visitor.ExpectMatch("syntactic", 2, 21);
|
Visitor.ExpectMatch("syntactic", 2, 21);
|
||||||
Visitor.ExpectMatch("semantic", 2, 21);
|
Visitor.ExpectMatch("semantic", 2, 21);
|
||||||
EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
|
EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
|
||||||
|
@ -32,4 +40,13 @@ TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) {
|
||||||
InitListExprPreOrderVisitor::Lang_C));
|
InitListExprPreOrderVisitor::Lang_C));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RecursiveASTVisitor, InitListExprVisitedOnceWhenNoImplicit) {
|
||||||
|
InitListExprPreOrderVisitor Visitor(/*VisitImplicitCode=*/false);
|
||||||
|
Visitor.ExpectMatch("syntactic", 2, 21);
|
||||||
|
Visitor.DisallowMatch("semantic", 2, 21);
|
||||||
|
EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
|
||||||
|
"static struct S s = {.x = 0};\n",
|
||||||
|
InitListExprPreOrderVisitor::Lang_C));
|
||||||
|
}
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
Loading…
Reference in New Issue