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