clang 17.0.0git
Synthesis.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
13
14using namespace clang;
15
16/// Exposes private syntax tree APIs required to implement node synthesis.
17/// Should not be used for anything else.
19public:
20 static void setCanModify(syntax::Node *N) { N->CanModify = true; }
21
24 T->prependChildLowLevel(Child, R);
25 }
28 T->appendChildLowLevel(Child, R);
29 }
30
31 static std::pair<FileID, ArrayRef<Token>>
33 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
34 return TBTM.lexBuffer(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.
42 tok::TokenKind K, StringRef Spelling) {
43 auto Tokens =
44 FactoryImpl::lexBuffer(TBTM, llvm::MemoryBuffer::getMemBufferCopy(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()));
54 return Leaf;
55}
56
60 const auto *Spelling = tok::getPunctuatorSpelling(K);
61 if (!Spelling)
62 Spelling = tok::getKeywordSpelling(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:
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:
105 case syntax::NodeKind::PostfixUnaryOperatorExpression:
107 case syntax::NodeKind::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:
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:
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:
141 case syntax::NodeKind::ExpressionStatement:
143 case syntax::NodeKind::CompoundStatement:
145 case syntax::NodeKind::UnknownDeclaration:
147 case syntax::NodeKind::EmptyDeclaration:
148 return new (A.getAllocator()) syntax::EmptyDeclaration;
149 case syntax::NodeKind::StaticAssertDeclaration:
151 case syntax::NodeKind::LinkageSpecificationDeclaration:
153 case syntax::NodeKind::SimpleDeclaration:
155 case syntax::NodeKind::TemplateDeclaration:
157 case syntax::NodeKind::ExplicitTemplateInstantiation:
159 case syntax::NodeKind::NamespaceDefinition:
161 case syntax::NodeKind::NamespaceAliasDefinition:
163 case syntax::NodeKind::UsingNamespaceDirective:
165 case syntax::NodeKind::UsingDeclaration:
166 return new (A.getAllocator()) syntax::UsingDeclaration;
167 case syntax::NodeKind::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:
177 case syntax::NodeKind::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:
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:
197 case syntax::NodeKind::DeclaratorList:
198 return new (A.getAllocator()) syntax::DeclaratorList;
199 }
200 llvm_unreachable("unknown node kind");
201}
202} // namespace
203
205 syntax::Arena &A,
206 ArrayRef<std::pair<syntax::Node *, syntax::NodeRole>> Children,
208 auto *T = allocateTree(A, K);
209 FactoryImpl::setCanModify(T);
210 for (const auto &Child : Children)
211 FactoryImpl::appendChildLowLevel(T, Child.first, Child.second);
212
213 T->assertInvariants();
214 return T;
215}
216
219 const syntax::Node *N) {
220 if (const auto *L = dyn_cast<syntax::Leaf>(N))
221 // `L->getToken()` gives us the expanded token, thus we implicitly expand
222 // any macros here.
223 return createLeaf(A, TBTM, TBTM.getToken(L->getTokenKey())->kind(),
224 TBTM.getText(L->getTokenKey()));
225
226 const auto *T = cast<syntax::Tree>(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({deepCopyExpandingMacros(A, TBTM, Child), Child->getRole()});
231
232 return createTree(A, Children, N->getKind());
233}
234
236 return cast<EmptyStatement>(
237 createTree(A, {{createLeaf(A, TBTM, tok::semi), NodeRole::Unknown}},
238 NodeKind::EmptyStatement));
239}
Defines the clang::TokenKind enum and support functions.
A memory arena for syntax trees.
Definition: Tree.h:36
llvm::BumpPtrAllocator & getAllocator()
Definition: Tree.h:38
Array size specified inside a declarator.
Definition: Nodes.h:515
<lhs> <operator> <rhs>
Definition: Nodes.h:198
Models arguments of a function call.
Definition: Nodes.h:146
{ statement1; statement2; … }
Definition: Nodes.h:340
E.g. 'int a, b = 10;'.
Definition: Nodes.h:224
A semicolon in the top-level context. Does not declare anything.
Definition: Nodes.h:368
The no-op statement, i.e. ';'.
Definition: Nodes.h:231
template <declaration> Examples: template struct X<int> template void foo<int>() template int var<dou...
Definition: Nodes.h:427
Expression in a statement position, e.g.
Definition: Nodes.h:332
Exposes private syntax tree APIs required to implement node synthesis.
Definition: Synthesis.cpp:18
static void appendChildLowLevel(syntax::Tree *T, syntax::Node *Child, syntax::NodeRole R)
Definition: Synthesis.cpp:26
static void setCanModify(syntax::Node *N)
Definition: Synthesis.cpp:20
static std::pair< FileID, ArrayRef< Token > > lexBuffer(TokenBufferTokenManager &TBTM, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Definition: Synthesis.cpp:32
static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child, syntax::NodeRole R)
Definition: Synthesis.cpp:22
for (<init>; <cond>; <increment>) <body>
Definition: Nodes.h:278
if (cond) <then-statement> else <else-statement> FIXME: add condition that models 'expression or vari...
Definition: Nodes.h:267
A leaf node points to a single token.
Definition: Tree.h:132
extern <string-literal> declaration extern <string-literal> { <decls> }
Definition: Nodes.h:386
Member pointer inside a declarator E.g.
Definition: Nodes.h:572
namespace <name> = <namespace-reference>
Definition: Nodes.h:445
namespace <name> { <decls> }
Definition: Nodes.h:438
Models a nested-name-specifier.
Definition: Nodes.h:116
A node in a syntax tree.
Definition: Tree.h:54
void assertInvariants() const
Asserts invariants on this node of the tree and its immediate children.
Definition: Tree.cpp:239
NodeKind getKind() const
Definition: Tree.h:70
Models a parameter-declaration-list which appears within parameters-and-qualifiers.
Definition: Nodes.h:540
Parameter list for a function type and a trailing return type, if the function has one.
Definition: Nodes.h:560
Declarator inside parentheses.
Definition: Nodes.h:503
for (<decl> : <init>) <body>
Definition: Nodes.h:322
return <expr>; return;
Definition: Nodes.h:313
Groups multiple declarators (e.g.
Definition: Nodes.h:405
A top-level declarator without parentheses.
Definition: Nodes.h:494
static_assert(<condition>, <message>) static_assert(<condition>)
Definition: Nodes.h:376
switch (<cond>) <body>
Definition: Nodes.h:238
template <template-parameters> <declaration>
Definition: Nodes.h:414
A TokenBuffer-powered token manager.
const syntax::Token * getToken(Key I) const
llvm::StringRef getText(Key I) const override
uintptr_t Key
A key to identify a specific token.
Definition: TokenManager.h:40
tok::TokenKind kind() const
Definition: Tokens.h:109
Trailing return type after the parameter list, including the arrow token.
Definition: Nodes.h:527
A node that has children and represents a syntactic language construct.
Definition: Tree.h:144
using <name> = <type>
Definition: Nodes.h:468
Declaration of an unknown kind, e.g. not yet supported in syntax trees.
Definition: Nodes.h:361
An expression of an unknown kind, i.e.
Definition: Nodes.h:135
A statement of an unknown kind, i.e.
Definition: Nodes.h:217
Models an unqualified-id.
Definition: Nodes.h:127
using <scope>::<name> using typename <scope>::<name>
Definition: Nodes.h:461
using namespace <name>
Definition: Nodes.h:453
while (<cond>) <body>
Definition: Nodes.h:287
NodeRole
A relation between a parent and child node, e.g.
Definition: Nodes.h:54
syntax::Node * deepCopyExpandingMacros(syntax::Arena &A, TokenBufferTokenManager &TBTM, const syntax::Node *N)
Creates a completely independent copy of N with its macros expanded.
Definition: Synthesis.cpp:217
syntax::EmptyStatement * createEmptyStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM)
Definition: Synthesis.cpp:235
syntax::Tree * createTree(syntax::Arena &A, ArrayRef< std::pair< syntax::Node *, syntax::NodeRole > > Children, syntax::NodeKind K)
Creates the concrete syntax node according to the specified NodeKind K.
Definition: Synthesis.cpp:204
NodeKind
A kind of a syntax node, used for implementing casts.
Definition: Nodes.h:32
syntax::Leaf * createLeaf(syntax::Arena &A, TokenBufferTokenManager &TBTM, tok::TokenKind K, StringRef Spelling)
Create Leaf from token with Spelling and assert it has the desired TokenKind.
Definition: Synthesis.cpp:40
const char * getKeywordSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple keyword and contextual keyword tokens like 'int' and 'dynamic_cast'...
Definition: TokenKinds.cpp:40
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Definition: TokenKinds.h:25
const char * getPunctuatorSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple punctuation tokens like '!' or '', and returns NULL for literal and...
Definition: TokenKinds.cpp:31