1f678e45dSDimitry Andric //===-- CPlusPlusNameParser.cpp ---------------------------------*- C++ -*-===//
2f678e45dSDimitry Andric //
3f678e45dSDimitry Andric // The LLVM Compiler Infrastructure
4f678e45dSDimitry Andric //
5f678e45dSDimitry Andric // This file is distributed under the University of Illinois Open Source
6f678e45dSDimitry Andric // License. See LICENSE.TXT for details.
7f678e45dSDimitry Andric //
8f678e45dSDimitry Andric //===----------------------------------------------------------------------===//
9f678e45dSDimitry Andric
10f678e45dSDimitry Andric #include "CPlusPlusNameParser.h"
11f678e45dSDimitry Andric
12f678e45dSDimitry Andric #include "clang/Basic/IdentifierTable.h"
13f678e45dSDimitry Andric #include "llvm/ADT/StringMap.h"
14f678e45dSDimitry Andric #include "llvm/Support/Threading.h"
15f678e45dSDimitry Andric
16f678e45dSDimitry Andric using namespace lldb;
17f678e45dSDimitry Andric using namespace lldb_private;
18f678e45dSDimitry Andric using llvm::Optional;
19f678e45dSDimitry Andric using llvm::None;
20f678e45dSDimitry Andric using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
21f678e45dSDimitry Andric using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
22f678e45dSDimitry Andric namespace tok = clang::tok;
23f678e45dSDimitry Andric
ParseAsFunctionDefinition()24f678e45dSDimitry Andric Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
25f678e45dSDimitry Andric m_next_token_index = 0;
26f678e45dSDimitry Andric Optional<ParsedFunction> result(None);
27f678e45dSDimitry Andric
28*4ba319b5SDimitry Andric // Try to parse the name as function without a return type specified e.g.
29*4ba319b5SDimitry Andric // main(int, char*[])
30f678e45dSDimitry Andric {
31f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
32f678e45dSDimitry Andric result = ParseFunctionImpl(false);
33f678e45dSDimitry Andric if (result && !HasMoreTokens())
34f678e45dSDimitry Andric return result;
35f678e45dSDimitry Andric }
36f678e45dSDimitry Andric
37*4ba319b5SDimitry Andric // Try to parse the name as function with function pointer return type e.g.
38*4ba319b5SDimitry Andric // void (*get_func(const char*))()
39f678e45dSDimitry Andric result = ParseFuncPtr(true);
40f678e45dSDimitry Andric if (result)
41f678e45dSDimitry Andric return result;
42f678e45dSDimitry Andric
43f678e45dSDimitry Andric // Finally try to parse the name as a function with non-function return type
44f678e45dSDimitry Andric // e.g. int main(int, char*[])
45f678e45dSDimitry Andric result = ParseFunctionImpl(true);
46f678e45dSDimitry Andric if (HasMoreTokens())
47f678e45dSDimitry Andric return None;
48f678e45dSDimitry Andric return result;
49f678e45dSDimitry Andric }
50f678e45dSDimitry Andric
ParseAsFullName()51f678e45dSDimitry Andric Optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
52f678e45dSDimitry Andric m_next_token_index = 0;
53f678e45dSDimitry Andric Optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
54f678e45dSDimitry Andric if (!name_ranges)
55f678e45dSDimitry Andric return None;
56f678e45dSDimitry Andric if (HasMoreTokens())
57f678e45dSDimitry Andric return None;
58f678e45dSDimitry Andric ParsedName result;
59f678e45dSDimitry Andric result.basename = GetTextForRange(name_ranges.getValue().basename_range);
60f678e45dSDimitry Andric result.context = GetTextForRange(name_ranges.getValue().context_range);
61f678e45dSDimitry Andric return result;
62f678e45dSDimitry Andric }
63f678e45dSDimitry Andric
HasMoreTokens()64f678e45dSDimitry Andric bool CPlusPlusNameParser::HasMoreTokens() {
65f678e45dSDimitry Andric return m_next_token_index < m_tokens.size();
66f678e45dSDimitry Andric }
67f678e45dSDimitry Andric
Advance()68f678e45dSDimitry Andric void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
69f678e45dSDimitry Andric
TakeBack()70f678e45dSDimitry Andric void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
71f678e45dSDimitry Andric
ConsumeToken(tok::TokenKind kind)72f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
73f678e45dSDimitry Andric if (!HasMoreTokens())
74f678e45dSDimitry Andric return false;
75f678e45dSDimitry Andric
76f678e45dSDimitry Andric if (!Peek().is(kind))
77f678e45dSDimitry Andric return false;
78f678e45dSDimitry Andric
79f678e45dSDimitry Andric Advance();
80f678e45dSDimitry Andric return true;
81f678e45dSDimitry Andric }
82f678e45dSDimitry Andric
ConsumeToken(Ts...kinds)83f678e45dSDimitry Andric template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
84f678e45dSDimitry Andric if (!HasMoreTokens())
85f678e45dSDimitry Andric return false;
86f678e45dSDimitry Andric
87f678e45dSDimitry Andric if (!Peek().isOneOf(kinds...))
88f678e45dSDimitry Andric return false;
89f678e45dSDimitry Andric
90f678e45dSDimitry Andric Advance();
91f678e45dSDimitry Andric return true;
92f678e45dSDimitry Andric }
93f678e45dSDimitry Andric
SetBookmark()94f678e45dSDimitry Andric CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
95f678e45dSDimitry Andric return Bookmark(m_next_token_index);
96f678e45dSDimitry Andric }
97f678e45dSDimitry Andric
GetCurrentPosition()98f678e45dSDimitry Andric size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
99f678e45dSDimitry Andric
Peek()100f678e45dSDimitry Andric clang::Token &CPlusPlusNameParser::Peek() {
101f678e45dSDimitry Andric assert(HasMoreTokens());
102f678e45dSDimitry Andric return m_tokens[m_next_token_index];
103f678e45dSDimitry Andric }
104f678e45dSDimitry Andric
105f678e45dSDimitry Andric Optional<ParsedFunction>
ParseFunctionImpl(bool expect_return_type)106f678e45dSDimitry Andric CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
107f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
108f678e45dSDimitry Andric if (expect_return_type) {
109f678e45dSDimitry Andric // Consume return type if it's expected.
110f678e45dSDimitry Andric if (!ConsumeTypename())
111f678e45dSDimitry Andric return None;
112f678e45dSDimitry Andric }
113f678e45dSDimitry Andric
114f678e45dSDimitry Andric auto maybe_name = ParseFullNameImpl();
115f678e45dSDimitry Andric if (!maybe_name) {
116f678e45dSDimitry Andric return None;
117f678e45dSDimitry Andric }
118f678e45dSDimitry Andric
119f678e45dSDimitry Andric size_t argument_start = GetCurrentPosition();
120f678e45dSDimitry Andric if (!ConsumeArguments()) {
121f678e45dSDimitry Andric return None;
122f678e45dSDimitry Andric }
123f678e45dSDimitry Andric
124f678e45dSDimitry Andric size_t qualifiers_start = GetCurrentPosition();
125f678e45dSDimitry Andric SkipFunctionQualifiers();
126f678e45dSDimitry Andric size_t end_position = GetCurrentPosition();
127f678e45dSDimitry Andric
128f678e45dSDimitry Andric ParsedFunction result;
129f678e45dSDimitry Andric result.name.basename = GetTextForRange(maybe_name.getValue().basename_range);
130f678e45dSDimitry Andric result.name.context = GetTextForRange(maybe_name.getValue().context_range);
131f678e45dSDimitry Andric result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
132f678e45dSDimitry Andric result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
133f678e45dSDimitry Andric start_position.Remove();
134f678e45dSDimitry Andric return result;
135f678e45dSDimitry Andric }
136f678e45dSDimitry Andric
137f678e45dSDimitry Andric Optional<ParsedFunction>
ParseFuncPtr(bool expect_return_type)138f678e45dSDimitry Andric CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
139f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
140f678e45dSDimitry Andric if (expect_return_type) {
141f678e45dSDimitry Andric // Consume return type.
142f678e45dSDimitry Andric if (!ConsumeTypename())
143f678e45dSDimitry Andric return None;
144f678e45dSDimitry Andric }
145f678e45dSDimitry Andric
146f678e45dSDimitry Andric if (!ConsumeToken(tok::l_paren))
147f678e45dSDimitry Andric return None;
148f678e45dSDimitry Andric if (!ConsumePtrsAndRefs())
149f678e45dSDimitry Andric return None;
150f678e45dSDimitry Andric
151f678e45dSDimitry Andric {
152f678e45dSDimitry Andric Bookmark before_inner_function_pos = SetBookmark();
153f678e45dSDimitry Andric auto maybe_inner_function_name = ParseFunctionImpl(false);
154f678e45dSDimitry Andric if (maybe_inner_function_name)
155f678e45dSDimitry Andric if (ConsumeToken(tok::r_paren))
156f678e45dSDimitry Andric if (ConsumeArguments()) {
157f678e45dSDimitry Andric SkipFunctionQualifiers();
158f678e45dSDimitry Andric start_position.Remove();
159f678e45dSDimitry Andric before_inner_function_pos.Remove();
160f678e45dSDimitry Andric return maybe_inner_function_name;
161f678e45dSDimitry Andric }
162f678e45dSDimitry Andric }
163f678e45dSDimitry Andric
164f678e45dSDimitry Andric auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
165f678e45dSDimitry Andric if (maybe_inner_function_ptr_name)
166f678e45dSDimitry Andric if (ConsumeToken(tok::r_paren))
167f678e45dSDimitry Andric if (ConsumeArguments()) {
168f678e45dSDimitry Andric SkipFunctionQualifiers();
169f678e45dSDimitry Andric start_position.Remove();
170f678e45dSDimitry Andric return maybe_inner_function_ptr_name;
171f678e45dSDimitry Andric }
172f678e45dSDimitry Andric return None;
173f678e45dSDimitry Andric }
174f678e45dSDimitry Andric
ConsumeArguments()175f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeArguments() {
176f678e45dSDimitry Andric return ConsumeBrackets(tok::l_paren, tok::r_paren);
177f678e45dSDimitry Andric }
178f678e45dSDimitry Andric
ConsumeTemplateArgs()179f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeTemplateArgs() {
180f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
181f678e45dSDimitry Andric if (!HasMoreTokens() || Peek().getKind() != tok::less)
182f678e45dSDimitry Andric return false;
183f678e45dSDimitry Andric Advance();
184f678e45dSDimitry Andric
185f678e45dSDimitry Andric // Consuming template arguments is a bit trickier than consuming function
186*4ba319b5SDimitry Andric // arguments, because '<' '>' brackets are not always trivially balanced. In
187*4ba319b5SDimitry Andric // some rare cases tokens '<' and '>' can appear inside template arguments as
188*4ba319b5SDimitry Andric // arithmetic or shift operators not as template brackets. Examples:
189*4ba319b5SDimitry Andric // std::enable_if<(10u)<(64), bool>
190f678e45dSDimitry Andric // f<A<operator<(X,Y)::Subclass>>
191*4ba319b5SDimitry Andric // Good thing that compiler makes sure that really ambiguous cases of '>'
192*4ba319b5SDimitry Andric // usage should be enclosed within '()' brackets.
193f678e45dSDimitry Andric int template_counter = 1;
194f678e45dSDimitry Andric bool can_open_template = false;
195f678e45dSDimitry Andric while (HasMoreTokens() && template_counter > 0) {
196f678e45dSDimitry Andric tok::TokenKind kind = Peek().getKind();
197f678e45dSDimitry Andric switch (kind) {
198f678e45dSDimitry Andric case tok::greatergreater:
199f678e45dSDimitry Andric template_counter -= 2;
200f678e45dSDimitry Andric can_open_template = false;
201f678e45dSDimitry Andric Advance();
202f678e45dSDimitry Andric break;
203f678e45dSDimitry Andric case tok::greater:
204f678e45dSDimitry Andric --template_counter;
205f678e45dSDimitry Andric can_open_template = false;
206f678e45dSDimitry Andric Advance();
207f678e45dSDimitry Andric break;
208f678e45dSDimitry Andric case tok::less:
209f678e45dSDimitry Andric // '<' is an attempt to open a subteamplte
210f678e45dSDimitry Andric // check if parser is at the point where it's actually possible,
211*4ba319b5SDimitry Andric // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No
212*4ba319b5SDimitry Andric // need to do the same for '>' because compiler actually makes sure that
213*4ba319b5SDimitry Andric // '>' always surrounded by brackets to avoid ambiguity.
214f678e45dSDimitry Andric if (can_open_template)
215f678e45dSDimitry Andric ++template_counter;
216f678e45dSDimitry Andric can_open_template = false;
217f678e45dSDimitry Andric Advance();
218f678e45dSDimitry Andric break;
219f678e45dSDimitry Andric case tok::kw_operator: // C++ operator overloading.
220f678e45dSDimitry Andric if (!ConsumeOperator())
221f678e45dSDimitry Andric return false;
222f678e45dSDimitry Andric can_open_template = true;
223f678e45dSDimitry Andric break;
224f678e45dSDimitry Andric case tok::raw_identifier:
225f678e45dSDimitry Andric can_open_template = true;
226f678e45dSDimitry Andric Advance();
227f678e45dSDimitry Andric break;
228f678e45dSDimitry Andric case tok::l_square:
229f678e45dSDimitry Andric if (!ConsumeBrackets(tok::l_square, tok::r_square))
230f678e45dSDimitry Andric return false;
231f678e45dSDimitry Andric can_open_template = false;
232f678e45dSDimitry Andric break;
233f678e45dSDimitry Andric case tok::l_paren:
234f678e45dSDimitry Andric if (!ConsumeArguments())
235f678e45dSDimitry Andric return false;
236f678e45dSDimitry Andric can_open_template = false;
237f678e45dSDimitry Andric break;
238f678e45dSDimitry Andric default:
239f678e45dSDimitry Andric can_open_template = false;
240f678e45dSDimitry Andric Advance();
241f678e45dSDimitry Andric break;
242f678e45dSDimitry Andric }
243f678e45dSDimitry Andric }
244f678e45dSDimitry Andric
245*4ba319b5SDimitry Andric if (template_counter != 0) {
246f678e45dSDimitry Andric return false;
247f678e45dSDimitry Andric }
248f678e45dSDimitry Andric start_position.Remove();
249f678e45dSDimitry Andric return true;
250f678e45dSDimitry Andric }
251f678e45dSDimitry Andric
ConsumeAnonymousNamespace()252f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
253f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
254f678e45dSDimitry Andric if (!ConsumeToken(tok::l_paren)) {
255f678e45dSDimitry Andric return false;
256f678e45dSDimitry Andric }
257f678e45dSDimitry Andric constexpr llvm::StringLiteral g_anonymous("anonymous");
258f678e45dSDimitry Andric if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
259f678e45dSDimitry Andric Peek().getRawIdentifier() == g_anonymous) {
260f678e45dSDimitry Andric Advance();
261f678e45dSDimitry Andric } else {
262f678e45dSDimitry Andric return false;
263f678e45dSDimitry Andric }
264f678e45dSDimitry Andric
265f678e45dSDimitry Andric if (!ConsumeToken(tok::kw_namespace)) {
266f678e45dSDimitry Andric return false;
267f678e45dSDimitry Andric }
268f678e45dSDimitry Andric
269f678e45dSDimitry Andric if (!ConsumeToken(tok::r_paren)) {
270f678e45dSDimitry Andric return false;
271f678e45dSDimitry Andric }
272f678e45dSDimitry Andric start_position.Remove();
273f678e45dSDimitry Andric return true;
274f678e45dSDimitry Andric }
275f678e45dSDimitry Andric
ConsumeLambda()276b40b48b8SDimitry Andric bool CPlusPlusNameParser::ConsumeLambda() {
277b40b48b8SDimitry Andric Bookmark start_position = SetBookmark();
278b40b48b8SDimitry Andric if (!ConsumeToken(tok::l_brace)) {
279b40b48b8SDimitry Andric return false;
280b40b48b8SDimitry Andric }
281b40b48b8SDimitry Andric constexpr llvm::StringLiteral g_lambda("lambda");
282b40b48b8SDimitry Andric if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
283b40b48b8SDimitry Andric Peek().getRawIdentifier() == g_lambda) {
284b40b48b8SDimitry Andric // Put the matched brace back so we can use ConsumeBrackets
285b40b48b8SDimitry Andric TakeBack();
286b40b48b8SDimitry Andric } else {
287b40b48b8SDimitry Andric return false;
288b40b48b8SDimitry Andric }
289b40b48b8SDimitry Andric
290b40b48b8SDimitry Andric if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) {
291b40b48b8SDimitry Andric return false;
292b40b48b8SDimitry Andric }
293b40b48b8SDimitry Andric
294b40b48b8SDimitry Andric start_position.Remove();
295b40b48b8SDimitry Andric return true;
296b40b48b8SDimitry Andric }
297b40b48b8SDimitry Andric
ConsumeBrackets(tok::TokenKind left,tok::TokenKind right)298f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
299f678e45dSDimitry Andric tok::TokenKind right) {
300f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
301f678e45dSDimitry Andric if (!HasMoreTokens() || Peek().getKind() != left)
302f678e45dSDimitry Andric return false;
303f678e45dSDimitry Andric Advance();
304f678e45dSDimitry Andric
305f678e45dSDimitry Andric int counter = 1;
306f678e45dSDimitry Andric while (HasMoreTokens() && counter > 0) {
307f678e45dSDimitry Andric tok::TokenKind kind = Peek().getKind();
308f678e45dSDimitry Andric if (kind == right)
309f678e45dSDimitry Andric --counter;
310f678e45dSDimitry Andric else if (kind == left)
311f678e45dSDimitry Andric ++counter;
312f678e45dSDimitry Andric Advance();
313f678e45dSDimitry Andric }
314f678e45dSDimitry Andric
315f678e45dSDimitry Andric assert(counter >= 0);
316f678e45dSDimitry Andric if (counter > 0) {
317f678e45dSDimitry Andric return false;
318f678e45dSDimitry Andric }
319f678e45dSDimitry Andric start_position.Remove();
320f678e45dSDimitry Andric return true;
321f678e45dSDimitry Andric }
322f678e45dSDimitry Andric
ConsumeOperator()323f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeOperator() {
324f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
325f678e45dSDimitry Andric if (!ConsumeToken(tok::kw_operator))
326f678e45dSDimitry Andric return false;
327f678e45dSDimitry Andric
328f678e45dSDimitry Andric if (!HasMoreTokens()) {
329f678e45dSDimitry Andric return false;
330f678e45dSDimitry Andric }
331f678e45dSDimitry Andric
332f678e45dSDimitry Andric const auto &token = Peek();
333f678e45dSDimitry Andric switch (token.getKind()) {
334f678e45dSDimitry Andric case tok::kw_new:
335f678e45dSDimitry Andric case tok::kw_delete:
336f678e45dSDimitry Andric // This is 'new' or 'delete' operators.
337f678e45dSDimitry Andric Advance();
338f678e45dSDimitry Andric // Check for array new/delete.
339f678e45dSDimitry Andric if (HasMoreTokens() && Peek().is(tok::l_square)) {
340f678e45dSDimitry Andric // Consume the '[' and ']'.
341f678e45dSDimitry Andric if (!ConsumeBrackets(tok::l_square, tok::r_square))
342f678e45dSDimitry Andric return false;
343f678e45dSDimitry Andric }
344f678e45dSDimitry Andric break;
345f678e45dSDimitry Andric
346f678e45dSDimitry Andric #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
347f678e45dSDimitry Andric case tok::Token: \
348f678e45dSDimitry Andric Advance(); \
349f678e45dSDimitry Andric break;
350f678e45dSDimitry Andric #define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
351f678e45dSDimitry Andric #include "clang/Basic/OperatorKinds.def"
352f678e45dSDimitry Andric #undef OVERLOADED_OPERATOR
353f678e45dSDimitry Andric #undef OVERLOADED_OPERATOR_MULTI
354f678e45dSDimitry Andric
355f678e45dSDimitry Andric case tok::l_paren:
356f678e45dSDimitry Andric // Call operator consume '(' ... ')'.
357f678e45dSDimitry Andric if (ConsumeBrackets(tok::l_paren, tok::r_paren))
358f678e45dSDimitry Andric break;
359f678e45dSDimitry Andric return false;
360f678e45dSDimitry Andric
361f678e45dSDimitry Andric case tok::l_square:
362f678e45dSDimitry Andric // This is a [] operator.
363f678e45dSDimitry Andric // Consume the '[' and ']'.
364f678e45dSDimitry Andric if (ConsumeBrackets(tok::l_square, tok::r_square))
365f678e45dSDimitry Andric break;
366f678e45dSDimitry Andric return false;
367f678e45dSDimitry Andric
368f678e45dSDimitry Andric default:
369f678e45dSDimitry Andric // This might be a cast operator.
370f678e45dSDimitry Andric if (ConsumeTypename())
371f678e45dSDimitry Andric break;
372f678e45dSDimitry Andric return false;
373f678e45dSDimitry Andric }
374f678e45dSDimitry Andric start_position.Remove();
375f678e45dSDimitry Andric return true;
376f678e45dSDimitry Andric }
377f678e45dSDimitry Andric
SkipTypeQualifiers()378f678e45dSDimitry Andric void CPlusPlusNameParser::SkipTypeQualifiers() {
379f678e45dSDimitry Andric while (ConsumeToken(tok::kw_const, tok::kw_volatile))
380f678e45dSDimitry Andric ;
381f678e45dSDimitry Andric }
382f678e45dSDimitry Andric
SkipFunctionQualifiers()383f678e45dSDimitry Andric void CPlusPlusNameParser::SkipFunctionQualifiers() {
384f678e45dSDimitry Andric while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
385f678e45dSDimitry Andric ;
386f678e45dSDimitry Andric }
387f678e45dSDimitry Andric
ConsumeBuiltinType()388f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeBuiltinType() {
389f678e45dSDimitry Andric bool result = false;
390f678e45dSDimitry Andric bool continue_parsing = true;
391*4ba319b5SDimitry Andric // Built-in types can be made of a few keywords like 'unsigned long long
392*4ba319b5SDimitry Andric // int'. This function consumes all built-in type keywords without checking
393*4ba319b5SDimitry Andric // if they make sense like 'unsigned char void'.
394f678e45dSDimitry Andric while (continue_parsing && HasMoreTokens()) {
395f678e45dSDimitry Andric switch (Peek().getKind()) {
396f678e45dSDimitry Andric case tok::kw_short:
397f678e45dSDimitry Andric case tok::kw_long:
398f678e45dSDimitry Andric case tok::kw___int64:
399f678e45dSDimitry Andric case tok::kw___int128:
400f678e45dSDimitry Andric case tok::kw_signed:
401f678e45dSDimitry Andric case tok::kw_unsigned:
402f678e45dSDimitry Andric case tok::kw_void:
403f678e45dSDimitry Andric case tok::kw_char:
404f678e45dSDimitry Andric case tok::kw_int:
405f678e45dSDimitry Andric case tok::kw_half:
406f678e45dSDimitry Andric case tok::kw_float:
407f678e45dSDimitry Andric case tok::kw_double:
408f678e45dSDimitry Andric case tok::kw___float128:
409f678e45dSDimitry Andric case tok::kw_wchar_t:
410f678e45dSDimitry Andric case tok::kw_bool:
411f678e45dSDimitry Andric case tok::kw_char16_t:
412f678e45dSDimitry Andric case tok::kw_char32_t:
413f678e45dSDimitry Andric result = true;
414f678e45dSDimitry Andric Advance();
415f678e45dSDimitry Andric break;
416f678e45dSDimitry Andric default:
417f678e45dSDimitry Andric continue_parsing = false;
418f678e45dSDimitry Andric break;
419f678e45dSDimitry Andric }
420f678e45dSDimitry Andric }
421f678e45dSDimitry Andric return result;
422f678e45dSDimitry Andric }
423f678e45dSDimitry Andric
SkipPtrsAndRefs()424f678e45dSDimitry Andric void CPlusPlusNameParser::SkipPtrsAndRefs() {
425f678e45dSDimitry Andric // Ignoring result.
426f678e45dSDimitry Andric ConsumePtrsAndRefs();
427f678e45dSDimitry Andric }
428f678e45dSDimitry Andric
ConsumePtrsAndRefs()429f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
430f678e45dSDimitry Andric bool found = false;
431f678e45dSDimitry Andric SkipTypeQualifiers();
432f678e45dSDimitry Andric while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
433f678e45dSDimitry Andric tok::kw_volatile)) {
434f678e45dSDimitry Andric found = true;
435f678e45dSDimitry Andric SkipTypeQualifiers();
436f678e45dSDimitry Andric }
437f678e45dSDimitry Andric return found;
438f678e45dSDimitry Andric }
439f678e45dSDimitry Andric
ConsumeDecltype()440f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeDecltype() {
441f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
442f678e45dSDimitry Andric if (!ConsumeToken(tok::kw_decltype))
443f678e45dSDimitry Andric return false;
444f678e45dSDimitry Andric
445f678e45dSDimitry Andric if (!ConsumeArguments())
446f678e45dSDimitry Andric return false;
447f678e45dSDimitry Andric
448f678e45dSDimitry Andric start_position.Remove();
449f678e45dSDimitry Andric return true;
450f678e45dSDimitry Andric }
451f678e45dSDimitry Andric
ConsumeTypename()452f678e45dSDimitry Andric bool CPlusPlusNameParser::ConsumeTypename() {
453f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
454f678e45dSDimitry Andric SkipTypeQualifiers();
455f678e45dSDimitry Andric if (!ConsumeBuiltinType() && !ConsumeDecltype()) {
456f678e45dSDimitry Andric if (!ParseFullNameImpl())
457f678e45dSDimitry Andric return false;
458f678e45dSDimitry Andric }
459f678e45dSDimitry Andric SkipPtrsAndRefs();
460f678e45dSDimitry Andric start_position.Remove();
461f678e45dSDimitry Andric return true;
462f678e45dSDimitry Andric }
463f678e45dSDimitry Andric
464f678e45dSDimitry Andric Optional<CPlusPlusNameParser::ParsedNameRanges>
ParseFullNameImpl()465f678e45dSDimitry Andric CPlusPlusNameParser::ParseFullNameImpl() {
466f678e45dSDimitry Andric // Name parsing state machine.
467f678e45dSDimitry Andric enum class State {
468f678e45dSDimitry Andric Beginning, // start of the name
469f678e45dSDimitry Andric AfterTwoColons, // right after ::
470f678e45dSDimitry Andric AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
471f678e45dSDimitry Andric AfterTemplate, // right after template brackets (<something>)
472f678e45dSDimitry Andric AfterOperator, // right after name of C++ operator
473f678e45dSDimitry Andric };
474f678e45dSDimitry Andric
475f678e45dSDimitry Andric Bookmark start_position = SetBookmark();
476f678e45dSDimitry Andric State state = State::Beginning;
477f678e45dSDimitry Andric bool continue_parsing = true;
478f678e45dSDimitry Andric Optional<size_t> last_coloncolon_position = None;
479f678e45dSDimitry Andric
480f678e45dSDimitry Andric while (continue_parsing && HasMoreTokens()) {
481f678e45dSDimitry Andric const auto &token = Peek();
482f678e45dSDimitry Andric switch (token.getKind()) {
483f678e45dSDimitry Andric case tok::raw_identifier: // Just a name.
484f678e45dSDimitry Andric if (state != State::Beginning && state != State::AfterTwoColons) {
485f678e45dSDimitry Andric continue_parsing = false;
486f678e45dSDimitry Andric break;
487f678e45dSDimitry Andric }
488f678e45dSDimitry Andric Advance();
489f678e45dSDimitry Andric state = State::AfterIdentifier;
490f678e45dSDimitry Andric break;
491f678e45dSDimitry Andric case tok::l_paren: {
492f678e45dSDimitry Andric if (state == State::Beginning || state == State::AfterTwoColons) {
493f678e45dSDimitry Andric // (anonymous namespace)
494f678e45dSDimitry Andric if (ConsumeAnonymousNamespace()) {
495f678e45dSDimitry Andric state = State::AfterIdentifier;
496f678e45dSDimitry Andric break;
497f678e45dSDimitry Andric }
498f678e45dSDimitry Andric }
499f678e45dSDimitry Andric
500f678e45dSDimitry Andric // Type declared inside a function 'func()::Type'
501f678e45dSDimitry Andric if (state != State::AfterIdentifier && state != State::AfterTemplate &&
502f678e45dSDimitry Andric state != State::AfterOperator) {
503f678e45dSDimitry Andric continue_parsing = false;
504f678e45dSDimitry Andric break;
505f678e45dSDimitry Andric }
506f678e45dSDimitry Andric Bookmark l_paren_position = SetBookmark();
507f678e45dSDimitry Andric // Consume the '(' ... ') [const]'.
508f678e45dSDimitry Andric if (!ConsumeArguments()) {
509f678e45dSDimitry Andric continue_parsing = false;
510f678e45dSDimitry Andric break;
511f678e45dSDimitry Andric }
512f678e45dSDimitry Andric SkipFunctionQualifiers();
513f678e45dSDimitry Andric
514f678e45dSDimitry Andric // Consume '::'
515f678e45dSDimitry Andric size_t coloncolon_position = GetCurrentPosition();
516f678e45dSDimitry Andric if (!ConsumeToken(tok::coloncolon)) {
517f678e45dSDimitry Andric continue_parsing = false;
518f678e45dSDimitry Andric break;
519f678e45dSDimitry Andric }
520f678e45dSDimitry Andric l_paren_position.Remove();
521f678e45dSDimitry Andric last_coloncolon_position = coloncolon_position;
522f678e45dSDimitry Andric state = State::AfterTwoColons;
523f678e45dSDimitry Andric break;
524f678e45dSDimitry Andric }
525b40b48b8SDimitry Andric case tok::l_brace:
526b40b48b8SDimitry Andric if (state == State::Beginning || state == State::AfterTwoColons) {
527b40b48b8SDimitry Andric if (ConsumeLambda()) {
528b40b48b8SDimitry Andric state = State::AfterIdentifier;
529b40b48b8SDimitry Andric break;
530b40b48b8SDimitry Andric }
531b40b48b8SDimitry Andric }
532b40b48b8SDimitry Andric continue_parsing = false;
533b40b48b8SDimitry Andric break;
534f678e45dSDimitry Andric case tok::coloncolon: // Type nesting delimiter.
535f678e45dSDimitry Andric if (state != State::Beginning && state != State::AfterIdentifier &&
536f678e45dSDimitry Andric state != State::AfterTemplate) {
537f678e45dSDimitry Andric continue_parsing = false;
538f678e45dSDimitry Andric break;
539f678e45dSDimitry Andric }
540f678e45dSDimitry Andric last_coloncolon_position = GetCurrentPosition();
541f678e45dSDimitry Andric Advance();
542f678e45dSDimitry Andric state = State::AfterTwoColons;
543f678e45dSDimitry Andric break;
544f678e45dSDimitry Andric case tok::less: // Template brackets.
545f678e45dSDimitry Andric if (state != State::AfterIdentifier && state != State::AfterOperator) {
546f678e45dSDimitry Andric continue_parsing = false;
547f678e45dSDimitry Andric break;
548f678e45dSDimitry Andric }
549f678e45dSDimitry Andric if (!ConsumeTemplateArgs()) {
550f678e45dSDimitry Andric continue_parsing = false;
551f678e45dSDimitry Andric break;
552f678e45dSDimitry Andric }
553f678e45dSDimitry Andric state = State::AfterTemplate;
554f678e45dSDimitry Andric break;
555f678e45dSDimitry Andric case tok::kw_operator: // C++ operator overloading.
556f678e45dSDimitry Andric if (state != State::Beginning && state != State::AfterTwoColons) {
557f678e45dSDimitry Andric continue_parsing = false;
558f678e45dSDimitry Andric break;
559f678e45dSDimitry Andric }
560f678e45dSDimitry Andric if (!ConsumeOperator()) {
561f678e45dSDimitry Andric continue_parsing = false;
562f678e45dSDimitry Andric break;
563f678e45dSDimitry Andric }
564f678e45dSDimitry Andric state = State::AfterOperator;
565f678e45dSDimitry Andric break;
566f678e45dSDimitry Andric case tok::tilde: // Destructor.
567f678e45dSDimitry Andric if (state != State::Beginning && state != State::AfterTwoColons) {
568f678e45dSDimitry Andric continue_parsing = false;
569f678e45dSDimitry Andric break;
570f678e45dSDimitry Andric }
571f678e45dSDimitry Andric Advance();
572f678e45dSDimitry Andric if (ConsumeToken(tok::raw_identifier)) {
573f678e45dSDimitry Andric state = State::AfterIdentifier;
574f678e45dSDimitry Andric } else {
575f678e45dSDimitry Andric TakeBack();
576f678e45dSDimitry Andric continue_parsing = false;
577f678e45dSDimitry Andric }
578f678e45dSDimitry Andric break;
579f678e45dSDimitry Andric default:
580f678e45dSDimitry Andric continue_parsing = false;
581f678e45dSDimitry Andric break;
582f678e45dSDimitry Andric }
583f678e45dSDimitry Andric }
584f678e45dSDimitry Andric
585f678e45dSDimitry Andric if (state == State::AfterIdentifier || state == State::AfterOperator ||
586f678e45dSDimitry Andric state == State::AfterTemplate) {
587f678e45dSDimitry Andric ParsedNameRanges result;
588f678e45dSDimitry Andric if (last_coloncolon_position) {
589f678e45dSDimitry Andric result.context_range = Range(start_position.GetSavedPosition(),
590f678e45dSDimitry Andric last_coloncolon_position.getValue());
591f678e45dSDimitry Andric result.basename_range =
592f678e45dSDimitry Andric Range(last_coloncolon_position.getValue() + 1, GetCurrentPosition());
593f678e45dSDimitry Andric } else {
594f678e45dSDimitry Andric result.basename_range =
595f678e45dSDimitry Andric Range(start_position.GetSavedPosition(), GetCurrentPosition());
596f678e45dSDimitry Andric }
597f678e45dSDimitry Andric start_position.Remove();
598f678e45dSDimitry Andric return result;
599f678e45dSDimitry Andric } else {
600f678e45dSDimitry Andric return None;
601f678e45dSDimitry Andric }
602f678e45dSDimitry Andric }
603f678e45dSDimitry Andric
GetTextForRange(const Range & range)604f678e45dSDimitry Andric llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
605f678e45dSDimitry Andric if (range.empty())
606f678e45dSDimitry Andric return llvm::StringRef();
607f678e45dSDimitry Andric assert(range.begin_index < range.end_index);
608f678e45dSDimitry Andric assert(range.begin_index < m_tokens.size());
609f678e45dSDimitry Andric assert(range.end_index <= m_tokens.size());
610f678e45dSDimitry Andric clang::Token &first_token = m_tokens[range.begin_index];
611f678e45dSDimitry Andric clang::Token &last_token = m_tokens[range.end_index - 1];
612f678e45dSDimitry Andric clang::SourceLocation start_loc = first_token.getLocation();
613f678e45dSDimitry Andric clang::SourceLocation end_loc = last_token.getLocation();
614f678e45dSDimitry Andric unsigned start_pos = start_loc.getRawEncoding();
615f678e45dSDimitry Andric unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
616f678e45dSDimitry Andric return m_text.take_front(end_pos).drop_front(start_pos);
617f678e45dSDimitry Andric }
618f678e45dSDimitry Andric
GetLangOptions()619f678e45dSDimitry Andric static const clang::LangOptions &GetLangOptions() {
620f678e45dSDimitry Andric static clang::LangOptions g_options;
621f678e45dSDimitry Andric static llvm::once_flag g_once_flag;
622f678e45dSDimitry Andric llvm::call_once(g_once_flag, []() {
623f678e45dSDimitry Andric g_options.LineComment = true;
624f678e45dSDimitry Andric g_options.C99 = true;
625f678e45dSDimitry Andric g_options.C11 = true;
626f678e45dSDimitry Andric g_options.CPlusPlus = true;
627f678e45dSDimitry Andric g_options.CPlusPlus11 = true;
628f678e45dSDimitry Andric g_options.CPlusPlus14 = true;
629acac075bSDimitry Andric g_options.CPlusPlus17 = true;
630f678e45dSDimitry Andric });
631f678e45dSDimitry Andric return g_options;
632f678e45dSDimitry Andric }
633f678e45dSDimitry Andric
GetKeywordsMap()634f678e45dSDimitry Andric static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
635f678e45dSDimitry Andric static llvm::StringMap<tok::TokenKind> g_map{
636f678e45dSDimitry Andric #define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
637f678e45dSDimitry Andric #include "clang/Basic/TokenKinds.def"
638f678e45dSDimitry Andric #undef KEYWORD
639f678e45dSDimitry Andric };
640f678e45dSDimitry Andric return g_map;
641f678e45dSDimitry Andric }
642f678e45dSDimitry Andric
ExtractTokens()643f678e45dSDimitry Andric void CPlusPlusNameParser::ExtractTokens() {
644f678e45dSDimitry Andric clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
645f678e45dSDimitry Andric m_text.data(), m_text.data() + m_text.size());
646f678e45dSDimitry Andric const auto &kw_map = GetKeywordsMap();
647f678e45dSDimitry Andric clang::Token token;
648f678e45dSDimitry Andric for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
649f678e45dSDimitry Andric lexer.LexFromRawLexer(token)) {
650f678e45dSDimitry Andric if (token.is(clang::tok::raw_identifier)) {
651f678e45dSDimitry Andric auto it = kw_map.find(token.getRawIdentifier());
652f678e45dSDimitry Andric if (it != kw_map.end()) {
653f678e45dSDimitry Andric token.setKind(it->getValue());
654f678e45dSDimitry Andric }
655f678e45dSDimitry Andric }
656f678e45dSDimitry Andric
657f678e45dSDimitry Andric m_tokens.push_back(token);
658f678e45dSDimitry Andric }
659f678e45dSDimitry Andric }
660