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#include "clang/Tooling/Syntax/Tokens.h"
12#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
13
14using namespace clang;
15
16/// Exposes private syntax tree APIs required to implement node synthesis.
17/// Should not be used for anything else.
18class clang::syntax::FactoryImpl {
19public:
20 static void setCanModify(syntax::Node *N) { N->CanModify = true; }
21
22 static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child,
23 syntax::NodeRole R) {
24 T->prependChildLowLevel(Child, Role: R);
25 }
26 static void appendChildLowLevel(syntax::Tree *T, syntax::Node *Child,
27 syntax::NodeRole R) {
28 T->appendChildLowLevel(Child, Role: R);
29 }
30
31 static std::pair<FileID, ArrayRef<Token>>
32 lexBuffer(TokenBufferTokenManager &TBTM,
33 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
34 return TBTM.lexBuffer(Buffer: std::move(Buffer));
35 }
36};
37
38// FIXME: `createLeaf` is based on `syntax::tokenize` internally, as such it
39// doesn't support digraphs or line continuations.
40syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A,
41 TokenBufferTokenManager &TBTM,
42 tok::TokenKind K, StringRef Spelling) {
43 auto Tokens =
44 FactoryImpl::lexBuffer(TBTM, Buffer: llvm::MemoryBuffer::getMemBufferCopy(InputData: Spelling))
45 .second;
46 assert(Tokens.size() == 1);
47 assert(Tokens.front().kind() == K &&
48 "spelling is not lexed into the expected kind of token");
49
50 auto *Leaf = new (A.getAllocator()) syntax::Leaf(
51 reinterpret_cast<TokenManager::Key>(Tokens.begin()));
52 syntax::FactoryImpl::setCanModify(Leaf);
53 Leaf->assertInvariants();
54 return Leaf;
55}
56
57syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A,
58 TokenBufferTokenManager &TBTM,
59 tok::TokenKind K) {
60 const auto *Spelling = tok::getPunctuatorSpelling(Kind: K);
61 if (!Spelling)
62 Spelling = tok::getKeywordSpelling(Kind: K);
63 assert(Spelling &&
64 "Cannot infer the spelling of the token from its token kind.");
65 return createLeaf(A, TBTM, K, Spelling);
66}
67
68namespace {
69// Allocates the concrete syntax `Tree` according to its `NodeKind`.
70syntax::Tree *allocateTree(syntax::Arena &A, syntax::NodeKind Kind) {
71 switch (Kind) {
72 case syntax::NodeKind::Leaf:
73 assert(false);
74 break;
75 case syntax::NodeKind::TranslationUnit:
76 return new (A.getAllocator()) syntax::TranslationUnit;
77 case syntax::NodeKind::UnknownExpression:
78 return new (A.getAllocator()) syntax::UnknownExpression;
79 case syntax::NodeKind::ParenExpression:
80 return new (A.getAllocator()) syntax::ParenExpression;
81 case syntax::NodeKind::ThisExpression:
82 return new (A.getAllocator()) syntax::ThisExpression;
83 case syntax::NodeKind::IntegerLiteralExpression:
84 return new (A.getAllocator()) syntax::IntegerLiteralExpression;
85 case syntax::NodeKind::CharacterLiteralExpression:
86 return new (A.getAllocator()) syntax::CharacterLiteralExpression;
87 case syntax::NodeKind::FloatingLiteralExpression:
88 return new (A.getAllocator()) syntax::FloatingLiteralExpression;
89 case syntax::NodeKind::StringLiteralExpression:
90 return new (A.getAllocator()) syntax::StringLiteralExpression;
91 case syntax::NodeKind::BoolLiteralExpression:
92 return new (A.getAllocator()) syntax::BoolLiteralExpression;
93 case syntax::NodeKind::CxxNullPtrExpression:
94 return new (A.getAllocator()) syntax::CxxNullPtrExpression;
95 case syntax::NodeKind::IntegerUserDefinedLiteralExpression:
96 return new (A.getAllocator()) syntax::IntegerUserDefinedLiteralExpression;
97 case syntax::NodeKind::FloatUserDefinedLiteralExpression:
98 return new (A.getAllocator()) syntax::FloatUserDefinedLiteralExpression;
99 case syntax::NodeKind::CharUserDefinedLiteralExpression:
100 return new (A.getAllocator()) syntax::CharUserDefinedLiteralExpression;
101 case syntax::NodeKind::StringUserDefinedLiteralExpression:
102 return new (A.getAllocator()) syntax::StringUserDefinedLiteralExpression;
103 case syntax::NodeKind::PrefixUnaryOperatorExpression:
104 return new (A.getAllocator()) syntax::PrefixUnaryOperatorExpression;
105 case syntax::NodeKind::PostfixUnaryOperatorExpression:
106 return new (A.getAllocator()) syntax::PostfixUnaryOperatorExpression;
107 case syntax::NodeKind::BinaryOperatorExpression:
108 return new (A.getAllocator()) syntax::BinaryOperatorExpression;
109 case syntax::NodeKind::UnqualifiedId:
110 return new (A.getAllocator()) syntax::UnqualifiedId;
111 case syntax::NodeKind::IdExpression:
112 return new (A.getAllocator()) syntax::IdExpression;
113 case syntax::NodeKind::CallExpression:
114 return new (A.getAllocator()) syntax::CallExpression;
115 case syntax::NodeKind::UnknownStatement:
116 return new (A.getAllocator()) syntax::UnknownStatement;
117 case syntax::NodeKind::DeclarationStatement:
118 return new (A.getAllocator()) syntax::DeclarationStatement;
119 case syntax::NodeKind::EmptyStatement:
120 return new (A.getAllocator()) syntax::EmptyStatement;
121 case syntax::NodeKind::SwitchStatement:
122 return new (A.getAllocator()) syntax::SwitchStatement;
123 case syntax::NodeKind::CaseStatement:
124 return new (A.getAllocator()) syntax::CaseStatement;
125 case syntax::NodeKind::DefaultStatement:
126 return new (A.getAllocator()) syntax::DefaultStatement;
127 case syntax::NodeKind::IfStatement:
128 return new (A.getAllocator()) syntax::IfStatement;
129 case syntax::NodeKind::ForStatement:
130 return new (A.getAllocator()) syntax::ForStatement;
131 case syntax::NodeKind::WhileStatement:
132 return new (A.getAllocator()) syntax::WhileStatement;
133 case syntax::NodeKind::ContinueStatement:
134 return new (A.getAllocator()) syntax::ContinueStatement;
135 case syntax::NodeKind::BreakStatement:
136 return new (A.getAllocator()) syntax::BreakStatement;
137 case syntax::NodeKind::ReturnStatement:
138 return new (A.getAllocator()) syntax::ReturnStatement;
139 case syntax::NodeKind::RangeBasedForStatement:
140 return new (A.getAllocator()) syntax::RangeBasedForStatement;
141 case syntax::NodeKind::ExpressionStatement:
142 return new (A.getAllocator()) syntax::ExpressionStatement;
143 case syntax::NodeKind::CompoundStatement:
144 return new (A.getAllocator()) syntax::CompoundStatement;
145 case syntax::NodeKind::UnknownDeclaration:
146 return new (A.getAllocator()) syntax::UnknownDeclaration;
147 case syntax::NodeKind::EmptyDeclaration:
148 return new (A.getAllocator()) syntax::EmptyDeclaration;
149 case syntax::NodeKind::StaticAssertDeclaration:
150 return new (A.getAllocator()) syntax::StaticAssertDeclaration;
151 case syntax::NodeKind::LinkageSpecificationDeclaration:
152 return new (A.getAllocator()) syntax::LinkageSpecificationDeclaration;
153 case syntax::NodeKind::SimpleDeclaration:
154 return new (A.getAllocator()) syntax::SimpleDeclaration;
155 case syntax::NodeKind::TemplateDeclaration:
156 return new (A.getAllocator()) syntax::TemplateDeclaration;
157 case syntax::NodeKind::ExplicitTemplateInstantiation:
158 return new (A.getAllocator()) syntax::ExplicitTemplateInstantiation;
159 case syntax::NodeKind::NamespaceDefinition:
160 return new (A.getAllocator()) syntax::NamespaceDefinition;
161 case syntax::NodeKind::NamespaceAliasDefinition:
162 return new (A.getAllocator()) syntax::NamespaceAliasDefinition;
163 case syntax::NodeKind::UsingNamespaceDirective:
164 return new (A.getAllocator()) syntax::UsingNamespaceDirective;
165 case syntax::NodeKind::UsingDeclaration:
166 return new (A.getAllocator()) syntax::UsingDeclaration;
167 case syntax::NodeKind::TypeAliasDeclaration:
168 return new (A.getAllocator()) syntax::TypeAliasDeclaration;
169 case syntax::NodeKind::SimpleDeclarator:
170 return new (A.getAllocator()) syntax::SimpleDeclarator;
171 case syntax::NodeKind::ParenDeclarator:
172 return new (A.getAllocator()) syntax::ParenDeclarator;
173 case syntax::NodeKind::ArraySubscript:
174 return new (A.getAllocator()) syntax::ArraySubscript;
175 case syntax::NodeKind::TrailingReturnType:
176 return new (A.getAllocator()) syntax::TrailingReturnType;
177 case syntax::NodeKind::ParametersAndQualifiers:
178 return new (A.getAllocator()) syntax::ParametersAndQualifiers;
179 case syntax::NodeKind::MemberPointer:
180 return new (A.getAllocator()) syntax::MemberPointer;
181 case syntax::NodeKind::GlobalNameSpecifier:
182 return new (A.getAllocator()) syntax::GlobalNameSpecifier;
183 case syntax::NodeKind::DecltypeNameSpecifier:
184 return new (A.getAllocator()) syntax::DecltypeNameSpecifier;
185 case syntax::NodeKind::IdentifierNameSpecifier:
186 return new (A.getAllocator()) syntax::IdentifierNameSpecifier;
187 case syntax::NodeKind::SimpleTemplateNameSpecifier:
188 return new (A.getAllocator()) syntax::SimpleTemplateNameSpecifier;
189 case syntax::NodeKind::NestedNameSpecifier:
190 return new (A.getAllocator()) syntax::NestedNameSpecifier;
191 case syntax::NodeKind::MemberExpression:
192 return new (A.getAllocator()) syntax::MemberExpression;
193 case syntax::NodeKind::CallArguments:
194 return new (A.getAllocator()) syntax::CallArguments;
195 case syntax::NodeKind::ParameterDeclarationList:
196 return new (A.getAllocator()) syntax::ParameterDeclarationList;
197 case syntax::NodeKind::DeclaratorList:
198 return new (A.getAllocator()) syntax::DeclaratorList;
199 }
200 llvm_unreachable("unknown node kind");
201}
202} // namespace
203
204syntax::Tree *clang::syntax::createTree(
205 syntax::Arena &A,
206 ArrayRef<std::pair<syntax::Node *, syntax::NodeRole>> Children,
207 syntax::NodeKind K) {
208 auto *T = allocateTree(A, Kind: K);
209 FactoryImpl::setCanModify(T);
210 for (const auto &Child : Children)
211 FactoryImpl::appendChildLowLevel(T, Child: Child.first, R: Child.second);
212
213 T->assertInvariants();
214 return T;
215}
216
217syntax::Node *clang::syntax::deepCopyExpandingMacros(syntax::Arena &A,
218 TokenBufferTokenManager &TBTM,
219 const syntax::Node *N) {
220 if (const auto *L = dyn_cast<syntax::Leaf>(Val: N))
221 // `L->getToken()` gives us the expanded token, thus we implicitly expand
222 // any macros here.
223 return createLeaf(A, TBTM, K: TBTM.getToken(I: L->getTokenKey())->kind(),
224 Spelling: TBTM.getText(I: L->getTokenKey()));
225
226 const auto *T = cast<syntax::Tree>(Val: N);
227 std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children;
228 for (const auto *Child = T->getFirstChild(); Child;
229 Child = Child->getNextSibling())
230 Children.push_back(x: {deepCopyExpandingMacros(A, TBTM, N: Child), Child->getRole()});
231
232 return createTree(A, Children, K: N->getKind());
233}
234
235syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM) {
236 return cast<EmptyStatement>(
237 createTree(A, {{createLeaf(A, TBTM, tok::semi), NodeRole::Unknown}},
238 NodeKind::EmptyStatement));
239}
240

source code of clang/lib/Tooling/Syntax/Synthesis.cpp