1 //===- Synthesis.cpp ------------------------------------------*- C++ -*-=====//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "clang/Basic/TokenKinds.h"
9 #include "clang/Tooling/Syntax/BuildTree.h"
10 #include "clang/Tooling/Syntax/Tree.h"
11 
12 using namespace clang;
13 
14 /// Exposes private syntax tree APIs required to implement node synthesis.
15 /// Should not be used for anything else.
16 class clang::syntax::FactoryImpl {
17 public:
18   static void setCanModify(syntax::Node *N) { N->CanModify = true; }
19 
20   static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child,
21                                    syntax::NodeRole R) {
22     T->prependChildLowLevel(Child, R);
23   }
24 
25   static std::pair<FileID, ArrayRef<Token>>
26   lexBuffer(syntax::Arena &A, std::unique_ptr<llvm::MemoryBuffer> Buffer) {
27     return A.lexBuffer(std::move(Buffer));
28   }
29 };
30 
31 syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K,
32                                         StringRef Spelling) {
33   auto Tokens =
34       FactoryImpl::lexBuffer(A, llvm::MemoryBuffer::getMemBuffer(Spelling))
35           .second;
36   assert(Tokens.size() == 1);
37   assert(Tokens.front().kind() == K &&
38          "spelling is not lexed into the expected kind of token");
39 
40   auto *Leaf = new (A.getAllocator()) syntax::Leaf(Tokens.begin());
41   syntax::FactoryImpl::setCanModify(Leaf);
42   Leaf->assertInvariants();
43   return Leaf;
44 }
45 
46 syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K) {
47   const auto *Spelling = tok::getPunctuatorSpelling(K);
48   if (!Spelling)
49     Spelling = tok::getKeywordSpelling(K);
50   assert(Spelling &&
51          "Cannot infer the spelling of the token from its token kind.");
52   return createLeaf(A, K, Spelling);
53 }
54 
55 syntax::Tree *clang::syntax::createTree(
56     syntax::Arena &A,
57     std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children,
58     syntax::NodeKind K) {
59   auto *T = new (A.getAllocator()) syntax::Tree(K);
60   FactoryImpl::setCanModify(T);
61   for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend();
62        std::advance(ChildIt, 1))
63     FactoryImpl::prependChildLowLevel(T, ChildIt->first, ChildIt->second);
64 
65   T->assertInvariants();
66   return T;
67 }
68 
69 syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) {
70   auto *S = new (A.getAllocator()) syntax::EmptyStatement;
71   FactoryImpl::setCanModify(S);
72   FactoryImpl::prependChildLowLevel(S, createLeaf(A, tok::semi),
73                                     NodeRole::Unknown);
74   S->assertInvariants();
75   return S;
76 }
77