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