diff --git a/clang/include/clang/Tooling/Syntax/BuildTree.h b/clang/include/clang/Tooling/Syntax/BuildTree.h --- a/clang/include/clang/Tooling/Syntax/BuildTree.h +++ b/clang/include/clang/Tooling/Syntax/BuildTree.h @@ -45,17 +45,13 @@ // Synthesis of Syntax Nodes syntax::EmptyStatement *createEmptyStatement(syntax::Arena &A); -/// Creates a completely independent copy of `N` (a deep copy). +/// Creates a completely independent copy of `N` with its macros expanded. /// /// The copy is: /// * Detached, i.e. `Parent == NextSibling == nullptr` and /// `Role == Detached`. /// * Synthesized, i.e. `Original == false`. -/// -/// `N` might be backed by source code but if any descendants of `N` are -/// unmodifiable returns `nullptr`. -syntax::Node *deepCopy(syntax::Arena &A, const syntax::Node *N); - +syntax::Node *deepCopyExpandingMacros(syntax::Arena &A, const syntax::Node *N); } // namespace syntax } // namespace clang #endif diff --git a/clang/lib/Tooling/Syntax/Synthesis.cpp b/clang/lib/Tooling/Syntax/Synthesis.cpp --- a/clang/lib/Tooling/Syntax/Synthesis.cpp +++ b/clang/lib/Tooling/Syntax/Synthesis.cpp @@ -201,25 +201,11 @@ return T; } -namespace { -bool canModifyAllDescendants(const syntax::Node *N) { - if (const auto *L = dyn_cast(N)) - return L->canModify(); - - const auto *T = cast(N); - - if (!T->canModify()) - return false; - for (const auto *Child = T->getFirstChild(); Child; - Child = Child->getNextSibling()) - if (!canModifyAllDescendants(Child)) - return false; - - return true; -} - -syntax::Node *deepCopyImpl(syntax::Arena &A, const syntax::Node *N) { +syntax::Node *clang::syntax::deepCopyExpandingMacros(syntax::Arena &A, + const syntax::Node *N) { if (const auto *L = dyn_cast(N)) + // `L->getToken()` gives us the expanded token, thus we implicitly expand + // any macros here. return createLeaf(A, L->getToken()->kind(), L->getToken()->text(A.getSourceManager())); @@ -227,18 +213,10 @@ std::vector> Children; for (const auto *Child = T->getFirstChild(); Child; Child = Child->getNextSibling()) - Children.push_back({deepCopyImpl(A, Child), Child->getRole()}); + Children.push_back({deepCopyExpandingMacros(A, Child), Child->getRole()}); return createTree(A, Children, N->getKind()); } -} // namespace - -syntax::Node *clang::syntax::deepCopy(syntax::Arena &A, const Node *N) { - if (!canModifyAllDescendants(N)) - return nullptr; - - return deepCopyImpl(A, N); -} syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) { return cast( diff --git a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp --- a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp +++ b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp @@ -173,7 +173,7 @@ {LeafSemiColon, NodeRole::Unknown}}, NodeKind::ContinueStatement); - auto *Copy = deepCopy(*Arena, StatementContinue); + auto *Copy = deepCopyExpandingMacros(*Arena, StatementContinue); EXPECT_TRUE( treeDumpEqual(Copy, StatementContinue->dump(Arena->getSourceManager()))); // FIXME: Test that copy is independent of original, once the Mutations API is @@ -183,7 +183,7 @@ TEST_P(SynthesisTest, DeepCopy_Original) { auto *OriginalTree = buildTree("int a;", GetParam()); - auto *Copy = deepCopy(*Arena, OriginalTree); + auto *Copy = deepCopyExpandingMacros(*Arena, OriginalTree); EXPECT_TRUE(treeDumpEqual(Copy, R"txt( TranslationUnit Detached synthesized `-SimpleDeclaration synthesized @@ -197,7 +197,7 @@ TEST_P(SynthesisTest, DeepCopy_Child) { auto *OriginalTree = buildTree("int a;", GetParam()); - auto *Copy = deepCopy(*Arena, OriginalTree->getFirstChild()); + auto *Copy = deepCopyExpandingMacros(*Arena, OriginalTree->getFirstChild()); EXPECT_TRUE(treeDumpEqual(Copy, R"txt( SimpleDeclaration Detached synthesized |-'int' synthesized @@ -216,8 +216,41 @@ })cpp", GetParam()); - auto *Copy = deepCopy(*Arena, OriginalTree); - EXPECT_TRUE(Copy == nullptr); + auto *Copy = deepCopyExpandingMacros(*Arena, OriginalTree); + + // The syntax tree stores already expanded Tokens, we can only see whether the + // macro was expanded when computing replacements. The dump does show that + // nodes in the copy are `modifiable`. + EXPECT_TRUE(treeDumpEqual(Copy, R"txt( +TranslationUnit Detached synthesized +`-SimpleDeclaration synthesized + |-'void' synthesized + |-SimpleDeclarator Declarator synthesized + | |-'test' synthesized + | `-ParametersAndQualifiers synthesized + | |-'(' OpenParen synthesized + | `-')' CloseParen synthesized + `-CompoundStatement synthesized + |-'{' OpenParen synthesized + |-IfStatement Statement synthesized + | |-'if' IntroducerKeyword synthesized + | |-'(' synthesized + | |-BinaryOperatorExpression synthesized + | | |-IntegerLiteralExpression LeftHandSide synthesized + | | | `-'1' LiteralToken synthesized + | | |-'+' OperatorToken synthesized + | | `-IntegerLiteralExpression RightHandSide synthesized + | | `-'1' LiteralToken synthesized + | |-')' synthesized + | |-CompoundStatement ThenStatement synthesized + | | |-'{' OpenParen synthesized + | | `-'}' CloseParen synthesized + | |-'else' ElseKeyword synthesized + | `-CompoundStatement ElseStatement synthesized + | |-'{' OpenParen synthesized + | `-'}' CloseParen synthesized + `-'}' CloseParen synthesized + )txt")); } TEST_P(SynthesisTest, Statement_EmptyStatement) { diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -22,8 +22,8 @@ std::vector> ChildrenWithRoles; ChildrenWithRoles.reserve(Children.size()); for (const auto *Child : Children) { - ChildrenWithRoles.push_back( - std::make_pair(deepCopy(*Arena, Child), NodeRole::Unknown)); + ChildrenWithRoles.push_back(std::make_pair( + deepCopyExpandingMacros(*Arena, Child), NodeRole::Unknown)); } return clang::syntax::createTree(*Arena, ChildrenWithRoles, NodeKind::UnknownExpression);