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 @@ -37,6 +37,9 @@ // Synthesis of Trees /// Creates the concrete syntax node according to the specified `NodeKind` `K`. /// Returns it as a pointer to the base class `Tree`. +/// +/// EXPECT: Nodes in `Children` are all synthesized, i.e. not backed by source +/// code. syntax::Tree * createTree(syntax::Arena &A, std::vector> Children, 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 @@ -8,6 +8,7 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Tooling/Syntax/BuildTree.h" #include "clang/Tooling/Syntax/Tree.h" +#include using namespace clang; @@ -184,12 +185,48 @@ } llvm_unreachable("unknown node kind"); } + +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 (!Child->canModify()) + return false; + + return true; +} + +bool areAllSynthesized(const syntax::Node *N) { + if (const auto *L = dyn_cast(N)) + return !L->isOriginal(); + + const auto *T = cast(N); + + if (T->isOriginal()) + return false; + for (const auto *Child = T->getFirstChild(); Child; + Child = Child->getNextSibling()) + if (Child->isOriginal()) + return false; + + return true; +} } // namespace syntax::Tree *clang::syntax::createTree( syntax::Arena &A, std::vector> Children, syntax::NodeKind K) { + if (std::all_of(Children.begin(), Children.end(), + [](auto p) { return areAllSynthesized(p.first); })) + return nullptr; + auto *T = allocateTree(A, K); FactoryImpl::setCanModify(T); for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend();