xref: /src/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1cfca06d7SDimitry Andric //===-- CPlusPlusNameParser.cpp -------------------------------------------===//
274a628f7SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674a628f7SDimitry Andric //
774a628f7SDimitry Andric //===----------------------------------------------------------------------===//
874a628f7SDimitry Andric 
974a628f7SDimitry Andric #include "CPlusPlusNameParser.h"
1074a628f7SDimitry Andric 
1174a628f7SDimitry Andric #include "clang/Basic/IdentifierTable.h"
12e3b55780SDimitry Andric #include "clang/Basic/TokenKinds.h"
1374a628f7SDimitry Andric #include "llvm/ADT/StringMap.h"
1474a628f7SDimitry Andric #include "llvm/Support/Threading.h"
15e3b55780SDimitry Andric #include <optional>
1674a628f7SDimitry Andric 
1774a628f7SDimitry Andric using namespace lldb;
1874a628f7SDimitry Andric using namespace lldb_private;
1974a628f7SDimitry Andric using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
2074a628f7SDimitry Andric using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
2174a628f7SDimitry Andric namespace tok = clang::tok;
2274a628f7SDimitry Andric 
ParseAsFunctionDefinition()23e3b55780SDimitry Andric std::optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
2474a628f7SDimitry Andric   m_next_token_index = 0;
25e3b55780SDimitry Andric   std::optional<ParsedFunction> result(std::nullopt);
2674a628f7SDimitry Andric 
27f73363f1SDimitry Andric   // Try to parse the name as function without a return type specified e.g.
28f73363f1SDimitry Andric   // main(int, char*[])
2974a628f7SDimitry Andric   {
3074a628f7SDimitry Andric     Bookmark start_position = SetBookmark();
3174a628f7SDimitry Andric     result = ParseFunctionImpl(false);
3274a628f7SDimitry Andric     if (result && !HasMoreTokens())
3374a628f7SDimitry Andric       return result;
3474a628f7SDimitry Andric   }
3574a628f7SDimitry Andric 
36f73363f1SDimitry Andric   // Try to parse the name as function with function pointer return type e.g.
37f73363f1SDimitry Andric   // void (*get_func(const char*))()
3874a628f7SDimitry Andric   result = ParseFuncPtr(true);
3974a628f7SDimitry Andric   if (result)
4074a628f7SDimitry Andric     return result;
4174a628f7SDimitry Andric 
4274a628f7SDimitry Andric   // Finally try to parse the name as a function with non-function return type
4374a628f7SDimitry Andric   // e.g. int main(int, char*[])
4474a628f7SDimitry Andric   result = ParseFunctionImpl(true);
4574a628f7SDimitry Andric   if (HasMoreTokens())
46e3b55780SDimitry Andric     return std::nullopt;
4774a628f7SDimitry Andric   return result;
4874a628f7SDimitry Andric }
4974a628f7SDimitry Andric 
ParseAsFullName()50e3b55780SDimitry Andric std::optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
5174a628f7SDimitry Andric   m_next_token_index = 0;
52e3b55780SDimitry Andric   std::optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
5374a628f7SDimitry Andric   if (!name_ranges)
54e3b55780SDimitry Andric     return std::nullopt;
5574a628f7SDimitry Andric   if (HasMoreTokens())
56e3b55780SDimitry Andric     return std::nullopt;
5774a628f7SDimitry Andric   ParsedName result;
58e3b55780SDimitry Andric   result.basename = GetTextForRange(name_ranges->basename_range);
59e3b55780SDimitry Andric   result.context = GetTextForRange(name_ranges->context_range);
6074a628f7SDimitry Andric   return result;
6174a628f7SDimitry Andric }
6274a628f7SDimitry Andric 
HasMoreTokens()6374a628f7SDimitry Andric bool CPlusPlusNameParser::HasMoreTokens() {
6474a628f7SDimitry Andric   return m_next_token_index < m_tokens.size();
6574a628f7SDimitry Andric }
6674a628f7SDimitry Andric 
Advance()6774a628f7SDimitry Andric void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
6874a628f7SDimitry Andric 
TakeBack()6974a628f7SDimitry Andric void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
7074a628f7SDimitry Andric 
ConsumeToken(tok::TokenKind kind)7174a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
7274a628f7SDimitry Andric   if (!HasMoreTokens())
7374a628f7SDimitry Andric     return false;
7474a628f7SDimitry Andric 
7574a628f7SDimitry Andric   if (!Peek().is(kind))
7674a628f7SDimitry Andric     return false;
7774a628f7SDimitry Andric 
7874a628f7SDimitry Andric   Advance();
7974a628f7SDimitry Andric   return true;
8074a628f7SDimitry Andric }
8174a628f7SDimitry Andric 
ConsumeToken(Ts...kinds)8274a628f7SDimitry Andric template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
8374a628f7SDimitry Andric   if (!HasMoreTokens())
8474a628f7SDimitry Andric     return false;
8574a628f7SDimitry Andric 
8674a628f7SDimitry Andric   if (!Peek().isOneOf(kinds...))
8774a628f7SDimitry Andric     return false;
8874a628f7SDimitry Andric 
8974a628f7SDimitry Andric   Advance();
9074a628f7SDimitry Andric   return true;
9174a628f7SDimitry Andric }
9274a628f7SDimitry Andric 
SetBookmark()9374a628f7SDimitry Andric CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
9474a628f7SDimitry Andric   return Bookmark(m_next_token_index);
9574a628f7SDimitry Andric }
9674a628f7SDimitry Andric 
GetCurrentPosition()9774a628f7SDimitry Andric size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
9874a628f7SDimitry Andric 
Peek()9974a628f7SDimitry Andric clang::Token &CPlusPlusNameParser::Peek() {
10074a628f7SDimitry Andric   assert(HasMoreTokens());
10174a628f7SDimitry Andric   return m_tokens[m_next_token_index];
10274a628f7SDimitry Andric }
10374a628f7SDimitry Andric 
104e3b55780SDimitry Andric std::optional<ParsedFunction>
ParseFunctionImpl(bool expect_return_type)10574a628f7SDimitry Andric CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
10674a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
107e3b55780SDimitry Andric 
108e3b55780SDimitry Andric   ParsedFunction result;
10974a628f7SDimitry Andric   if (expect_return_type) {
110e3b55780SDimitry Andric     size_t return_start = GetCurrentPosition();
11174a628f7SDimitry Andric     // Consume return type if it's expected.
112e3b55780SDimitry Andric     if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
113e3b55780SDimitry Andric       return std::nullopt;
114e3b55780SDimitry Andric 
115e3b55780SDimitry Andric     size_t return_end = GetCurrentPosition();
116e3b55780SDimitry Andric     result.return_type = GetTextForRange(Range(return_start, return_end));
11774a628f7SDimitry Andric   }
11874a628f7SDimitry Andric 
11974a628f7SDimitry Andric   auto maybe_name = ParseFullNameImpl();
12074a628f7SDimitry Andric   if (!maybe_name) {
121e3b55780SDimitry Andric     return std::nullopt;
12274a628f7SDimitry Andric   }
12374a628f7SDimitry Andric 
12474a628f7SDimitry Andric   size_t argument_start = GetCurrentPosition();
12574a628f7SDimitry Andric   if (!ConsumeArguments()) {
126e3b55780SDimitry Andric     return std::nullopt;
12774a628f7SDimitry Andric   }
12874a628f7SDimitry Andric 
12974a628f7SDimitry Andric   size_t qualifiers_start = GetCurrentPosition();
13074a628f7SDimitry Andric   SkipFunctionQualifiers();
13174a628f7SDimitry Andric   size_t end_position = GetCurrentPosition();
13274a628f7SDimitry Andric 
133e3b55780SDimitry Andric   result.name.basename = GetTextForRange(maybe_name->basename_range);
134e3b55780SDimitry Andric   result.name.context = GetTextForRange(maybe_name->context_range);
13574a628f7SDimitry Andric   result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
13674a628f7SDimitry Andric   result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
13774a628f7SDimitry Andric   start_position.Remove();
13874a628f7SDimitry Andric   return result;
13974a628f7SDimitry Andric }
14074a628f7SDimitry Andric 
141e3b55780SDimitry Andric std::optional<ParsedFunction>
ParseFuncPtr(bool expect_return_type)14274a628f7SDimitry Andric CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
143e3b55780SDimitry Andric   // This function parses a function definition
144e3b55780SDimitry Andric   // that returns a pointer type.
145e3b55780SDimitry Andric   // E.g., double (*(*func(long))(int))(float)
146e3b55780SDimitry Andric 
147e3b55780SDimitry Andric   // Step 1:
148e3b55780SDimitry Andric   // Remove the return type of the innermost
149e3b55780SDimitry Andric   // function pointer type.
150e3b55780SDimitry Andric   //
151e3b55780SDimitry Andric   // Leaves us with:
152e3b55780SDimitry Andric   //   (*(*func(long))(int))(float)
15374a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
15474a628f7SDimitry Andric   if (expect_return_type) {
15574a628f7SDimitry Andric     // Consume return type.
15674a628f7SDimitry Andric     if (!ConsumeTypename())
157e3b55780SDimitry Andric       return std::nullopt;
15874a628f7SDimitry Andric   }
15974a628f7SDimitry Andric 
160e3b55780SDimitry Andric   // Step 2:
161e3b55780SDimitry Andric   //
162e3b55780SDimitry Andric   // Skip a pointer and parenthesis pair.
163e3b55780SDimitry Andric   //
164e3b55780SDimitry Andric   // Leaves us with:
165e3b55780SDimitry Andric   //   (*func(long))(int))(float)
16674a628f7SDimitry Andric   if (!ConsumeToken(tok::l_paren))
167e3b55780SDimitry Andric     return std::nullopt;
16874a628f7SDimitry Andric   if (!ConsumePtrsAndRefs())
169e3b55780SDimitry Andric     return std::nullopt;
17074a628f7SDimitry Andric 
171e3b55780SDimitry Andric   // Step 3:
172e3b55780SDimitry Andric   //
173e3b55780SDimitry Andric   // Consume inner function name. This will fail unless
174e3b55780SDimitry Andric   // we stripped all the pointers on the left hand side
1757fa27ce4SDimitry Andric   // of the function name.
17674a628f7SDimitry Andric   {
17774a628f7SDimitry Andric     Bookmark before_inner_function_pos = SetBookmark();
17874a628f7SDimitry Andric     auto maybe_inner_function_name = ParseFunctionImpl(false);
17974a628f7SDimitry Andric     if (maybe_inner_function_name)
18074a628f7SDimitry Andric       if (ConsumeToken(tok::r_paren))
18174a628f7SDimitry Andric         if (ConsumeArguments()) {
18274a628f7SDimitry Andric           SkipFunctionQualifiers();
18374a628f7SDimitry Andric           start_position.Remove();
18474a628f7SDimitry Andric           before_inner_function_pos.Remove();
18574a628f7SDimitry Andric           return maybe_inner_function_name;
18674a628f7SDimitry Andric         }
18774a628f7SDimitry Andric   }
18874a628f7SDimitry Andric 
189e3b55780SDimitry Andric   // Step 4:
190e3b55780SDimitry Andric   //
191e3b55780SDimitry Andric   // Parse the remaining string as a function pointer again.
192e3b55780SDimitry Andric   // This time don't consume the inner-most typename since
193e3b55780SDimitry Andric   // we're left with pointers only. This will strip another
194e3b55780SDimitry Andric   // layer of pointers until we're left with the innermost
195e3b55780SDimitry Andric   // function name/argument. I.e., func(long))(int))(float)
196e3b55780SDimitry Andric   //
197e3b55780SDimitry Andric   // Once we successfully stripped all pointers and gotten
198e3b55780SDimitry Andric   // the innermost function name from ParseFunctionImpl above,
199e3b55780SDimitry Andric   // we consume a single ')' and the arguments '(...)' that follows.
200e3b55780SDimitry Andric   //
201e3b55780SDimitry Andric   // Leaves us with:
202e3b55780SDimitry Andric   //   )(float)
203e3b55780SDimitry Andric   //
204e3b55780SDimitry Andric   // This is the remnant of the outer function pointers' arguments.
205e3b55780SDimitry Andric   // Unwinding the recursive calls will remove the remaining
206e3b55780SDimitry Andric   // arguments.
20774a628f7SDimitry Andric   auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
20874a628f7SDimitry Andric   if (maybe_inner_function_ptr_name)
20974a628f7SDimitry Andric     if (ConsumeToken(tok::r_paren))
21074a628f7SDimitry Andric       if (ConsumeArguments()) {
21174a628f7SDimitry Andric         SkipFunctionQualifiers();
21274a628f7SDimitry Andric         start_position.Remove();
21374a628f7SDimitry Andric         return maybe_inner_function_ptr_name;
21474a628f7SDimitry Andric       }
215e3b55780SDimitry Andric 
216e3b55780SDimitry Andric   return std::nullopt;
21774a628f7SDimitry Andric }
21874a628f7SDimitry Andric 
ConsumeArguments()21974a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeArguments() {
22074a628f7SDimitry Andric   return ConsumeBrackets(tok::l_paren, tok::r_paren);
22174a628f7SDimitry Andric }
22274a628f7SDimitry Andric 
ConsumeTemplateArgs()22374a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeTemplateArgs() {
22474a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
22574a628f7SDimitry Andric   if (!HasMoreTokens() || Peek().getKind() != tok::less)
22674a628f7SDimitry Andric     return false;
22774a628f7SDimitry Andric   Advance();
22874a628f7SDimitry Andric 
22974a628f7SDimitry Andric   // Consuming template arguments is a bit trickier than consuming function
230f73363f1SDimitry Andric   // arguments, because '<' '>' brackets are not always trivially balanced. In
231f73363f1SDimitry Andric   // some rare cases tokens '<' and '>' can appear inside template arguments as
232f73363f1SDimitry Andric   // arithmetic or shift operators not as template brackets. Examples:
233f73363f1SDimitry Andric   // std::enable_if<(10u)<(64), bool>
23474a628f7SDimitry Andric   //           f<A<operator<(X,Y)::Subclass>>
235f73363f1SDimitry Andric   // Good thing that compiler makes sure that really ambiguous cases of '>'
236f73363f1SDimitry Andric   // usage should be enclosed within '()' brackets.
23774a628f7SDimitry Andric   int template_counter = 1;
23874a628f7SDimitry Andric   bool can_open_template = false;
23974a628f7SDimitry Andric   while (HasMoreTokens() && template_counter > 0) {
24074a628f7SDimitry Andric     tok::TokenKind kind = Peek().getKind();
24174a628f7SDimitry Andric     switch (kind) {
24274a628f7SDimitry Andric     case tok::greatergreater:
24374a628f7SDimitry Andric       template_counter -= 2;
24474a628f7SDimitry Andric       can_open_template = false;
24574a628f7SDimitry Andric       Advance();
24674a628f7SDimitry Andric       break;
24774a628f7SDimitry Andric     case tok::greater:
24874a628f7SDimitry Andric       --template_counter;
24974a628f7SDimitry Andric       can_open_template = false;
25074a628f7SDimitry Andric       Advance();
25174a628f7SDimitry Andric       break;
25274a628f7SDimitry Andric     case tok::less:
25374a628f7SDimitry Andric       // '<' is an attempt to open a subteamplte
25474a628f7SDimitry Andric       // check if parser is at the point where it's actually possible,
255f73363f1SDimitry Andric       // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No
256f73363f1SDimitry Andric       // need to do the same for '>' because compiler actually makes sure that
257f73363f1SDimitry Andric       // '>' always surrounded by brackets to avoid ambiguity.
25874a628f7SDimitry Andric       if (can_open_template)
25974a628f7SDimitry Andric         ++template_counter;
26074a628f7SDimitry Andric       can_open_template = false;
26174a628f7SDimitry Andric       Advance();
26274a628f7SDimitry Andric       break;
26374a628f7SDimitry Andric     case tok::kw_operator: // C++ operator overloading.
26474a628f7SDimitry Andric       if (!ConsumeOperator())
26574a628f7SDimitry Andric         return false;
26674a628f7SDimitry Andric       can_open_template = true;
26774a628f7SDimitry Andric       break;
26874a628f7SDimitry Andric     case tok::raw_identifier:
26974a628f7SDimitry Andric       can_open_template = true;
27074a628f7SDimitry Andric       Advance();
27174a628f7SDimitry Andric       break;
27274a628f7SDimitry Andric     case tok::l_square:
273e3b55780SDimitry Andric       // Handle templates tagged with an ABI tag.
274e3b55780SDimitry Andric       // An example demangled/prettified version is:
275e3b55780SDimitry Andric       //   func[abi:tag1][abi:tag2]<type[abi:tag3]>(int)
276e3b55780SDimitry Andric       if (ConsumeAbiTag())
277e3b55780SDimitry Andric         can_open_template = true;
278e3b55780SDimitry Andric       else if (ConsumeBrackets(tok::l_square, tok::r_square))
27974a628f7SDimitry Andric         can_open_template = false;
280e3b55780SDimitry Andric       else
281e3b55780SDimitry Andric         return false;
28274a628f7SDimitry Andric       break;
28374a628f7SDimitry Andric     case tok::l_paren:
28474a628f7SDimitry Andric       if (!ConsumeArguments())
28574a628f7SDimitry Andric         return false;
28674a628f7SDimitry Andric       can_open_template = false;
28774a628f7SDimitry Andric       break;
28874a628f7SDimitry Andric     default:
28974a628f7SDimitry Andric       can_open_template = false;
29074a628f7SDimitry Andric       Advance();
29174a628f7SDimitry Andric       break;
29274a628f7SDimitry Andric     }
29374a628f7SDimitry Andric   }
29474a628f7SDimitry Andric 
295f73363f1SDimitry Andric   if (template_counter != 0) {
29674a628f7SDimitry Andric     return false;
29774a628f7SDimitry Andric   }
29874a628f7SDimitry Andric   start_position.Remove();
29974a628f7SDimitry Andric   return true;
30074a628f7SDimitry Andric }
30174a628f7SDimitry Andric 
ConsumeAbiTag()302e3b55780SDimitry Andric bool CPlusPlusNameParser::ConsumeAbiTag() {
303e3b55780SDimitry Andric   Bookmark start_position = SetBookmark();
304e3b55780SDimitry Andric   if (!ConsumeToken(tok::l_square))
305e3b55780SDimitry Andric     return false;
306e3b55780SDimitry Andric 
307e3b55780SDimitry Andric   if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
308e3b55780SDimitry Andric       Peek().getRawIdentifier() == "abi")
309e3b55780SDimitry Andric     Advance();
310e3b55780SDimitry Andric   else
311e3b55780SDimitry Andric     return false;
312e3b55780SDimitry Andric 
313e3b55780SDimitry Andric   if (!ConsumeToken(tok::colon))
314e3b55780SDimitry Andric     return false;
315e3b55780SDimitry Andric 
316e3b55780SDimitry Andric   // Consume the actual tag string (and allow some special characters)
317e3b55780SDimitry Andric   while (ConsumeToken(tok::raw_identifier, tok::comma, tok::period,
318e3b55780SDimitry Andric                       tok::numeric_constant))
319e3b55780SDimitry Andric     ;
320e3b55780SDimitry Andric 
321e3b55780SDimitry Andric   if (!ConsumeToken(tok::r_square))
322e3b55780SDimitry Andric     return false;
323e3b55780SDimitry Andric 
324e3b55780SDimitry Andric   start_position.Remove();
325e3b55780SDimitry Andric   return true;
326e3b55780SDimitry Andric }
327e3b55780SDimitry Andric 
ConsumeAnonymousNamespace()32874a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
32974a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
33074a628f7SDimitry Andric   if (!ConsumeToken(tok::l_paren)) {
33174a628f7SDimitry Andric     return false;
33274a628f7SDimitry Andric   }
33374a628f7SDimitry Andric   constexpr llvm::StringLiteral g_anonymous("anonymous");
33474a628f7SDimitry Andric   if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
33574a628f7SDimitry Andric       Peek().getRawIdentifier() == g_anonymous) {
33674a628f7SDimitry Andric     Advance();
33774a628f7SDimitry Andric   } else {
33874a628f7SDimitry Andric     return false;
33974a628f7SDimitry Andric   }
34074a628f7SDimitry Andric 
34174a628f7SDimitry Andric   if (!ConsumeToken(tok::kw_namespace)) {
34274a628f7SDimitry Andric     return false;
34374a628f7SDimitry Andric   }
34474a628f7SDimitry Andric 
34574a628f7SDimitry Andric   if (!ConsumeToken(tok::r_paren)) {
34674a628f7SDimitry Andric     return false;
34774a628f7SDimitry Andric   }
34874a628f7SDimitry Andric   start_position.Remove();
34974a628f7SDimitry Andric   return true;
35074a628f7SDimitry Andric }
35174a628f7SDimitry Andric 
ConsumeLambda()352a884e649SDimitry Andric bool CPlusPlusNameParser::ConsumeLambda() {
353a884e649SDimitry Andric   Bookmark start_position = SetBookmark();
354a884e649SDimitry Andric   if (!ConsumeToken(tok::l_brace)) {
355a884e649SDimitry Andric     return false;
356a884e649SDimitry Andric   }
357a884e649SDimitry Andric   constexpr llvm::StringLiteral g_lambda("lambda");
358a884e649SDimitry Andric   if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
359a884e649SDimitry Andric       Peek().getRawIdentifier() == g_lambda) {
360a884e649SDimitry Andric     // Put the matched brace back so we can use ConsumeBrackets
361a884e649SDimitry Andric     TakeBack();
362a884e649SDimitry Andric   } else {
363a884e649SDimitry Andric     return false;
364a884e649SDimitry Andric   }
365a884e649SDimitry Andric 
366a884e649SDimitry Andric   if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) {
367a884e649SDimitry Andric     return false;
368a884e649SDimitry Andric   }
369a884e649SDimitry Andric 
370a884e649SDimitry Andric   start_position.Remove();
371a884e649SDimitry Andric   return true;
372a884e649SDimitry Andric }
373a884e649SDimitry Andric 
ConsumeBrackets(tok::TokenKind left,tok::TokenKind right)37474a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
37574a628f7SDimitry Andric                                           tok::TokenKind right) {
37674a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
37774a628f7SDimitry Andric   if (!HasMoreTokens() || Peek().getKind() != left)
37874a628f7SDimitry Andric     return false;
37974a628f7SDimitry Andric   Advance();
38074a628f7SDimitry Andric 
38174a628f7SDimitry Andric   int counter = 1;
38274a628f7SDimitry Andric   while (HasMoreTokens() && counter > 0) {
38374a628f7SDimitry Andric     tok::TokenKind kind = Peek().getKind();
38474a628f7SDimitry Andric     if (kind == right)
38574a628f7SDimitry Andric       --counter;
38674a628f7SDimitry Andric     else if (kind == left)
38774a628f7SDimitry Andric       ++counter;
38874a628f7SDimitry Andric     Advance();
38974a628f7SDimitry Andric   }
39074a628f7SDimitry Andric 
39174a628f7SDimitry Andric   assert(counter >= 0);
39274a628f7SDimitry Andric   if (counter > 0) {
39374a628f7SDimitry Andric     return false;
39474a628f7SDimitry Andric   }
39574a628f7SDimitry Andric   start_position.Remove();
39674a628f7SDimitry Andric   return true;
39774a628f7SDimitry Andric }
39874a628f7SDimitry Andric 
ConsumeOperator()39974a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeOperator() {
40074a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
40174a628f7SDimitry Andric   if (!ConsumeToken(tok::kw_operator))
40274a628f7SDimitry Andric     return false;
40374a628f7SDimitry Andric 
40474a628f7SDimitry Andric   if (!HasMoreTokens()) {
40574a628f7SDimitry Andric     return false;
40674a628f7SDimitry Andric   }
40774a628f7SDimitry Andric 
40874a628f7SDimitry Andric   const auto &token = Peek();
409cfca06d7SDimitry Andric 
410cfca06d7SDimitry Andric   // When clang generates debug info it adds template parameters to names.
411cfca06d7SDimitry Andric   // Since clang doesn't add a space between the name and the template parameter
412cfca06d7SDimitry Andric   // in some cases we are not generating valid C++ names e.g.:
413cfca06d7SDimitry Andric   //
414cfca06d7SDimitry Andric   //   operator<<A::B>
415cfca06d7SDimitry Andric   //
416cfca06d7SDimitry Andric   // In some of these cases we will not parse them correctly. This fixes the
417cfca06d7SDimitry Andric   // issue by detecting this case and inserting tok::less in place of
418cfca06d7SDimitry Andric   // tok::lessless and returning successfully that we consumed the operator.
419cfca06d7SDimitry Andric   if (token.getKind() == tok::lessless) {
420cfca06d7SDimitry Andric     // Make sure we have more tokens before attempting to look ahead one more.
421cfca06d7SDimitry Andric     if (m_next_token_index + 1 < m_tokens.size()) {
422cfca06d7SDimitry Andric       // Look ahead two tokens.
423cfca06d7SDimitry Andric       clang::Token n_token = m_tokens[m_next_token_index + 1];
424cfca06d7SDimitry Andric       // If we find ( or < then this is indeed operator<< no need for fix.
425cfca06d7SDimitry Andric       if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) {
426cfca06d7SDimitry Andric         clang::Token tmp_tok;
427cfca06d7SDimitry Andric         tmp_tok.startToken();
428cfca06d7SDimitry Andric         tmp_tok.setLength(1);
429cfca06d7SDimitry Andric         tmp_tok.setLocation(token.getLocation().getLocWithOffset(1));
430cfca06d7SDimitry Andric         tmp_tok.setKind(tok::less);
431cfca06d7SDimitry Andric 
432cfca06d7SDimitry Andric         m_tokens[m_next_token_index] = tmp_tok;
433cfca06d7SDimitry Andric 
434cfca06d7SDimitry Andric         start_position.Remove();
435cfca06d7SDimitry Andric         return true;
436cfca06d7SDimitry Andric       }
437cfca06d7SDimitry Andric     }
438cfca06d7SDimitry Andric   }
439cfca06d7SDimitry Andric 
44074a628f7SDimitry Andric   switch (token.getKind()) {
44174a628f7SDimitry Andric   case tok::kw_new:
44274a628f7SDimitry Andric   case tok::kw_delete:
44374a628f7SDimitry Andric     // This is 'new' or 'delete' operators.
44474a628f7SDimitry Andric     Advance();
44574a628f7SDimitry Andric     // Check for array new/delete.
44674a628f7SDimitry Andric     if (HasMoreTokens() && Peek().is(tok::l_square)) {
44774a628f7SDimitry Andric       // Consume the '[' and ']'.
44874a628f7SDimitry Andric       if (!ConsumeBrackets(tok::l_square, tok::r_square))
44974a628f7SDimitry Andric         return false;
45074a628f7SDimitry Andric     }
45174a628f7SDimitry Andric     break;
45274a628f7SDimitry Andric 
45374a628f7SDimitry Andric #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \
45474a628f7SDimitry Andric   case tok::Token:                                                             \
45574a628f7SDimitry Andric     Advance();                                                                 \
45674a628f7SDimitry Andric     break;
45774a628f7SDimitry Andric #define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
45874a628f7SDimitry Andric #include "clang/Basic/OperatorKinds.def"
45974a628f7SDimitry Andric #undef OVERLOADED_OPERATOR
46074a628f7SDimitry Andric #undef OVERLOADED_OPERATOR_MULTI
46174a628f7SDimitry Andric 
46274a628f7SDimitry Andric   case tok::l_paren:
46374a628f7SDimitry Andric     // Call operator consume '(' ... ')'.
46474a628f7SDimitry Andric     if (ConsumeBrackets(tok::l_paren, tok::r_paren))
46574a628f7SDimitry Andric       break;
46674a628f7SDimitry Andric     return false;
46774a628f7SDimitry Andric 
46874a628f7SDimitry Andric   case tok::l_square:
46974a628f7SDimitry Andric     // This is a [] operator.
47074a628f7SDimitry Andric     // Consume the '[' and ']'.
47174a628f7SDimitry Andric     if (ConsumeBrackets(tok::l_square, tok::r_square))
47274a628f7SDimitry Andric       break;
47374a628f7SDimitry Andric     return false;
47474a628f7SDimitry Andric 
47574a628f7SDimitry Andric   default:
47674a628f7SDimitry Andric     // This might be a cast operator.
47774a628f7SDimitry Andric     if (ConsumeTypename())
47874a628f7SDimitry Andric       break;
47974a628f7SDimitry Andric     return false;
48074a628f7SDimitry Andric   }
48174a628f7SDimitry Andric   start_position.Remove();
48274a628f7SDimitry Andric   return true;
48374a628f7SDimitry Andric }
48474a628f7SDimitry Andric 
SkipTypeQualifiers()48574a628f7SDimitry Andric void CPlusPlusNameParser::SkipTypeQualifiers() {
48674a628f7SDimitry Andric   while (ConsumeToken(tok::kw_const, tok::kw_volatile))
48774a628f7SDimitry Andric     ;
48874a628f7SDimitry Andric }
48974a628f7SDimitry Andric 
SkipFunctionQualifiers()49074a628f7SDimitry Andric void CPlusPlusNameParser::SkipFunctionQualifiers() {
49174a628f7SDimitry Andric   while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
49274a628f7SDimitry Andric     ;
49374a628f7SDimitry Andric }
49474a628f7SDimitry Andric 
ConsumeBuiltinType()49574a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeBuiltinType() {
49674a628f7SDimitry Andric   bool result = false;
49774a628f7SDimitry Andric   bool continue_parsing = true;
498f73363f1SDimitry Andric   // Built-in types can be made of a few keywords like 'unsigned long long
499f73363f1SDimitry Andric   // int'. This function consumes all built-in type keywords without checking
500f73363f1SDimitry Andric   // if they make sense like 'unsigned char void'.
50174a628f7SDimitry Andric   while (continue_parsing && HasMoreTokens()) {
50274a628f7SDimitry Andric     switch (Peek().getKind()) {
50374a628f7SDimitry Andric     case tok::kw_short:
50474a628f7SDimitry Andric     case tok::kw_long:
50574a628f7SDimitry Andric     case tok::kw___int64:
50674a628f7SDimitry Andric     case tok::kw___int128:
50774a628f7SDimitry Andric     case tok::kw_signed:
50874a628f7SDimitry Andric     case tok::kw_unsigned:
50974a628f7SDimitry Andric     case tok::kw_void:
51074a628f7SDimitry Andric     case tok::kw_char:
51174a628f7SDimitry Andric     case tok::kw_int:
51274a628f7SDimitry Andric     case tok::kw_half:
51374a628f7SDimitry Andric     case tok::kw_float:
51474a628f7SDimitry Andric     case tok::kw_double:
51574a628f7SDimitry Andric     case tok::kw___float128:
51674a628f7SDimitry Andric     case tok::kw_wchar_t:
51774a628f7SDimitry Andric     case tok::kw_bool:
51874a628f7SDimitry Andric     case tok::kw_char16_t:
51974a628f7SDimitry Andric     case tok::kw_char32_t:
52074a628f7SDimitry Andric       result = true;
52174a628f7SDimitry Andric       Advance();
52274a628f7SDimitry Andric       break;
52374a628f7SDimitry Andric     default:
52474a628f7SDimitry Andric       continue_parsing = false;
52574a628f7SDimitry Andric       break;
52674a628f7SDimitry Andric     }
52774a628f7SDimitry Andric   }
52874a628f7SDimitry Andric   return result;
52974a628f7SDimitry Andric }
53074a628f7SDimitry Andric 
SkipPtrsAndRefs()53174a628f7SDimitry Andric void CPlusPlusNameParser::SkipPtrsAndRefs() {
53274a628f7SDimitry Andric   // Ignoring result.
53374a628f7SDimitry Andric   ConsumePtrsAndRefs();
53474a628f7SDimitry Andric }
53574a628f7SDimitry Andric 
ConsumePtrsAndRefs()53674a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
53774a628f7SDimitry Andric   bool found = false;
53874a628f7SDimitry Andric   SkipTypeQualifiers();
53974a628f7SDimitry Andric   while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
54074a628f7SDimitry Andric                       tok::kw_volatile)) {
54174a628f7SDimitry Andric     found = true;
54274a628f7SDimitry Andric     SkipTypeQualifiers();
54374a628f7SDimitry Andric   }
54474a628f7SDimitry Andric   return found;
54574a628f7SDimitry Andric }
54674a628f7SDimitry Andric 
ConsumeDecltype()54774a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeDecltype() {
54874a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
54974a628f7SDimitry Andric   if (!ConsumeToken(tok::kw_decltype))
55074a628f7SDimitry Andric     return false;
55174a628f7SDimitry Andric 
55274a628f7SDimitry Andric   if (!ConsumeArguments())
55374a628f7SDimitry Andric     return false;
55474a628f7SDimitry Andric 
55574a628f7SDimitry Andric   start_position.Remove();
55674a628f7SDimitry Andric   return true;
55774a628f7SDimitry Andric }
55874a628f7SDimitry Andric 
ConsumeTypename()55974a628f7SDimitry Andric bool CPlusPlusNameParser::ConsumeTypename() {
56074a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
56174a628f7SDimitry Andric   SkipTypeQualifiers();
56274a628f7SDimitry Andric   if (!ConsumeBuiltinType() && !ConsumeDecltype()) {
56374a628f7SDimitry Andric     if (!ParseFullNameImpl())
56474a628f7SDimitry Andric       return false;
56574a628f7SDimitry Andric   }
56674a628f7SDimitry Andric   SkipPtrsAndRefs();
56774a628f7SDimitry Andric   start_position.Remove();
56874a628f7SDimitry Andric   return true;
56974a628f7SDimitry Andric }
57074a628f7SDimitry Andric 
571e3b55780SDimitry Andric std::optional<CPlusPlusNameParser::ParsedNameRanges>
ParseFullNameImpl()57274a628f7SDimitry Andric CPlusPlusNameParser::ParseFullNameImpl() {
57374a628f7SDimitry Andric   // Name parsing state machine.
57474a628f7SDimitry Andric   enum class State {
57574a628f7SDimitry Andric     Beginning,       // start of the name
57674a628f7SDimitry Andric     AfterTwoColons,  // right after ::
57774a628f7SDimitry Andric     AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
57874a628f7SDimitry Andric     AfterTemplate,   // right after template brackets (<something>)
57974a628f7SDimitry Andric     AfterOperator,   // right after name of C++ operator
58074a628f7SDimitry Andric   };
58174a628f7SDimitry Andric 
58274a628f7SDimitry Andric   Bookmark start_position = SetBookmark();
58374a628f7SDimitry Andric   State state = State::Beginning;
58474a628f7SDimitry Andric   bool continue_parsing = true;
585e3b55780SDimitry Andric   std::optional<size_t> last_coloncolon_position;
58674a628f7SDimitry Andric 
58774a628f7SDimitry Andric   while (continue_parsing && HasMoreTokens()) {
58874a628f7SDimitry Andric     const auto &token = Peek();
58974a628f7SDimitry Andric     switch (token.getKind()) {
59074a628f7SDimitry Andric     case tok::raw_identifier: // Just a name.
59174a628f7SDimitry Andric       if (state != State::Beginning && state != State::AfterTwoColons) {
59274a628f7SDimitry Andric         continue_parsing = false;
59374a628f7SDimitry Andric         break;
59474a628f7SDimitry Andric       }
59574a628f7SDimitry Andric       Advance();
59674a628f7SDimitry Andric       state = State::AfterIdentifier;
59774a628f7SDimitry Andric       break;
598e3b55780SDimitry Andric     case tok::l_square: {
599e3b55780SDimitry Andric       // Handles types or functions that were tagged
600e3b55780SDimitry Andric       // with, e.g.,
601e3b55780SDimitry Andric       //   [[gnu::abi_tag("tag1","tag2")]] func()
602e3b55780SDimitry Andric       // and demangled/prettified into:
603e3b55780SDimitry Andric       //   func[abi:tag1][abi:tag2]()
604e3b55780SDimitry Andric 
605e3b55780SDimitry Andric       // ABI tags only appear after a method or type name
606e3b55780SDimitry Andric       const bool valid_state =
607e3b55780SDimitry Andric           state == State::AfterIdentifier || state == State::AfterOperator;
608e3b55780SDimitry Andric       if (!valid_state || !ConsumeAbiTag()) {
609e3b55780SDimitry Andric         continue_parsing = false;
610e3b55780SDimitry Andric       }
611e3b55780SDimitry Andric 
612e3b55780SDimitry Andric       break;
613e3b55780SDimitry Andric     }
61474a628f7SDimitry Andric     case tok::l_paren: {
61574a628f7SDimitry Andric       if (state == State::Beginning || state == State::AfterTwoColons) {
61674a628f7SDimitry Andric         // (anonymous namespace)
61774a628f7SDimitry Andric         if (ConsumeAnonymousNamespace()) {
61874a628f7SDimitry Andric           state = State::AfterIdentifier;
61974a628f7SDimitry Andric           break;
62074a628f7SDimitry Andric         }
62174a628f7SDimitry Andric       }
62274a628f7SDimitry Andric 
62374a628f7SDimitry Andric       // Type declared inside a function 'func()::Type'
62474a628f7SDimitry Andric       if (state != State::AfterIdentifier && state != State::AfterTemplate &&
62574a628f7SDimitry Andric           state != State::AfterOperator) {
62674a628f7SDimitry Andric         continue_parsing = false;
62774a628f7SDimitry Andric         break;
62874a628f7SDimitry Andric       }
62974a628f7SDimitry Andric       Bookmark l_paren_position = SetBookmark();
63074a628f7SDimitry Andric       // Consume the '(' ... ') [const]'.
63174a628f7SDimitry Andric       if (!ConsumeArguments()) {
63274a628f7SDimitry Andric         continue_parsing = false;
63374a628f7SDimitry Andric         break;
63474a628f7SDimitry Andric       }
63574a628f7SDimitry Andric       SkipFunctionQualifiers();
63674a628f7SDimitry Andric 
63774a628f7SDimitry Andric       // Consume '::'
63874a628f7SDimitry Andric       size_t coloncolon_position = GetCurrentPosition();
63974a628f7SDimitry Andric       if (!ConsumeToken(tok::coloncolon)) {
64074a628f7SDimitry Andric         continue_parsing = false;
64174a628f7SDimitry Andric         break;
64274a628f7SDimitry Andric       }
64374a628f7SDimitry Andric       l_paren_position.Remove();
64474a628f7SDimitry Andric       last_coloncolon_position = coloncolon_position;
64574a628f7SDimitry Andric       state = State::AfterTwoColons;
64674a628f7SDimitry Andric       break;
64774a628f7SDimitry Andric     }
648a884e649SDimitry Andric     case tok::l_brace:
649a884e649SDimitry Andric       if (state == State::Beginning || state == State::AfterTwoColons) {
650a884e649SDimitry Andric         if (ConsumeLambda()) {
651a884e649SDimitry Andric           state = State::AfterIdentifier;
652a884e649SDimitry Andric           break;
653a884e649SDimitry Andric         }
654a884e649SDimitry Andric       }
655a884e649SDimitry Andric       continue_parsing = false;
656a884e649SDimitry Andric       break;
65774a628f7SDimitry Andric     case tok::coloncolon: // Type nesting delimiter.
65874a628f7SDimitry Andric       if (state != State::Beginning && state != State::AfterIdentifier &&
65974a628f7SDimitry Andric           state != State::AfterTemplate) {
66074a628f7SDimitry Andric         continue_parsing = false;
66174a628f7SDimitry Andric         break;
66274a628f7SDimitry Andric       }
66374a628f7SDimitry Andric       last_coloncolon_position = GetCurrentPosition();
66474a628f7SDimitry Andric       Advance();
66574a628f7SDimitry Andric       state = State::AfterTwoColons;
66674a628f7SDimitry Andric       break;
66774a628f7SDimitry Andric     case tok::less: // Template brackets.
66874a628f7SDimitry Andric       if (state != State::AfterIdentifier && state != State::AfterOperator) {
66974a628f7SDimitry Andric         continue_parsing = false;
67074a628f7SDimitry Andric         break;
67174a628f7SDimitry Andric       }
67274a628f7SDimitry Andric       if (!ConsumeTemplateArgs()) {
67374a628f7SDimitry Andric         continue_parsing = false;
67474a628f7SDimitry Andric         break;
67574a628f7SDimitry Andric       }
67674a628f7SDimitry Andric       state = State::AfterTemplate;
67774a628f7SDimitry Andric       break;
67874a628f7SDimitry Andric     case tok::kw_operator: // C++ operator overloading.
67974a628f7SDimitry Andric       if (state != State::Beginning && state != State::AfterTwoColons) {
68074a628f7SDimitry Andric         continue_parsing = false;
68174a628f7SDimitry Andric         break;
68274a628f7SDimitry Andric       }
68374a628f7SDimitry Andric       if (!ConsumeOperator()) {
68474a628f7SDimitry Andric         continue_parsing = false;
68574a628f7SDimitry Andric         break;
68674a628f7SDimitry Andric       }
68774a628f7SDimitry Andric       state = State::AfterOperator;
68874a628f7SDimitry Andric       break;
68974a628f7SDimitry Andric     case tok::tilde: // Destructor.
69074a628f7SDimitry Andric       if (state != State::Beginning && state != State::AfterTwoColons) {
69174a628f7SDimitry Andric         continue_parsing = false;
69274a628f7SDimitry Andric         break;
69374a628f7SDimitry Andric       }
69474a628f7SDimitry Andric       Advance();
69574a628f7SDimitry Andric       if (ConsumeToken(tok::raw_identifier)) {
69674a628f7SDimitry Andric         state = State::AfterIdentifier;
69774a628f7SDimitry Andric       } else {
69874a628f7SDimitry Andric         TakeBack();
69974a628f7SDimitry Andric         continue_parsing = false;
70074a628f7SDimitry Andric       }
70174a628f7SDimitry Andric       break;
70274a628f7SDimitry Andric     default:
70374a628f7SDimitry Andric       continue_parsing = false;
70474a628f7SDimitry Andric       break;
70574a628f7SDimitry Andric     }
70674a628f7SDimitry Andric   }
70774a628f7SDimitry Andric 
70874a628f7SDimitry Andric   if (state == State::AfterIdentifier || state == State::AfterOperator ||
70974a628f7SDimitry Andric       state == State::AfterTemplate) {
71074a628f7SDimitry Andric     ParsedNameRanges result;
71174a628f7SDimitry Andric     if (last_coloncolon_position) {
712e3b55780SDimitry Andric       result.context_range =
713e3b55780SDimitry Andric           Range(start_position.GetSavedPosition(), *last_coloncolon_position);
71474a628f7SDimitry Andric       result.basename_range =
715e3b55780SDimitry Andric           Range(*last_coloncolon_position + 1, GetCurrentPosition());
71674a628f7SDimitry Andric     } else {
71774a628f7SDimitry Andric       result.basename_range =
71874a628f7SDimitry Andric           Range(start_position.GetSavedPosition(), GetCurrentPosition());
71974a628f7SDimitry Andric     }
72074a628f7SDimitry Andric     start_position.Remove();
72174a628f7SDimitry Andric     return result;
72274a628f7SDimitry Andric   } else {
723e3b55780SDimitry Andric     return std::nullopt;
72474a628f7SDimitry Andric   }
72574a628f7SDimitry Andric }
72674a628f7SDimitry Andric 
GetTextForRange(const Range & range)72774a628f7SDimitry Andric llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
72874a628f7SDimitry Andric   if (range.empty())
72974a628f7SDimitry Andric     return llvm::StringRef();
73074a628f7SDimitry Andric   assert(range.begin_index < range.end_index);
73174a628f7SDimitry Andric   assert(range.begin_index < m_tokens.size());
73274a628f7SDimitry Andric   assert(range.end_index <= m_tokens.size());
73374a628f7SDimitry Andric   clang::Token &first_token = m_tokens[range.begin_index];
73474a628f7SDimitry Andric   clang::Token &last_token = m_tokens[range.end_index - 1];
73574a628f7SDimitry Andric   clang::SourceLocation start_loc = first_token.getLocation();
73674a628f7SDimitry Andric   clang::SourceLocation end_loc = last_token.getLocation();
73774a628f7SDimitry Andric   unsigned start_pos = start_loc.getRawEncoding();
73874a628f7SDimitry Andric   unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
73974a628f7SDimitry Andric   return m_text.take_front(end_pos).drop_front(start_pos);
74074a628f7SDimitry Andric }
74174a628f7SDimitry Andric 
GetLangOptions()74274a628f7SDimitry Andric static const clang::LangOptions &GetLangOptions() {
74374a628f7SDimitry Andric   static clang::LangOptions g_options;
74474a628f7SDimitry Andric   static llvm::once_flag g_once_flag;
74574a628f7SDimitry Andric   llvm::call_once(g_once_flag, []() {
74674a628f7SDimitry Andric     g_options.LineComment = true;
74774a628f7SDimitry Andric     g_options.C99 = true;
74874a628f7SDimitry Andric     g_options.C11 = true;
74974a628f7SDimitry Andric     g_options.CPlusPlus = true;
75074a628f7SDimitry Andric     g_options.CPlusPlus11 = true;
75174a628f7SDimitry Andric     g_options.CPlusPlus14 = true;
752ef5d0b5eSDimitry Andric     g_options.CPlusPlus17 = true;
7537fa27ce4SDimitry Andric     g_options.CPlusPlus20 = true;
75474a628f7SDimitry Andric   });
75574a628f7SDimitry Andric   return g_options;
75674a628f7SDimitry Andric }
75774a628f7SDimitry Andric 
GetKeywordsMap()75874a628f7SDimitry Andric static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
75974a628f7SDimitry Andric   static llvm::StringMap<tok::TokenKind> g_map{
76074a628f7SDimitry Andric #define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
76174a628f7SDimitry Andric #include "clang/Basic/TokenKinds.def"
76274a628f7SDimitry Andric #undef KEYWORD
76374a628f7SDimitry Andric   };
76474a628f7SDimitry Andric   return g_map;
76574a628f7SDimitry Andric }
76674a628f7SDimitry Andric 
ExtractTokens()76774a628f7SDimitry Andric void CPlusPlusNameParser::ExtractTokens() {
7685f29bb8aSDimitry Andric   if (m_text.empty())
7695f29bb8aSDimitry Andric     return;
77074a628f7SDimitry Andric   clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
77174a628f7SDimitry Andric                      m_text.data(), m_text.data() + m_text.size());
77274a628f7SDimitry Andric   const auto &kw_map = GetKeywordsMap();
77374a628f7SDimitry Andric   clang::Token token;
77474a628f7SDimitry Andric   for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
77574a628f7SDimitry Andric        lexer.LexFromRawLexer(token)) {
77674a628f7SDimitry Andric     if (token.is(clang::tok::raw_identifier)) {
77774a628f7SDimitry Andric       auto it = kw_map.find(token.getRawIdentifier());
77874a628f7SDimitry Andric       if (it != kw_map.end()) {
77974a628f7SDimitry Andric         token.setKind(it->getValue());
78074a628f7SDimitry Andric       }
78174a628f7SDimitry Andric     }
78274a628f7SDimitry Andric 
78374a628f7SDimitry Andric     m_tokens.push_back(token);
78474a628f7SDimitry Andric   }
78574a628f7SDimitry Andric }
786