xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
15ffd83dbSDimitry Andric //===-- CPlusPlusNameParser.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "CPlusPlusNameParser.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
12bdd1243dSDimitry Andric #include "clang/Basic/TokenKinds.h"
130b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
140b57cec5SDimitry Andric #include "llvm/Support/Threading.h"
15bdd1243dSDimitry Andric #include <optional>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric using namespace lldb;
180b57cec5SDimitry Andric using namespace lldb_private;
190b57cec5SDimitry Andric using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
200b57cec5SDimitry Andric using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
210b57cec5SDimitry Andric namespace tok = clang::tok;
220b57cec5SDimitry Andric 
ParseAsFunctionDefinition()23bdd1243dSDimitry Andric std::optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
240b57cec5SDimitry Andric   m_next_token_index = 0;
25bdd1243dSDimitry Andric   std::optional<ParsedFunction> result(std::nullopt);
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric   // Try to parse the name as function without a return type specified e.g.
280b57cec5SDimitry Andric   // main(int, char*[])
290b57cec5SDimitry Andric   {
300b57cec5SDimitry Andric     Bookmark start_position = SetBookmark();
310b57cec5SDimitry Andric     result = ParseFunctionImpl(false);
320b57cec5SDimitry Andric     if (result && !HasMoreTokens())
330b57cec5SDimitry Andric       return result;
340b57cec5SDimitry Andric   }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   // Try to parse the name as function with function pointer return type e.g.
370b57cec5SDimitry Andric   // void (*get_func(const char*))()
380b57cec5SDimitry Andric   result = ParseFuncPtr(true);
390b57cec5SDimitry Andric   if (result)
400b57cec5SDimitry Andric     return result;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   // Finally try to parse the name as a function with non-function return type
430b57cec5SDimitry Andric   // e.g. int main(int, char*[])
440b57cec5SDimitry Andric   result = ParseFunctionImpl(true);
450b57cec5SDimitry Andric   if (HasMoreTokens())
46bdd1243dSDimitry Andric     return std::nullopt;
470b57cec5SDimitry Andric   return result;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
ParseAsFullName()50bdd1243dSDimitry Andric std::optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
510b57cec5SDimitry Andric   m_next_token_index = 0;
52bdd1243dSDimitry Andric   std::optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
530b57cec5SDimitry Andric   if (!name_ranges)
54bdd1243dSDimitry Andric     return std::nullopt;
550b57cec5SDimitry Andric   if (HasMoreTokens())
56bdd1243dSDimitry Andric     return std::nullopt;
570b57cec5SDimitry Andric   ParsedName result;
58bdd1243dSDimitry Andric   result.basename = GetTextForRange(name_ranges->basename_range);
59bdd1243dSDimitry Andric   result.context = GetTextForRange(name_ranges->context_range);
600b57cec5SDimitry Andric   return result;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
HasMoreTokens()630b57cec5SDimitry Andric bool CPlusPlusNameParser::HasMoreTokens() {
640b57cec5SDimitry Andric   return m_next_token_index < m_tokens.size();
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
Advance()670b57cec5SDimitry Andric void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
680b57cec5SDimitry Andric 
TakeBack()690b57cec5SDimitry Andric void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
700b57cec5SDimitry Andric 
ConsumeToken(tok::TokenKind kind)710b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
720b57cec5SDimitry Andric   if (!HasMoreTokens())
730b57cec5SDimitry Andric     return false;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   if (!Peek().is(kind))
760b57cec5SDimitry Andric     return false;
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   Advance();
790b57cec5SDimitry Andric   return true;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
ConsumeToken(Ts...kinds)820b57cec5SDimitry Andric template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
830b57cec5SDimitry Andric   if (!HasMoreTokens())
840b57cec5SDimitry Andric     return false;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   if (!Peek().isOneOf(kinds...))
870b57cec5SDimitry Andric     return false;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   Advance();
900b57cec5SDimitry Andric   return true;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
SetBookmark()930b57cec5SDimitry Andric CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
940b57cec5SDimitry Andric   return Bookmark(m_next_token_index);
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
GetCurrentPosition()970b57cec5SDimitry Andric size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
980b57cec5SDimitry Andric 
Peek()990b57cec5SDimitry Andric clang::Token &CPlusPlusNameParser::Peek() {
1000b57cec5SDimitry Andric   assert(HasMoreTokens());
1010b57cec5SDimitry Andric   return m_tokens[m_next_token_index];
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
104bdd1243dSDimitry Andric std::optional<ParsedFunction>
ParseFunctionImpl(bool expect_return_type)1050b57cec5SDimitry Andric CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
1060b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
107bdd1243dSDimitry Andric 
108bdd1243dSDimitry Andric   ParsedFunction result;
1090b57cec5SDimitry Andric   if (expect_return_type) {
110bdd1243dSDimitry Andric     size_t return_start = GetCurrentPosition();
1110b57cec5SDimitry Andric     // Consume return type if it's expected.
112bdd1243dSDimitry Andric     if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
113bdd1243dSDimitry Andric       return std::nullopt;
114bdd1243dSDimitry Andric 
115bdd1243dSDimitry Andric     size_t return_end = GetCurrentPosition();
116bdd1243dSDimitry Andric     result.return_type = GetTextForRange(Range(return_start, return_end));
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   auto maybe_name = ParseFullNameImpl();
1200b57cec5SDimitry Andric   if (!maybe_name) {
121bdd1243dSDimitry Andric     return std::nullopt;
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   size_t argument_start = GetCurrentPosition();
1250b57cec5SDimitry Andric   if (!ConsumeArguments()) {
126bdd1243dSDimitry Andric     return std::nullopt;
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   size_t qualifiers_start = GetCurrentPosition();
1300b57cec5SDimitry Andric   SkipFunctionQualifiers();
1310b57cec5SDimitry Andric   size_t end_position = GetCurrentPosition();
1320b57cec5SDimitry Andric 
133bdd1243dSDimitry Andric   result.name.basename = GetTextForRange(maybe_name->basename_range);
134bdd1243dSDimitry Andric   result.name.context = GetTextForRange(maybe_name->context_range);
1350b57cec5SDimitry Andric   result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
1360b57cec5SDimitry Andric   result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
1370b57cec5SDimitry Andric   start_position.Remove();
1380b57cec5SDimitry Andric   return result;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
141bdd1243dSDimitry Andric std::optional<ParsedFunction>
ParseFuncPtr(bool expect_return_type)1420b57cec5SDimitry Andric CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
143bdd1243dSDimitry Andric   // This function parses a function definition
144bdd1243dSDimitry Andric   // that returns a pointer type.
145bdd1243dSDimitry Andric   // E.g., double (*(*func(long))(int))(float)
146bdd1243dSDimitry Andric 
147bdd1243dSDimitry Andric   // Step 1:
148bdd1243dSDimitry Andric   // Remove the return type of the innermost
149bdd1243dSDimitry Andric   // function pointer type.
150bdd1243dSDimitry Andric   //
151bdd1243dSDimitry Andric   // Leaves us with:
152bdd1243dSDimitry Andric   //   (*(*func(long))(int))(float)
1530b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
1540b57cec5SDimitry Andric   if (expect_return_type) {
1550b57cec5SDimitry Andric     // Consume return type.
1560b57cec5SDimitry Andric     if (!ConsumeTypename())
157bdd1243dSDimitry Andric       return std::nullopt;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
160bdd1243dSDimitry Andric   // Step 2:
161bdd1243dSDimitry Andric   //
162bdd1243dSDimitry Andric   // Skip a pointer and parenthesis pair.
163bdd1243dSDimitry Andric   //
164bdd1243dSDimitry Andric   // Leaves us with:
165bdd1243dSDimitry Andric   //   (*func(long))(int))(float)
1660b57cec5SDimitry Andric   if (!ConsumeToken(tok::l_paren))
167bdd1243dSDimitry Andric     return std::nullopt;
1680b57cec5SDimitry Andric   if (!ConsumePtrsAndRefs())
169bdd1243dSDimitry Andric     return std::nullopt;
1700b57cec5SDimitry Andric 
171bdd1243dSDimitry Andric   // Step 3:
172bdd1243dSDimitry Andric   //
173bdd1243dSDimitry Andric   // Consume inner function name. This will fail unless
174bdd1243dSDimitry Andric   // we stripped all the pointers on the left hand side
175*06c3fb27SDimitry Andric   // of the function name.
1760b57cec5SDimitry Andric   {
1770b57cec5SDimitry Andric     Bookmark before_inner_function_pos = SetBookmark();
1780b57cec5SDimitry Andric     auto maybe_inner_function_name = ParseFunctionImpl(false);
1790b57cec5SDimitry Andric     if (maybe_inner_function_name)
1800b57cec5SDimitry Andric       if (ConsumeToken(tok::r_paren))
1810b57cec5SDimitry Andric         if (ConsumeArguments()) {
1820b57cec5SDimitry Andric           SkipFunctionQualifiers();
1830b57cec5SDimitry Andric           start_position.Remove();
1840b57cec5SDimitry Andric           before_inner_function_pos.Remove();
1850b57cec5SDimitry Andric           return maybe_inner_function_name;
1860b57cec5SDimitry Andric         }
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric 
189bdd1243dSDimitry Andric   // Step 4:
190bdd1243dSDimitry Andric   //
191bdd1243dSDimitry Andric   // Parse the remaining string as a function pointer again.
192bdd1243dSDimitry Andric   // This time don't consume the inner-most typename since
193bdd1243dSDimitry Andric   // we're left with pointers only. This will strip another
194bdd1243dSDimitry Andric   // layer of pointers until we're left with the innermost
195bdd1243dSDimitry Andric   // function name/argument. I.e., func(long))(int))(float)
196bdd1243dSDimitry Andric   //
197bdd1243dSDimitry Andric   // Once we successfully stripped all pointers and gotten
198bdd1243dSDimitry Andric   // the innermost function name from ParseFunctionImpl above,
199bdd1243dSDimitry Andric   // we consume a single ')' and the arguments '(...)' that follows.
200bdd1243dSDimitry Andric   //
201bdd1243dSDimitry Andric   // Leaves us with:
202bdd1243dSDimitry Andric   //   )(float)
203bdd1243dSDimitry Andric   //
204bdd1243dSDimitry Andric   // This is the remnant of the outer function pointers' arguments.
205bdd1243dSDimitry Andric   // Unwinding the recursive calls will remove the remaining
206bdd1243dSDimitry Andric   // arguments.
2070b57cec5SDimitry Andric   auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
2080b57cec5SDimitry Andric   if (maybe_inner_function_ptr_name)
2090b57cec5SDimitry Andric     if (ConsumeToken(tok::r_paren))
2100b57cec5SDimitry Andric       if (ConsumeArguments()) {
2110b57cec5SDimitry Andric         SkipFunctionQualifiers();
2120b57cec5SDimitry Andric         start_position.Remove();
2130b57cec5SDimitry Andric         return maybe_inner_function_ptr_name;
2140b57cec5SDimitry Andric       }
215bdd1243dSDimitry Andric 
216bdd1243dSDimitry Andric   return std::nullopt;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
ConsumeArguments()2190b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeArguments() {
2200b57cec5SDimitry Andric   return ConsumeBrackets(tok::l_paren, tok::r_paren);
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
ConsumeTemplateArgs()2230b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeTemplateArgs() {
2240b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
2250b57cec5SDimitry Andric   if (!HasMoreTokens() || Peek().getKind() != tok::less)
2260b57cec5SDimitry Andric     return false;
2270b57cec5SDimitry Andric   Advance();
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   // Consuming template arguments is a bit trickier than consuming function
2300b57cec5SDimitry Andric   // arguments, because '<' '>' brackets are not always trivially balanced. In
2310b57cec5SDimitry Andric   // some rare cases tokens '<' and '>' can appear inside template arguments as
2320b57cec5SDimitry Andric   // arithmetic or shift operators not as template brackets. Examples:
2330b57cec5SDimitry Andric   // std::enable_if<(10u)<(64), bool>
2340b57cec5SDimitry Andric   //           f<A<operator<(X,Y)::Subclass>>
2350b57cec5SDimitry Andric   // Good thing that compiler makes sure that really ambiguous cases of '>'
2360b57cec5SDimitry Andric   // usage should be enclosed within '()' brackets.
2370b57cec5SDimitry Andric   int template_counter = 1;
2380b57cec5SDimitry Andric   bool can_open_template = false;
2390b57cec5SDimitry Andric   while (HasMoreTokens() && template_counter > 0) {
2400b57cec5SDimitry Andric     tok::TokenKind kind = Peek().getKind();
2410b57cec5SDimitry Andric     switch (kind) {
2420b57cec5SDimitry Andric     case tok::greatergreater:
2430b57cec5SDimitry Andric       template_counter -= 2;
2440b57cec5SDimitry Andric       can_open_template = false;
2450b57cec5SDimitry Andric       Advance();
2460b57cec5SDimitry Andric       break;
2470b57cec5SDimitry Andric     case tok::greater:
2480b57cec5SDimitry Andric       --template_counter;
2490b57cec5SDimitry Andric       can_open_template = false;
2500b57cec5SDimitry Andric       Advance();
2510b57cec5SDimitry Andric       break;
2520b57cec5SDimitry Andric     case tok::less:
2530b57cec5SDimitry Andric       // '<' is an attempt to open a subteamplte
2540b57cec5SDimitry Andric       // check if parser is at the point where it's actually possible,
2550b57cec5SDimitry Andric       // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No
2560b57cec5SDimitry Andric       // need to do the same for '>' because compiler actually makes sure that
2570b57cec5SDimitry Andric       // '>' always surrounded by brackets to avoid ambiguity.
2580b57cec5SDimitry Andric       if (can_open_template)
2590b57cec5SDimitry Andric         ++template_counter;
2600b57cec5SDimitry Andric       can_open_template = false;
2610b57cec5SDimitry Andric       Advance();
2620b57cec5SDimitry Andric       break;
2630b57cec5SDimitry Andric     case tok::kw_operator: // C++ operator overloading.
2640b57cec5SDimitry Andric       if (!ConsumeOperator())
2650b57cec5SDimitry Andric         return false;
2660b57cec5SDimitry Andric       can_open_template = true;
2670b57cec5SDimitry Andric       break;
2680b57cec5SDimitry Andric     case tok::raw_identifier:
2690b57cec5SDimitry Andric       can_open_template = true;
2700b57cec5SDimitry Andric       Advance();
2710b57cec5SDimitry Andric       break;
2720b57cec5SDimitry Andric     case tok::l_square:
273bdd1243dSDimitry Andric       // Handle templates tagged with an ABI tag.
274bdd1243dSDimitry Andric       // An example demangled/prettified version is:
275bdd1243dSDimitry Andric       //   func[abi:tag1][abi:tag2]<type[abi:tag3]>(int)
276bdd1243dSDimitry Andric       if (ConsumeAbiTag())
277bdd1243dSDimitry Andric         can_open_template = true;
278bdd1243dSDimitry Andric       else if (ConsumeBrackets(tok::l_square, tok::r_square))
2790b57cec5SDimitry Andric         can_open_template = false;
280bdd1243dSDimitry Andric       else
281bdd1243dSDimitry Andric         return false;
2820b57cec5SDimitry Andric       break;
2830b57cec5SDimitry Andric     case tok::l_paren:
2840b57cec5SDimitry Andric       if (!ConsumeArguments())
2850b57cec5SDimitry Andric         return false;
2860b57cec5SDimitry Andric       can_open_template = false;
2870b57cec5SDimitry Andric       break;
2880b57cec5SDimitry Andric     default:
2890b57cec5SDimitry Andric       can_open_template = false;
2900b57cec5SDimitry Andric       Advance();
2910b57cec5SDimitry Andric       break;
2920b57cec5SDimitry Andric     }
2930b57cec5SDimitry Andric   }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   if (template_counter != 0) {
2960b57cec5SDimitry Andric     return false;
2970b57cec5SDimitry Andric   }
2980b57cec5SDimitry Andric   start_position.Remove();
2990b57cec5SDimitry Andric   return true;
3000b57cec5SDimitry Andric }
3010b57cec5SDimitry Andric 
ConsumeAbiTag()302bdd1243dSDimitry Andric bool CPlusPlusNameParser::ConsumeAbiTag() {
303bdd1243dSDimitry Andric   Bookmark start_position = SetBookmark();
304bdd1243dSDimitry Andric   if (!ConsumeToken(tok::l_square))
305bdd1243dSDimitry Andric     return false;
306bdd1243dSDimitry Andric 
307bdd1243dSDimitry Andric   if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
308bdd1243dSDimitry Andric       Peek().getRawIdentifier() == "abi")
309bdd1243dSDimitry Andric     Advance();
310bdd1243dSDimitry Andric   else
311bdd1243dSDimitry Andric     return false;
312bdd1243dSDimitry Andric 
313bdd1243dSDimitry Andric   if (!ConsumeToken(tok::colon))
314bdd1243dSDimitry Andric     return false;
315bdd1243dSDimitry Andric 
316bdd1243dSDimitry Andric   // Consume the actual tag string (and allow some special characters)
317bdd1243dSDimitry Andric   while (ConsumeToken(tok::raw_identifier, tok::comma, tok::period,
318bdd1243dSDimitry Andric                       tok::numeric_constant))
319bdd1243dSDimitry Andric     ;
320bdd1243dSDimitry Andric 
321bdd1243dSDimitry Andric   if (!ConsumeToken(tok::r_square))
322bdd1243dSDimitry Andric     return false;
323bdd1243dSDimitry Andric 
324bdd1243dSDimitry Andric   start_position.Remove();
325bdd1243dSDimitry Andric   return true;
326bdd1243dSDimitry Andric }
327bdd1243dSDimitry Andric 
ConsumeAnonymousNamespace()3280b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
3290b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
3300b57cec5SDimitry Andric   if (!ConsumeToken(tok::l_paren)) {
3310b57cec5SDimitry Andric     return false;
3320b57cec5SDimitry Andric   }
3330b57cec5SDimitry Andric   constexpr llvm::StringLiteral g_anonymous("anonymous");
3340b57cec5SDimitry Andric   if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
3350b57cec5SDimitry Andric       Peek().getRawIdentifier() == g_anonymous) {
3360b57cec5SDimitry Andric     Advance();
3370b57cec5SDimitry Andric   } else {
3380b57cec5SDimitry Andric     return false;
3390b57cec5SDimitry Andric   }
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   if (!ConsumeToken(tok::kw_namespace)) {
3420b57cec5SDimitry Andric     return false;
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   if (!ConsumeToken(tok::r_paren)) {
3460b57cec5SDimitry Andric     return false;
3470b57cec5SDimitry Andric   }
3480b57cec5SDimitry Andric   start_position.Remove();
3490b57cec5SDimitry Andric   return true;
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric 
ConsumeLambda()3520b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeLambda() {
3530b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
3540b57cec5SDimitry Andric   if (!ConsumeToken(tok::l_brace)) {
3550b57cec5SDimitry Andric     return false;
3560b57cec5SDimitry Andric   }
3570b57cec5SDimitry Andric   constexpr llvm::StringLiteral g_lambda("lambda");
3580b57cec5SDimitry Andric   if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
3590b57cec5SDimitry Andric       Peek().getRawIdentifier() == g_lambda) {
3600b57cec5SDimitry Andric     // Put the matched brace back so we can use ConsumeBrackets
3610b57cec5SDimitry Andric     TakeBack();
3620b57cec5SDimitry Andric   } else {
3630b57cec5SDimitry Andric     return false;
3640b57cec5SDimitry Andric   }
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) {
3670b57cec5SDimitry Andric     return false;
3680b57cec5SDimitry Andric   }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   start_position.Remove();
3710b57cec5SDimitry Andric   return true;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric 
ConsumeBrackets(tok::TokenKind left,tok::TokenKind right)3740b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
3750b57cec5SDimitry Andric                                           tok::TokenKind right) {
3760b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
3770b57cec5SDimitry Andric   if (!HasMoreTokens() || Peek().getKind() != left)
3780b57cec5SDimitry Andric     return false;
3790b57cec5SDimitry Andric   Advance();
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   int counter = 1;
3820b57cec5SDimitry Andric   while (HasMoreTokens() && counter > 0) {
3830b57cec5SDimitry Andric     tok::TokenKind kind = Peek().getKind();
3840b57cec5SDimitry Andric     if (kind == right)
3850b57cec5SDimitry Andric       --counter;
3860b57cec5SDimitry Andric     else if (kind == left)
3870b57cec5SDimitry Andric       ++counter;
3880b57cec5SDimitry Andric     Advance();
3890b57cec5SDimitry Andric   }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   assert(counter >= 0);
3920b57cec5SDimitry Andric   if (counter > 0) {
3930b57cec5SDimitry Andric     return false;
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric   start_position.Remove();
3960b57cec5SDimitry Andric   return true;
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
ConsumeOperator()3990b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeOperator() {
4000b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
4010b57cec5SDimitry Andric   if (!ConsumeToken(tok::kw_operator))
4020b57cec5SDimitry Andric     return false;
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   if (!HasMoreTokens()) {
4050b57cec5SDimitry Andric     return false;
4060b57cec5SDimitry Andric   }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   const auto &token = Peek();
4095ffd83dbSDimitry Andric 
4105ffd83dbSDimitry Andric   // When clang generates debug info it adds template parameters to names.
4115ffd83dbSDimitry Andric   // Since clang doesn't add a space between the name and the template parameter
4125ffd83dbSDimitry Andric   // in some cases we are not generating valid C++ names e.g.:
4135ffd83dbSDimitry Andric   //
4145ffd83dbSDimitry Andric   //   operator<<A::B>
4155ffd83dbSDimitry Andric   //
4165ffd83dbSDimitry Andric   // In some of these cases we will not parse them correctly. This fixes the
4175ffd83dbSDimitry Andric   // issue by detecting this case and inserting tok::less in place of
4185ffd83dbSDimitry Andric   // tok::lessless and returning successfully that we consumed the operator.
4195ffd83dbSDimitry Andric   if (token.getKind() == tok::lessless) {
4205ffd83dbSDimitry Andric     // Make sure we have more tokens before attempting to look ahead one more.
4215ffd83dbSDimitry Andric     if (m_next_token_index + 1 < m_tokens.size()) {
4225ffd83dbSDimitry Andric       // Look ahead two tokens.
4235ffd83dbSDimitry Andric       clang::Token n_token = m_tokens[m_next_token_index + 1];
4245ffd83dbSDimitry Andric       // If we find ( or < then this is indeed operator<< no need for fix.
4255ffd83dbSDimitry Andric       if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) {
4265ffd83dbSDimitry Andric         clang::Token tmp_tok;
4275ffd83dbSDimitry Andric         tmp_tok.startToken();
4285ffd83dbSDimitry Andric         tmp_tok.setLength(1);
4295ffd83dbSDimitry Andric         tmp_tok.setLocation(token.getLocation().getLocWithOffset(1));
4305ffd83dbSDimitry Andric         tmp_tok.setKind(tok::less);
4315ffd83dbSDimitry Andric 
4325ffd83dbSDimitry Andric         m_tokens[m_next_token_index] = tmp_tok;
4335ffd83dbSDimitry Andric 
4345ffd83dbSDimitry Andric         start_position.Remove();
4355ffd83dbSDimitry Andric         return true;
4365ffd83dbSDimitry Andric       }
4375ffd83dbSDimitry Andric     }
4385ffd83dbSDimitry Andric   }
4395ffd83dbSDimitry Andric 
4400b57cec5SDimitry Andric   switch (token.getKind()) {
4410b57cec5SDimitry Andric   case tok::kw_new:
4420b57cec5SDimitry Andric   case tok::kw_delete:
4430b57cec5SDimitry Andric     // This is 'new' or 'delete' operators.
4440b57cec5SDimitry Andric     Advance();
4450b57cec5SDimitry Andric     // Check for array new/delete.
4460b57cec5SDimitry Andric     if (HasMoreTokens() && Peek().is(tok::l_square)) {
4470b57cec5SDimitry Andric       // Consume the '[' and ']'.
4480b57cec5SDimitry Andric       if (!ConsumeBrackets(tok::l_square, tok::r_square))
4490b57cec5SDimitry Andric         return false;
4500b57cec5SDimitry Andric     }
4510b57cec5SDimitry Andric     break;
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \
4540b57cec5SDimitry Andric   case tok::Token:                                                             \
4550b57cec5SDimitry Andric     Advance();                                                                 \
4560b57cec5SDimitry Andric     break;
4570b57cec5SDimitry Andric #define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
4580b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.def"
4590b57cec5SDimitry Andric #undef OVERLOADED_OPERATOR
4600b57cec5SDimitry Andric #undef OVERLOADED_OPERATOR_MULTI
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   case tok::l_paren:
4630b57cec5SDimitry Andric     // Call operator consume '(' ... ')'.
4640b57cec5SDimitry Andric     if (ConsumeBrackets(tok::l_paren, tok::r_paren))
4650b57cec5SDimitry Andric       break;
4660b57cec5SDimitry Andric     return false;
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   case tok::l_square:
4690b57cec5SDimitry Andric     // This is a [] operator.
4700b57cec5SDimitry Andric     // Consume the '[' and ']'.
4710b57cec5SDimitry Andric     if (ConsumeBrackets(tok::l_square, tok::r_square))
4720b57cec5SDimitry Andric       break;
4730b57cec5SDimitry Andric     return false;
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric   default:
4760b57cec5SDimitry Andric     // This might be a cast operator.
4770b57cec5SDimitry Andric     if (ConsumeTypename())
4780b57cec5SDimitry Andric       break;
4790b57cec5SDimitry Andric     return false;
4800b57cec5SDimitry Andric   }
4810b57cec5SDimitry Andric   start_position.Remove();
4820b57cec5SDimitry Andric   return true;
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric 
SkipTypeQualifiers()4850b57cec5SDimitry Andric void CPlusPlusNameParser::SkipTypeQualifiers() {
4860b57cec5SDimitry Andric   while (ConsumeToken(tok::kw_const, tok::kw_volatile))
4870b57cec5SDimitry Andric     ;
4880b57cec5SDimitry Andric }
4890b57cec5SDimitry Andric 
SkipFunctionQualifiers()4900b57cec5SDimitry Andric void CPlusPlusNameParser::SkipFunctionQualifiers() {
4910b57cec5SDimitry Andric   while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
4920b57cec5SDimitry Andric     ;
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric 
ConsumeBuiltinType()4950b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeBuiltinType() {
4960b57cec5SDimitry Andric   bool result = false;
4970b57cec5SDimitry Andric   bool continue_parsing = true;
4980b57cec5SDimitry Andric   // Built-in types can be made of a few keywords like 'unsigned long long
4990b57cec5SDimitry Andric   // int'. This function consumes all built-in type keywords without checking
5000b57cec5SDimitry Andric   // if they make sense like 'unsigned char void'.
5010b57cec5SDimitry Andric   while (continue_parsing && HasMoreTokens()) {
5020b57cec5SDimitry Andric     switch (Peek().getKind()) {
5030b57cec5SDimitry Andric     case tok::kw_short:
5040b57cec5SDimitry Andric     case tok::kw_long:
5050b57cec5SDimitry Andric     case tok::kw___int64:
5060b57cec5SDimitry Andric     case tok::kw___int128:
5070b57cec5SDimitry Andric     case tok::kw_signed:
5080b57cec5SDimitry Andric     case tok::kw_unsigned:
5090b57cec5SDimitry Andric     case tok::kw_void:
5100b57cec5SDimitry Andric     case tok::kw_char:
5110b57cec5SDimitry Andric     case tok::kw_int:
5120b57cec5SDimitry Andric     case tok::kw_half:
5130b57cec5SDimitry Andric     case tok::kw_float:
5140b57cec5SDimitry Andric     case tok::kw_double:
5150b57cec5SDimitry Andric     case tok::kw___float128:
5160b57cec5SDimitry Andric     case tok::kw_wchar_t:
5170b57cec5SDimitry Andric     case tok::kw_bool:
5180b57cec5SDimitry Andric     case tok::kw_char16_t:
5190b57cec5SDimitry Andric     case tok::kw_char32_t:
5200b57cec5SDimitry Andric       result = true;
5210b57cec5SDimitry Andric       Advance();
5220b57cec5SDimitry Andric       break;
5230b57cec5SDimitry Andric     default:
5240b57cec5SDimitry Andric       continue_parsing = false;
5250b57cec5SDimitry Andric       break;
5260b57cec5SDimitry Andric     }
5270b57cec5SDimitry Andric   }
5280b57cec5SDimitry Andric   return result;
5290b57cec5SDimitry Andric }
5300b57cec5SDimitry Andric 
SkipPtrsAndRefs()5310b57cec5SDimitry Andric void CPlusPlusNameParser::SkipPtrsAndRefs() {
5320b57cec5SDimitry Andric   // Ignoring result.
5330b57cec5SDimitry Andric   ConsumePtrsAndRefs();
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric 
ConsumePtrsAndRefs()5360b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
5370b57cec5SDimitry Andric   bool found = false;
5380b57cec5SDimitry Andric   SkipTypeQualifiers();
5390b57cec5SDimitry Andric   while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
5400b57cec5SDimitry Andric                       tok::kw_volatile)) {
5410b57cec5SDimitry Andric     found = true;
5420b57cec5SDimitry Andric     SkipTypeQualifiers();
5430b57cec5SDimitry Andric   }
5440b57cec5SDimitry Andric   return found;
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric 
ConsumeDecltype()5470b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeDecltype() {
5480b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
5490b57cec5SDimitry Andric   if (!ConsumeToken(tok::kw_decltype))
5500b57cec5SDimitry Andric     return false;
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric   if (!ConsumeArguments())
5530b57cec5SDimitry Andric     return false;
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   start_position.Remove();
5560b57cec5SDimitry Andric   return true;
5570b57cec5SDimitry Andric }
5580b57cec5SDimitry Andric 
ConsumeTypename()5590b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeTypename() {
5600b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
5610b57cec5SDimitry Andric   SkipTypeQualifiers();
5620b57cec5SDimitry Andric   if (!ConsumeBuiltinType() && !ConsumeDecltype()) {
5630b57cec5SDimitry Andric     if (!ParseFullNameImpl())
5640b57cec5SDimitry Andric       return false;
5650b57cec5SDimitry Andric   }
5660b57cec5SDimitry Andric   SkipPtrsAndRefs();
5670b57cec5SDimitry Andric   start_position.Remove();
5680b57cec5SDimitry Andric   return true;
5690b57cec5SDimitry Andric }
5700b57cec5SDimitry Andric 
571bdd1243dSDimitry Andric std::optional<CPlusPlusNameParser::ParsedNameRanges>
ParseFullNameImpl()5720b57cec5SDimitry Andric CPlusPlusNameParser::ParseFullNameImpl() {
5730b57cec5SDimitry Andric   // Name parsing state machine.
5740b57cec5SDimitry Andric   enum class State {
5750b57cec5SDimitry Andric     Beginning,       // start of the name
5760b57cec5SDimitry Andric     AfterTwoColons,  // right after ::
5770b57cec5SDimitry Andric     AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
5780b57cec5SDimitry Andric     AfterTemplate,   // right after template brackets (<something>)
5790b57cec5SDimitry Andric     AfterOperator,   // right after name of C++ operator
5800b57cec5SDimitry Andric   };
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric   Bookmark start_position = SetBookmark();
5830b57cec5SDimitry Andric   State state = State::Beginning;
5840b57cec5SDimitry Andric   bool continue_parsing = true;
585bdd1243dSDimitry Andric   std::optional<size_t> last_coloncolon_position;
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   while (continue_parsing && HasMoreTokens()) {
5880b57cec5SDimitry Andric     const auto &token = Peek();
5890b57cec5SDimitry Andric     switch (token.getKind()) {
5900b57cec5SDimitry Andric     case tok::raw_identifier: // Just a name.
5910b57cec5SDimitry Andric       if (state != State::Beginning && state != State::AfterTwoColons) {
5920b57cec5SDimitry Andric         continue_parsing = false;
5930b57cec5SDimitry Andric         break;
5940b57cec5SDimitry Andric       }
5950b57cec5SDimitry Andric       Advance();
5960b57cec5SDimitry Andric       state = State::AfterIdentifier;
5970b57cec5SDimitry Andric       break;
598bdd1243dSDimitry Andric     case tok::l_square: {
599bdd1243dSDimitry Andric       // Handles types or functions that were tagged
600bdd1243dSDimitry Andric       // with, e.g.,
601bdd1243dSDimitry Andric       //   [[gnu::abi_tag("tag1","tag2")]] func()
602bdd1243dSDimitry Andric       // and demangled/prettified into:
603bdd1243dSDimitry Andric       //   func[abi:tag1][abi:tag2]()
604bdd1243dSDimitry Andric 
605bdd1243dSDimitry Andric       // ABI tags only appear after a method or type name
606bdd1243dSDimitry Andric       const bool valid_state =
607bdd1243dSDimitry Andric           state == State::AfterIdentifier || state == State::AfterOperator;
608bdd1243dSDimitry Andric       if (!valid_state || !ConsumeAbiTag()) {
609bdd1243dSDimitry Andric         continue_parsing = false;
610bdd1243dSDimitry Andric       }
611bdd1243dSDimitry Andric 
612bdd1243dSDimitry Andric       break;
613bdd1243dSDimitry Andric     }
6140b57cec5SDimitry Andric     case tok::l_paren: {
6150b57cec5SDimitry Andric       if (state == State::Beginning || state == State::AfterTwoColons) {
6160b57cec5SDimitry Andric         // (anonymous namespace)
6170b57cec5SDimitry Andric         if (ConsumeAnonymousNamespace()) {
6180b57cec5SDimitry Andric           state = State::AfterIdentifier;
6190b57cec5SDimitry Andric           break;
6200b57cec5SDimitry Andric         }
6210b57cec5SDimitry Andric       }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric       // Type declared inside a function 'func()::Type'
6240b57cec5SDimitry Andric       if (state != State::AfterIdentifier && state != State::AfterTemplate &&
6250b57cec5SDimitry Andric           state != State::AfterOperator) {
6260b57cec5SDimitry Andric         continue_parsing = false;
6270b57cec5SDimitry Andric         break;
6280b57cec5SDimitry Andric       }
6290b57cec5SDimitry Andric       Bookmark l_paren_position = SetBookmark();
6300b57cec5SDimitry Andric       // Consume the '(' ... ') [const]'.
6310b57cec5SDimitry Andric       if (!ConsumeArguments()) {
6320b57cec5SDimitry Andric         continue_parsing = false;
6330b57cec5SDimitry Andric         break;
6340b57cec5SDimitry Andric       }
6350b57cec5SDimitry Andric       SkipFunctionQualifiers();
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric       // Consume '::'
6380b57cec5SDimitry Andric       size_t coloncolon_position = GetCurrentPosition();
6390b57cec5SDimitry Andric       if (!ConsumeToken(tok::coloncolon)) {
6400b57cec5SDimitry Andric         continue_parsing = false;
6410b57cec5SDimitry Andric         break;
6420b57cec5SDimitry Andric       }
6430b57cec5SDimitry Andric       l_paren_position.Remove();
6440b57cec5SDimitry Andric       last_coloncolon_position = coloncolon_position;
6450b57cec5SDimitry Andric       state = State::AfterTwoColons;
6460b57cec5SDimitry Andric       break;
6470b57cec5SDimitry Andric     }
6480b57cec5SDimitry Andric     case tok::l_brace:
6490b57cec5SDimitry Andric       if (state == State::Beginning || state == State::AfterTwoColons) {
6500b57cec5SDimitry Andric         if (ConsumeLambda()) {
6510b57cec5SDimitry Andric           state = State::AfterIdentifier;
6520b57cec5SDimitry Andric           break;
6530b57cec5SDimitry Andric         }
6540b57cec5SDimitry Andric       }
6550b57cec5SDimitry Andric       continue_parsing = false;
6560b57cec5SDimitry Andric       break;
6570b57cec5SDimitry Andric     case tok::coloncolon: // Type nesting delimiter.
6580b57cec5SDimitry Andric       if (state != State::Beginning && state != State::AfterIdentifier &&
6590b57cec5SDimitry Andric           state != State::AfterTemplate) {
6600b57cec5SDimitry Andric         continue_parsing = false;
6610b57cec5SDimitry Andric         break;
6620b57cec5SDimitry Andric       }
6630b57cec5SDimitry Andric       last_coloncolon_position = GetCurrentPosition();
6640b57cec5SDimitry Andric       Advance();
6650b57cec5SDimitry Andric       state = State::AfterTwoColons;
6660b57cec5SDimitry Andric       break;
6670b57cec5SDimitry Andric     case tok::less: // Template brackets.
6680b57cec5SDimitry Andric       if (state != State::AfterIdentifier && state != State::AfterOperator) {
6690b57cec5SDimitry Andric         continue_parsing = false;
6700b57cec5SDimitry Andric         break;
6710b57cec5SDimitry Andric       }
6720b57cec5SDimitry Andric       if (!ConsumeTemplateArgs()) {
6730b57cec5SDimitry Andric         continue_parsing = false;
6740b57cec5SDimitry Andric         break;
6750b57cec5SDimitry Andric       }
6760b57cec5SDimitry Andric       state = State::AfterTemplate;
6770b57cec5SDimitry Andric       break;
6780b57cec5SDimitry Andric     case tok::kw_operator: // C++ operator overloading.
6790b57cec5SDimitry Andric       if (state != State::Beginning && state != State::AfterTwoColons) {
6800b57cec5SDimitry Andric         continue_parsing = false;
6810b57cec5SDimitry Andric         break;
6820b57cec5SDimitry Andric       }
6830b57cec5SDimitry Andric       if (!ConsumeOperator()) {
6840b57cec5SDimitry Andric         continue_parsing = false;
6850b57cec5SDimitry Andric         break;
6860b57cec5SDimitry Andric       }
6870b57cec5SDimitry Andric       state = State::AfterOperator;
6880b57cec5SDimitry Andric       break;
6890b57cec5SDimitry Andric     case tok::tilde: // Destructor.
6900b57cec5SDimitry Andric       if (state != State::Beginning && state != State::AfterTwoColons) {
6910b57cec5SDimitry Andric         continue_parsing = false;
6920b57cec5SDimitry Andric         break;
6930b57cec5SDimitry Andric       }
6940b57cec5SDimitry Andric       Advance();
6950b57cec5SDimitry Andric       if (ConsumeToken(tok::raw_identifier)) {
6960b57cec5SDimitry Andric         state = State::AfterIdentifier;
6970b57cec5SDimitry Andric       } else {
6980b57cec5SDimitry Andric         TakeBack();
6990b57cec5SDimitry Andric         continue_parsing = false;
7000b57cec5SDimitry Andric       }
7010b57cec5SDimitry Andric       break;
7020b57cec5SDimitry Andric     default:
7030b57cec5SDimitry Andric       continue_parsing = false;
7040b57cec5SDimitry Andric       break;
7050b57cec5SDimitry Andric     }
7060b57cec5SDimitry Andric   }
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric   if (state == State::AfterIdentifier || state == State::AfterOperator ||
7090b57cec5SDimitry Andric       state == State::AfterTemplate) {
7100b57cec5SDimitry Andric     ParsedNameRanges result;
7110b57cec5SDimitry Andric     if (last_coloncolon_position) {
712bdd1243dSDimitry Andric       result.context_range =
713bdd1243dSDimitry Andric           Range(start_position.GetSavedPosition(), *last_coloncolon_position);
7140b57cec5SDimitry Andric       result.basename_range =
715bdd1243dSDimitry Andric           Range(*last_coloncolon_position + 1, GetCurrentPosition());
7160b57cec5SDimitry Andric     } else {
7170b57cec5SDimitry Andric       result.basename_range =
7180b57cec5SDimitry Andric           Range(start_position.GetSavedPosition(), GetCurrentPosition());
7190b57cec5SDimitry Andric     }
7200b57cec5SDimitry Andric     start_position.Remove();
7210b57cec5SDimitry Andric     return result;
7220b57cec5SDimitry Andric   } else {
723bdd1243dSDimitry Andric     return std::nullopt;
7240b57cec5SDimitry Andric   }
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric 
GetTextForRange(const Range & range)7270b57cec5SDimitry Andric llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
7280b57cec5SDimitry Andric   if (range.empty())
7290b57cec5SDimitry Andric     return llvm::StringRef();
7300b57cec5SDimitry Andric   assert(range.begin_index < range.end_index);
7310b57cec5SDimitry Andric   assert(range.begin_index < m_tokens.size());
7320b57cec5SDimitry Andric   assert(range.end_index <= m_tokens.size());
7330b57cec5SDimitry Andric   clang::Token &first_token = m_tokens[range.begin_index];
7340b57cec5SDimitry Andric   clang::Token &last_token = m_tokens[range.end_index - 1];
7350b57cec5SDimitry Andric   clang::SourceLocation start_loc = first_token.getLocation();
7360b57cec5SDimitry Andric   clang::SourceLocation end_loc = last_token.getLocation();
7370b57cec5SDimitry Andric   unsigned start_pos = start_loc.getRawEncoding();
7380b57cec5SDimitry Andric   unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
7390b57cec5SDimitry Andric   return m_text.take_front(end_pos).drop_front(start_pos);
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric 
GetLangOptions()7420b57cec5SDimitry Andric static const clang::LangOptions &GetLangOptions() {
7430b57cec5SDimitry Andric   static clang::LangOptions g_options;
7440b57cec5SDimitry Andric   static llvm::once_flag g_once_flag;
7450b57cec5SDimitry Andric   llvm::call_once(g_once_flag, []() {
7460b57cec5SDimitry Andric     g_options.LineComment = true;
7470b57cec5SDimitry Andric     g_options.C99 = true;
7480b57cec5SDimitry Andric     g_options.C11 = true;
7490b57cec5SDimitry Andric     g_options.CPlusPlus = true;
7500b57cec5SDimitry Andric     g_options.CPlusPlus11 = true;
7510b57cec5SDimitry Andric     g_options.CPlusPlus14 = true;
7520b57cec5SDimitry Andric     g_options.CPlusPlus17 = true;
753*06c3fb27SDimitry Andric     g_options.CPlusPlus20 = true;
7540b57cec5SDimitry Andric   });
7550b57cec5SDimitry Andric   return g_options;
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric 
GetKeywordsMap()7580b57cec5SDimitry Andric static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
7590b57cec5SDimitry Andric   static llvm::StringMap<tok::TokenKind> g_map{
7600b57cec5SDimitry Andric #define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
7610b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.def"
7620b57cec5SDimitry Andric #undef KEYWORD
7630b57cec5SDimitry Andric   };
7640b57cec5SDimitry Andric   return g_map;
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric 
ExtractTokens()7670b57cec5SDimitry Andric void CPlusPlusNameParser::ExtractTokens() {
7680b57cec5SDimitry Andric   if (m_text.empty())
7690b57cec5SDimitry Andric     return;
7700b57cec5SDimitry Andric   clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
7710b57cec5SDimitry Andric                      m_text.data(), m_text.data() + m_text.size());
7720b57cec5SDimitry Andric   const auto &kw_map = GetKeywordsMap();
7730b57cec5SDimitry Andric   clang::Token token;
7740b57cec5SDimitry Andric   for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
7750b57cec5SDimitry Andric        lexer.LexFromRawLexer(token)) {
7760b57cec5SDimitry Andric     if (token.is(clang::tok::raw_identifier)) {
7770b57cec5SDimitry Andric       auto it = kw_map.find(token.getRawIdentifier());
7780b57cec5SDimitry Andric       if (it != kw_map.end()) {
7790b57cec5SDimitry Andric         token.setKind(it->getValue());
7800b57cec5SDimitry Andric       }
7810b57cec5SDimitry Andric     }
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric     m_tokens.push_back(token);
7840b57cec5SDimitry Andric   }
7850b57cec5SDimitry Andric }
786