15ffd83dbSDimitry Andric //===-- CPlusPlusNameParser.cpp -------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "CPlusPlusNameParser.h" 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h" 12bdd1243dSDimitry Andric #include "clang/Basic/TokenKinds.h" 13*0b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h" 14*0b57cec5SDimitry Andric #include "llvm/Support/Threading.h" 15bdd1243dSDimitry Andric #include <optional> 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric using namespace lldb; 18*0b57cec5SDimitry Andric using namespace lldb_private; 19*0b57cec5SDimitry Andric using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction; 20*0b57cec5SDimitry Andric using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName; 21*0b57cec5SDimitry Andric namespace tok = clang::tok; 22*0b57cec5SDimitry Andric 23bdd1243dSDimitry Andric std::optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() { 24*0b57cec5SDimitry Andric m_next_token_index = 0; 25bdd1243dSDimitry Andric std::optional<ParsedFunction> result(std::nullopt); 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric // Try to parse the name as function without a return type specified e.g. 28*0b57cec5SDimitry Andric // main(int, char*[]) 29*0b57cec5SDimitry Andric { 30*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 31*0b57cec5SDimitry Andric result = ParseFunctionImpl(false); 32*0b57cec5SDimitry Andric if (result && !HasMoreTokens()) 33*0b57cec5SDimitry Andric return result; 34*0b57cec5SDimitry Andric } 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric // Try to parse the name as function with function pointer return type e.g. 37*0b57cec5SDimitry Andric // void (*get_func(const char*))() 38*0b57cec5SDimitry Andric result = ParseFuncPtr(true); 39*0b57cec5SDimitry Andric if (result) 40*0b57cec5SDimitry Andric return result; 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric // Finally try to parse the name as a function with non-function return type 43*0b57cec5SDimitry Andric // e.g. int main(int, char*[]) 44*0b57cec5SDimitry Andric result = ParseFunctionImpl(true); 45*0b57cec5SDimitry Andric if (HasMoreTokens()) 46bdd1243dSDimitry Andric return std::nullopt; 47*0b57cec5SDimitry Andric return result; 48*0b57cec5SDimitry Andric } 49*0b57cec5SDimitry Andric 50bdd1243dSDimitry Andric std::optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() { 51*0b57cec5SDimitry Andric m_next_token_index = 0; 52bdd1243dSDimitry Andric std::optional<ParsedNameRanges> name_ranges = ParseFullNameImpl(); 53*0b57cec5SDimitry Andric if (!name_ranges) 54bdd1243dSDimitry Andric return std::nullopt; 55*0b57cec5SDimitry Andric if (HasMoreTokens()) 56bdd1243dSDimitry Andric return std::nullopt; 57*0b57cec5SDimitry Andric ParsedName result; 58bdd1243dSDimitry Andric result.basename = GetTextForRange(name_ranges->basename_range); 59bdd1243dSDimitry Andric result.context = GetTextForRange(name_ranges->context_range); 60*0b57cec5SDimitry Andric return result; 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric bool CPlusPlusNameParser::HasMoreTokens() { 64*0b57cec5SDimitry Andric return m_next_token_index < m_tokens.size(); 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric void CPlusPlusNameParser::Advance() { ++m_next_token_index; } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric void CPlusPlusNameParser::TakeBack() { --m_next_token_index; } 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) { 72*0b57cec5SDimitry Andric if (!HasMoreTokens()) 73*0b57cec5SDimitry Andric return false; 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric if (!Peek().is(kind)) 76*0b57cec5SDimitry Andric return false; 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric Advance(); 79*0b57cec5SDimitry Andric return true; 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) { 83*0b57cec5SDimitry Andric if (!HasMoreTokens()) 84*0b57cec5SDimitry Andric return false; 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric if (!Peek().isOneOf(kinds...)) 87*0b57cec5SDimitry Andric return false; 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric Advance(); 90*0b57cec5SDimitry Andric return true; 91*0b57cec5SDimitry Andric } 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() { 94*0b57cec5SDimitry Andric return Bookmark(m_next_token_index); 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; } 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric clang::Token &CPlusPlusNameParser::Peek() { 100*0b57cec5SDimitry Andric assert(HasMoreTokens()); 101*0b57cec5SDimitry Andric return m_tokens[m_next_token_index]; 102*0b57cec5SDimitry Andric } 103*0b57cec5SDimitry Andric 104bdd1243dSDimitry Andric std::optional<ParsedFunction> 105*0b57cec5SDimitry Andric CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) { 106*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 107bdd1243dSDimitry Andric 108bdd1243dSDimitry Andric ParsedFunction result; 109*0b57cec5SDimitry Andric if (expect_return_type) { 110bdd1243dSDimitry Andric size_t return_start = GetCurrentPosition(); 111*0b57cec5SDimitry 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)); 117*0b57cec5SDimitry Andric } 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric auto maybe_name = ParseFullNameImpl(); 120*0b57cec5SDimitry Andric if (!maybe_name) { 121bdd1243dSDimitry Andric return std::nullopt; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric size_t argument_start = GetCurrentPosition(); 125*0b57cec5SDimitry Andric if (!ConsumeArguments()) { 126bdd1243dSDimitry Andric return std::nullopt; 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric size_t qualifiers_start = GetCurrentPosition(); 130*0b57cec5SDimitry Andric SkipFunctionQualifiers(); 131*0b57cec5SDimitry Andric size_t end_position = GetCurrentPosition(); 132*0b57cec5SDimitry Andric 133bdd1243dSDimitry Andric result.name.basename = GetTextForRange(maybe_name->basename_range); 134bdd1243dSDimitry Andric result.name.context = GetTextForRange(maybe_name->context_range); 135*0b57cec5SDimitry Andric result.arguments = GetTextForRange(Range(argument_start, qualifiers_start)); 136*0b57cec5SDimitry Andric result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position)); 137*0b57cec5SDimitry Andric start_position.Remove(); 138*0b57cec5SDimitry Andric return result; 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 141bdd1243dSDimitry Andric std::optional<ParsedFunction> 142*0b57cec5SDimitry 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) 153*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 154*0b57cec5SDimitry Andric if (expect_return_type) { 155*0b57cec5SDimitry Andric // Consume return type. 156*0b57cec5SDimitry Andric if (!ConsumeTypename()) 157bdd1243dSDimitry Andric return std::nullopt; 158*0b57cec5SDimitry Andric } 159*0b57cec5SDimitry 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) 166*0b57cec5SDimitry Andric if (!ConsumeToken(tok::l_paren)) 167bdd1243dSDimitry Andric return std::nullopt; 168*0b57cec5SDimitry Andric if (!ConsumePtrsAndRefs()) 169bdd1243dSDimitry Andric return std::nullopt; 170*0b57cec5SDimitry 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 175bdd1243dSDimitry Andric // of the funciton name. 176*0b57cec5SDimitry Andric { 177*0b57cec5SDimitry Andric Bookmark before_inner_function_pos = SetBookmark(); 178*0b57cec5SDimitry Andric auto maybe_inner_function_name = ParseFunctionImpl(false); 179*0b57cec5SDimitry Andric if (maybe_inner_function_name) 180*0b57cec5SDimitry Andric if (ConsumeToken(tok::r_paren)) 181*0b57cec5SDimitry Andric if (ConsumeArguments()) { 182*0b57cec5SDimitry Andric SkipFunctionQualifiers(); 183*0b57cec5SDimitry Andric start_position.Remove(); 184*0b57cec5SDimitry Andric before_inner_function_pos.Remove(); 185*0b57cec5SDimitry Andric return maybe_inner_function_name; 186*0b57cec5SDimitry Andric } 187*0b57cec5SDimitry Andric } 188*0b57cec5SDimitry 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. 207*0b57cec5SDimitry Andric auto maybe_inner_function_ptr_name = ParseFuncPtr(false); 208*0b57cec5SDimitry Andric if (maybe_inner_function_ptr_name) 209*0b57cec5SDimitry Andric if (ConsumeToken(tok::r_paren)) 210*0b57cec5SDimitry Andric if (ConsumeArguments()) { 211*0b57cec5SDimitry Andric SkipFunctionQualifiers(); 212*0b57cec5SDimitry Andric start_position.Remove(); 213*0b57cec5SDimitry Andric return maybe_inner_function_ptr_name; 214*0b57cec5SDimitry Andric } 215bdd1243dSDimitry Andric 216bdd1243dSDimitry Andric return std::nullopt; 217*0b57cec5SDimitry Andric } 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeArguments() { 220*0b57cec5SDimitry Andric return ConsumeBrackets(tok::l_paren, tok::r_paren); 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeTemplateArgs() { 224*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 225*0b57cec5SDimitry Andric if (!HasMoreTokens() || Peek().getKind() != tok::less) 226*0b57cec5SDimitry Andric return false; 227*0b57cec5SDimitry Andric Advance(); 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric // Consuming template arguments is a bit trickier than consuming function 230*0b57cec5SDimitry Andric // arguments, because '<' '>' brackets are not always trivially balanced. In 231*0b57cec5SDimitry Andric // some rare cases tokens '<' and '>' can appear inside template arguments as 232*0b57cec5SDimitry Andric // arithmetic or shift operators not as template brackets. Examples: 233*0b57cec5SDimitry Andric // std::enable_if<(10u)<(64), bool> 234*0b57cec5SDimitry Andric // f<A<operator<(X,Y)::Subclass>> 235*0b57cec5SDimitry Andric // Good thing that compiler makes sure that really ambiguous cases of '>' 236*0b57cec5SDimitry Andric // usage should be enclosed within '()' brackets. 237*0b57cec5SDimitry Andric int template_counter = 1; 238*0b57cec5SDimitry Andric bool can_open_template = false; 239*0b57cec5SDimitry Andric while (HasMoreTokens() && template_counter > 0) { 240*0b57cec5SDimitry Andric tok::TokenKind kind = Peek().getKind(); 241*0b57cec5SDimitry Andric switch (kind) { 242*0b57cec5SDimitry Andric case tok::greatergreater: 243*0b57cec5SDimitry Andric template_counter -= 2; 244*0b57cec5SDimitry Andric can_open_template = false; 245*0b57cec5SDimitry Andric Advance(); 246*0b57cec5SDimitry Andric break; 247*0b57cec5SDimitry Andric case tok::greater: 248*0b57cec5SDimitry Andric --template_counter; 249*0b57cec5SDimitry Andric can_open_template = false; 250*0b57cec5SDimitry Andric Advance(); 251*0b57cec5SDimitry Andric break; 252*0b57cec5SDimitry Andric case tok::less: 253*0b57cec5SDimitry Andric // '<' is an attempt to open a subteamplte 254*0b57cec5SDimitry Andric // check if parser is at the point where it's actually possible, 255*0b57cec5SDimitry Andric // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No 256*0b57cec5SDimitry Andric // need to do the same for '>' because compiler actually makes sure that 257*0b57cec5SDimitry Andric // '>' always surrounded by brackets to avoid ambiguity. 258*0b57cec5SDimitry Andric if (can_open_template) 259*0b57cec5SDimitry Andric ++template_counter; 260*0b57cec5SDimitry Andric can_open_template = false; 261*0b57cec5SDimitry Andric Advance(); 262*0b57cec5SDimitry Andric break; 263*0b57cec5SDimitry Andric case tok::kw_operator: // C++ operator overloading. 264*0b57cec5SDimitry Andric if (!ConsumeOperator()) 265*0b57cec5SDimitry Andric return false; 266*0b57cec5SDimitry Andric can_open_template = true; 267*0b57cec5SDimitry Andric break; 268*0b57cec5SDimitry Andric case tok::raw_identifier: 269*0b57cec5SDimitry Andric can_open_template = true; 270*0b57cec5SDimitry Andric Advance(); 271*0b57cec5SDimitry Andric break; 272*0b57cec5SDimitry 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)) 279*0b57cec5SDimitry Andric can_open_template = false; 280bdd1243dSDimitry Andric else 281bdd1243dSDimitry Andric return false; 282*0b57cec5SDimitry Andric break; 283*0b57cec5SDimitry Andric case tok::l_paren: 284*0b57cec5SDimitry Andric if (!ConsumeArguments()) 285*0b57cec5SDimitry Andric return false; 286*0b57cec5SDimitry Andric can_open_template = false; 287*0b57cec5SDimitry Andric break; 288*0b57cec5SDimitry Andric default: 289*0b57cec5SDimitry Andric can_open_template = false; 290*0b57cec5SDimitry Andric Advance(); 291*0b57cec5SDimitry Andric break; 292*0b57cec5SDimitry Andric } 293*0b57cec5SDimitry Andric } 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric if (template_counter != 0) { 296*0b57cec5SDimitry Andric return false; 297*0b57cec5SDimitry Andric } 298*0b57cec5SDimitry Andric start_position.Remove(); 299*0b57cec5SDimitry Andric return true; 300*0b57cec5SDimitry Andric } 301*0b57cec5SDimitry Andric 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 328*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeAnonymousNamespace() { 329*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 330*0b57cec5SDimitry Andric if (!ConsumeToken(tok::l_paren)) { 331*0b57cec5SDimitry Andric return false; 332*0b57cec5SDimitry Andric } 333*0b57cec5SDimitry Andric constexpr llvm::StringLiteral g_anonymous("anonymous"); 334*0b57cec5SDimitry Andric if (HasMoreTokens() && Peek().is(tok::raw_identifier) && 335*0b57cec5SDimitry Andric Peek().getRawIdentifier() == g_anonymous) { 336*0b57cec5SDimitry Andric Advance(); 337*0b57cec5SDimitry Andric } else { 338*0b57cec5SDimitry Andric return false; 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric if (!ConsumeToken(tok::kw_namespace)) { 342*0b57cec5SDimitry Andric return false; 343*0b57cec5SDimitry Andric } 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric if (!ConsumeToken(tok::r_paren)) { 346*0b57cec5SDimitry Andric return false; 347*0b57cec5SDimitry Andric } 348*0b57cec5SDimitry Andric start_position.Remove(); 349*0b57cec5SDimitry Andric return true; 350*0b57cec5SDimitry Andric } 351*0b57cec5SDimitry Andric 352*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeLambda() { 353*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 354*0b57cec5SDimitry Andric if (!ConsumeToken(tok::l_brace)) { 355*0b57cec5SDimitry Andric return false; 356*0b57cec5SDimitry Andric } 357*0b57cec5SDimitry Andric constexpr llvm::StringLiteral g_lambda("lambda"); 358*0b57cec5SDimitry Andric if (HasMoreTokens() && Peek().is(tok::raw_identifier) && 359*0b57cec5SDimitry Andric Peek().getRawIdentifier() == g_lambda) { 360*0b57cec5SDimitry Andric // Put the matched brace back so we can use ConsumeBrackets 361*0b57cec5SDimitry Andric TakeBack(); 362*0b57cec5SDimitry Andric } else { 363*0b57cec5SDimitry Andric return false; 364*0b57cec5SDimitry Andric } 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) { 367*0b57cec5SDimitry Andric return false; 368*0b57cec5SDimitry Andric } 369*0b57cec5SDimitry Andric 370*0b57cec5SDimitry Andric start_position.Remove(); 371*0b57cec5SDimitry Andric return true; 372*0b57cec5SDimitry Andric } 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left, 375*0b57cec5SDimitry Andric tok::TokenKind right) { 376*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 377*0b57cec5SDimitry Andric if (!HasMoreTokens() || Peek().getKind() != left) 378*0b57cec5SDimitry Andric return false; 379*0b57cec5SDimitry Andric Advance(); 380*0b57cec5SDimitry Andric 381*0b57cec5SDimitry Andric int counter = 1; 382*0b57cec5SDimitry Andric while (HasMoreTokens() && counter > 0) { 383*0b57cec5SDimitry Andric tok::TokenKind kind = Peek().getKind(); 384*0b57cec5SDimitry Andric if (kind == right) 385*0b57cec5SDimitry Andric --counter; 386*0b57cec5SDimitry Andric else if (kind == left) 387*0b57cec5SDimitry Andric ++counter; 388*0b57cec5SDimitry Andric Advance(); 389*0b57cec5SDimitry Andric } 390*0b57cec5SDimitry Andric 391*0b57cec5SDimitry Andric assert(counter >= 0); 392*0b57cec5SDimitry Andric if (counter > 0) { 393*0b57cec5SDimitry Andric return false; 394*0b57cec5SDimitry Andric } 395*0b57cec5SDimitry Andric start_position.Remove(); 396*0b57cec5SDimitry Andric return true; 397*0b57cec5SDimitry Andric } 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeOperator() { 400*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 401*0b57cec5SDimitry Andric if (!ConsumeToken(tok::kw_operator)) 402*0b57cec5SDimitry Andric return false; 403*0b57cec5SDimitry Andric 404*0b57cec5SDimitry Andric if (!HasMoreTokens()) { 405*0b57cec5SDimitry Andric return false; 406*0b57cec5SDimitry Andric } 407*0b57cec5SDimitry Andric 408*0b57cec5SDimitry 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 440*0b57cec5SDimitry Andric switch (token.getKind()) { 441*0b57cec5SDimitry Andric case tok::kw_new: 442*0b57cec5SDimitry Andric case tok::kw_delete: 443*0b57cec5SDimitry Andric // This is 'new' or 'delete' operators. 444*0b57cec5SDimitry Andric Advance(); 445*0b57cec5SDimitry Andric // Check for array new/delete. 446*0b57cec5SDimitry Andric if (HasMoreTokens() && Peek().is(tok::l_square)) { 447*0b57cec5SDimitry Andric // Consume the '[' and ']'. 448*0b57cec5SDimitry Andric if (!ConsumeBrackets(tok::l_square, tok::r_square)) 449*0b57cec5SDimitry Andric return false; 450*0b57cec5SDimitry Andric } 451*0b57cec5SDimitry Andric break; 452*0b57cec5SDimitry Andric 453*0b57cec5SDimitry Andric #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ 454*0b57cec5SDimitry Andric case tok::Token: \ 455*0b57cec5SDimitry Andric Advance(); \ 456*0b57cec5SDimitry Andric break; 457*0b57cec5SDimitry Andric #define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly) 458*0b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.def" 459*0b57cec5SDimitry Andric #undef OVERLOADED_OPERATOR 460*0b57cec5SDimitry Andric #undef OVERLOADED_OPERATOR_MULTI 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric case tok::l_paren: 463*0b57cec5SDimitry Andric // Call operator consume '(' ... ')'. 464*0b57cec5SDimitry Andric if (ConsumeBrackets(tok::l_paren, tok::r_paren)) 465*0b57cec5SDimitry Andric break; 466*0b57cec5SDimitry Andric return false; 467*0b57cec5SDimitry Andric 468*0b57cec5SDimitry Andric case tok::l_square: 469*0b57cec5SDimitry Andric // This is a [] operator. 470*0b57cec5SDimitry Andric // Consume the '[' and ']'. 471*0b57cec5SDimitry Andric if (ConsumeBrackets(tok::l_square, tok::r_square)) 472*0b57cec5SDimitry Andric break; 473*0b57cec5SDimitry Andric return false; 474*0b57cec5SDimitry Andric 475*0b57cec5SDimitry Andric default: 476*0b57cec5SDimitry Andric // This might be a cast operator. 477*0b57cec5SDimitry Andric if (ConsumeTypename()) 478*0b57cec5SDimitry Andric break; 479*0b57cec5SDimitry Andric return false; 480*0b57cec5SDimitry Andric } 481*0b57cec5SDimitry Andric start_position.Remove(); 482*0b57cec5SDimitry Andric return true; 483*0b57cec5SDimitry Andric } 484*0b57cec5SDimitry Andric 485*0b57cec5SDimitry Andric void CPlusPlusNameParser::SkipTypeQualifiers() { 486*0b57cec5SDimitry Andric while (ConsumeToken(tok::kw_const, tok::kw_volatile)) 487*0b57cec5SDimitry Andric ; 488*0b57cec5SDimitry Andric } 489*0b57cec5SDimitry Andric 490*0b57cec5SDimitry Andric void CPlusPlusNameParser::SkipFunctionQualifiers() { 491*0b57cec5SDimitry Andric while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp)) 492*0b57cec5SDimitry Andric ; 493*0b57cec5SDimitry Andric } 494*0b57cec5SDimitry Andric 495*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeBuiltinType() { 496*0b57cec5SDimitry Andric bool result = false; 497*0b57cec5SDimitry Andric bool continue_parsing = true; 498*0b57cec5SDimitry Andric // Built-in types can be made of a few keywords like 'unsigned long long 499*0b57cec5SDimitry Andric // int'. This function consumes all built-in type keywords without checking 500*0b57cec5SDimitry Andric // if they make sense like 'unsigned char void'. 501*0b57cec5SDimitry Andric while (continue_parsing && HasMoreTokens()) { 502*0b57cec5SDimitry Andric switch (Peek().getKind()) { 503*0b57cec5SDimitry Andric case tok::kw_short: 504*0b57cec5SDimitry Andric case tok::kw_long: 505*0b57cec5SDimitry Andric case tok::kw___int64: 506*0b57cec5SDimitry Andric case tok::kw___int128: 507*0b57cec5SDimitry Andric case tok::kw_signed: 508*0b57cec5SDimitry Andric case tok::kw_unsigned: 509*0b57cec5SDimitry Andric case tok::kw_void: 510*0b57cec5SDimitry Andric case tok::kw_char: 511*0b57cec5SDimitry Andric case tok::kw_int: 512*0b57cec5SDimitry Andric case tok::kw_half: 513*0b57cec5SDimitry Andric case tok::kw_float: 514*0b57cec5SDimitry Andric case tok::kw_double: 515*0b57cec5SDimitry Andric case tok::kw___float128: 516*0b57cec5SDimitry Andric case tok::kw_wchar_t: 517*0b57cec5SDimitry Andric case tok::kw_bool: 518*0b57cec5SDimitry Andric case tok::kw_char16_t: 519*0b57cec5SDimitry Andric case tok::kw_char32_t: 520*0b57cec5SDimitry Andric result = true; 521*0b57cec5SDimitry Andric Advance(); 522*0b57cec5SDimitry Andric break; 523*0b57cec5SDimitry Andric default: 524*0b57cec5SDimitry Andric continue_parsing = false; 525*0b57cec5SDimitry Andric break; 526*0b57cec5SDimitry Andric } 527*0b57cec5SDimitry Andric } 528*0b57cec5SDimitry Andric return result; 529*0b57cec5SDimitry Andric } 530*0b57cec5SDimitry Andric 531*0b57cec5SDimitry Andric void CPlusPlusNameParser::SkipPtrsAndRefs() { 532*0b57cec5SDimitry Andric // Ignoring result. 533*0b57cec5SDimitry Andric ConsumePtrsAndRefs(); 534*0b57cec5SDimitry Andric } 535*0b57cec5SDimitry Andric 536*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumePtrsAndRefs() { 537*0b57cec5SDimitry Andric bool found = false; 538*0b57cec5SDimitry Andric SkipTypeQualifiers(); 539*0b57cec5SDimitry Andric while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const, 540*0b57cec5SDimitry Andric tok::kw_volatile)) { 541*0b57cec5SDimitry Andric found = true; 542*0b57cec5SDimitry Andric SkipTypeQualifiers(); 543*0b57cec5SDimitry Andric } 544*0b57cec5SDimitry Andric return found; 545*0b57cec5SDimitry Andric } 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeDecltype() { 548*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 549*0b57cec5SDimitry Andric if (!ConsumeToken(tok::kw_decltype)) 550*0b57cec5SDimitry Andric return false; 551*0b57cec5SDimitry Andric 552*0b57cec5SDimitry Andric if (!ConsumeArguments()) 553*0b57cec5SDimitry Andric return false; 554*0b57cec5SDimitry Andric 555*0b57cec5SDimitry Andric start_position.Remove(); 556*0b57cec5SDimitry Andric return true; 557*0b57cec5SDimitry Andric } 558*0b57cec5SDimitry Andric 559*0b57cec5SDimitry Andric bool CPlusPlusNameParser::ConsumeTypename() { 560*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 561*0b57cec5SDimitry Andric SkipTypeQualifiers(); 562*0b57cec5SDimitry Andric if (!ConsumeBuiltinType() && !ConsumeDecltype()) { 563*0b57cec5SDimitry Andric if (!ParseFullNameImpl()) 564*0b57cec5SDimitry Andric return false; 565*0b57cec5SDimitry Andric } 566*0b57cec5SDimitry Andric SkipPtrsAndRefs(); 567*0b57cec5SDimitry Andric start_position.Remove(); 568*0b57cec5SDimitry Andric return true; 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric 571bdd1243dSDimitry Andric std::optional<CPlusPlusNameParser::ParsedNameRanges> 572*0b57cec5SDimitry Andric CPlusPlusNameParser::ParseFullNameImpl() { 573*0b57cec5SDimitry Andric // Name parsing state machine. 574*0b57cec5SDimitry Andric enum class State { 575*0b57cec5SDimitry Andric Beginning, // start of the name 576*0b57cec5SDimitry Andric AfterTwoColons, // right after :: 577*0b57cec5SDimitry Andric AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+) 578*0b57cec5SDimitry Andric AfterTemplate, // right after template brackets (<something>) 579*0b57cec5SDimitry Andric AfterOperator, // right after name of C++ operator 580*0b57cec5SDimitry Andric }; 581*0b57cec5SDimitry Andric 582*0b57cec5SDimitry Andric Bookmark start_position = SetBookmark(); 583*0b57cec5SDimitry Andric State state = State::Beginning; 584*0b57cec5SDimitry Andric bool continue_parsing = true; 585bdd1243dSDimitry Andric std::optional<size_t> last_coloncolon_position; 586*0b57cec5SDimitry Andric 587*0b57cec5SDimitry Andric while (continue_parsing && HasMoreTokens()) { 588*0b57cec5SDimitry Andric const auto &token = Peek(); 589*0b57cec5SDimitry Andric switch (token.getKind()) { 590*0b57cec5SDimitry Andric case tok::raw_identifier: // Just a name. 591*0b57cec5SDimitry Andric if (state != State::Beginning && state != State::AfterTwoColons) { 592*0b57cec5SDimitry Andric continue_parsing = false; 593*0b57cec5SDimitry Andric break; 594*0b57cec5SDimitry Andric } 595*0b57cec5SDimitry Andric Advance(); 596*0b57cec5SDimitry Andric state = State::AfterIdentifier; 597*0b57cec5SDimitry 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 } 614*0b57cec5SDimitry Andric case tok::l_paren: { 615*0b57cec5SDimitry Andric if (state == State::Beginning || state == State::AfterTwoColons) { 616*0b57cec5SDimitry Andric // (anonymous namespace) 617*0b57cec5SDimitry Andric if (ConsumeAnonymousNamespace()) { 618*0b57cec5SDimitry Andric state = State::AfterIdentifier; 619*0b57cec5SDimitry Andric break; 620*0b57cec5SDimitry Andric } 621*0b57cec5SDimitry Andric } 622*0b57cec5SDimitry Andric 623*0b57cec5SDimitry Andric // Type declared inside a function 'func()::Type' 624*0b57cec5SDimitry Andric if (state != State::AfterIdentifier && state != State::AfterTemplate && 625*0b57cec5SDimitry Andric state != State::AfterOperator) { 626*0b57cec5SDimitry Andric continue_parsing = false; 627*0b57cec5SDimitry Andric break; 628*0b57cec5SDimitry Andric } 629*0b57cec5SDimitry Andric Bookmark l_paren_position = SetBookmark(); 630*0b57cec5SDimitry Andric // Consume the '(' ... ') [const]'. 631*0b57cec5SDimitry Andric if (!ConsumeArguments()) { 632*0b57cec5SDimitry Andric continue_parsing = false; 633*0b57cec5SDimitry Andric break; 634*0b57cec5SDimitry Andric } 635*0b57cec5SDimitry Andric SkipFunctionQualifiers(); 636*0b57cec5SDimitry Andric 637*0b57cec5SDimitry Andric // Consume '::' 638*0b57cec5SDimitry Andric size_t coloncolon_position = GetCurrentPosition(); 639*0b57cec5SDimitry Andric if (!ConsumeToken(tok::coloncolon)) { 640*0b57cec5SDimitry Andric continue_parsing = false; 641*0b57cec5SDimitry Andric break; 642*0b57cec5SDimitry Andric } 643*0b57cec5SDimitry Andric l_paren_position.Remove(); 644*0b57cec5SDimitry Andric last_coloncolon_position = coloncolon_position; 645*0b57cec5SDimitry Andric state = State::AfterTwoColons; 646*0b57cec5SDimitry Andric break; 647*0b57cec5SDimitry Andric } 648*0b57cec5SDimitry Andric case tok::l_brace: 649*0b57cec5SDimitry Andric if (state == State::Beginning || state == State::AfterTwoColons) { 650*0b57cec5SDimitry Andric if (ConsumeLambda()) { 651*0b57cec5SDimitry Andric state = State::AfterIdentifier; 652*0b57cec5SDimitry Andric break; 653*0b57cec5SDimitry Andric } 654*0b57cec5SDimitry Andric } 655*0b57cec5SDimitry Andric continue_parsing = false; 656*0b57cec5SDimitry Andric break; 657*0b57cec5SDimitry Andric case tok::coloncolon: // Type nesting delimiter. 658*0b57cec5SDimitry Andric if (state != State::Beginning && state != State::AfterIdentifier && 659*0b57cec5SDimitry Andric state != State::AfterTemplate) { 660*0b57cec5SDimitry Andric continue_parsing = false; 661*0b57cec5SDimitry Andric break; 662*0b57cec5SDimitry Andric } 663*0b57cec5SDimitry Andric last_coloncolon_position = GetCurrentPosition(); 664*0b57cec5SDimitry Andric Advance(); 665*0b57cec5SDimitry Andric state = State::AfterTwoColons; 666*0b57cec5SDimitry Andric break; 667*0b57cec5SDimitry Andric case tok::less: // Template brackets. 668*0b57cec5SDimitry Andric if (state != State::AfterIdentifier && state != State::AfterOperator) { 669*0b57cec5SDimitry Andric continue_parsing = false; 670*0b57cec5SDimitry Andric break; 671*0b57cec5SDimitry Andric } 672*0b57cec5SDimitry Andric if (!ConsumeTemplateArgs()) { 673*0b57cec5SDimitry Andric continue_parsing = false; 674*0b57cec5SDimitry Andric break; 675*0b57cec5SDimitry Andric } 676*0b57cec5SDimitry Andric state = State::AfterTemplate; 677*0b57cec5SDimitry Andric break; 678*0b57cec5SDimitry Andric case tok::kw_operator: // C++ operator overloading. 679*0b57cec5SDimitry Andric if (state != State::Beginning && state != State::AfterTwoColons) { 680*0b57cec5SDimitry Andric continue_parsing = false; 681*0b57cec5SDimitry Andric break; 682*0b57cec5SDimitry Andric } 683*0b57cec5SDimitry Andric if (!ConsumeOperator()) { 684*0b57cec5SDimitry Andric continue_parsing = false; 685*0b57cec5SDimitry Andric break; 686*0b57cec5SDimitry Andric } 687*0b57cec5SDimitry Andric state = State::AfterOperator; 688*0b57cec5SDimitry Andric break; 689*0b57cec5SDimitry Andric case tok::tilde: // Destructor. 690*0b57cec5SDimitry Andric if (state != State::Beginning && state != State::AfterTwoColons) { 691*0b57cec5SDimitry Andric continue_parsing = false; 692*0b57cec5SDimitry Andric break; 693*0b57cec5SDimitry Andric } 694*0b57cec5SDimitry Andric Advance(); 695*0b57cec5SDimitry Andric if (ConsumeToken(tok::raw_identifier)) { 696*0b57cec5SDimitry Andric state = State::AfterIdentifier; 697*0b57cec5SDimitry Andric } else { 698*0b57cec5SDimitry Andric TakeBack(); 699*0b57cec5SDimitry Andric continue_parsing = false; 700*0b57cec5SDimitry Andric } 701*0b57cec5SDimitry Andric break; 702*0b57cec5SDimitry Andric default: 703*0b57cec5SDimitry Andric continue_parsing = false; 704*0b57cec5SDimitry Andric break; 705*0b57cec5SDimitry Andric } 706*0b57cec5SDimitry Andric } 707*0b57cec5SDimitry Andric 708*0b57cec5SDimitry Andric if (state == State::AfterIdentifier || state == State::AfterOperator || 709*0b57cec5SDimitry Andric state == State::AfterTemplate) { 710*0b57cec5SDimitry Andric ParsedNameRanges result; 711*0b57cec5SDimitry Andric if (last_coloncolon_position) { 712bdd1243dSDimitry Andric result.context_range = 713bdd1243dSDimitry Andric Range(start_position.GetSavedPosition(), *last_coloncolon_position); 714*0b57cec5SDimitry Andric result.basename_range = 715bdd1243dSDimitry Andric Range(*last_coloncolon_position + 1, GetCurrentPosition()); 716*0b57cec5SDimitry Andric } else { 717*0b57cec5SDimitry Andric result.basename_range = 718*0b57cec5SDimitry Andric Range(start_position.GetSavedPosition(), GetCurrentPosition()); 719*0b57cec5SDimitry Andric } 720*0b57cec5SDimitry Andric start_position.Remove(); 721*0b57cec5SDimitry Andric return result; 722*0b57cec5SDimitry Andric } else { 723bdd1243dSDimitry Andric return std::nullopt; 724*0b57cec5SDimitry Andric } 725*0b57cec5SDimitry Andric } 726*0b57cec5SDimitry Andric 727*0b57cec5SDimitry Andric llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) { 728*0b57cec5SDimitry Andric if (range.empty()) 729*0b57cec5SDimitry Andric return llvm::StringRef(); 730*0b57cec5SDimitry Andric assert(range.begin_index < range.end_index); 731*0b57cec5SDimitry Andric assert(range.begin_index < m_tokens.size()); 732*0b57cec5SDimitry Andric assert(range.end_index <= m_tokens.size()); 733*0b57cec5SDimitry Andric clang::Token &first_token = m_tokens[range.begin_index]; 734*0b57cec5SDimitry Andric clang::Token &last_token = m_tokens[range.end_index - 1]; 735*0b57cec5SDimitry Andric clang::SourceLocation start_loc = first_token.getLocation(); 736*0b57cec5SDimitry Andric clang::SourceLocation end_loc = last_token.getLocation(); 737*0b57cec5SDimitry Andric unsigned start_pos = start_loc.getRawEncoding(); 738*0b57cec5SDimitry Andric unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength(); 739*0b57cec5SDimitry Andric return m_text.take_front(end_pos).drop_front(start_pos); 740*0b57cec5SDimitry Andric } 741*0b57cec5SDimitry Andric 742*0b57cec5SDimitry Andric static const clang::LangOptions &GetLangOptions() { 743*0b57cec5SDimitry Andric static clang::LangOptions g_options; 744*0b57cec5SDimitry Andric static llvm::once_flag g_once_flag; 745*0b57cec5SDimitry Andric llvm::call_once(g_once_flag, []() { 746*0b57cec5SDimitry Andric g_options.LineComment = true; 747*0b57cec5SDimitry Andric g_options.C99 = true; 748*0b57cec5SDimitry Andric g_options.C11 = true; 749*0b57cec5SDimitry Andric g_options.CPlusPlus = true; 750*0b57cec5SDimitry Andric g_options.CPlusPlus11 = true; 751*0b57cec5SDimitry Andric g_options.CPlusPlus14 = true; 752*0b57cec5SDimitry Andric g_options.CPlusPlus17 = true; 753*0b57cec5SDimitry Andric }); 754*0b57cec5SDimitry Andric return g_options; 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric 757*0b57cec5SDimitry Andric static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() { 758*0b57cec5SDimitry Andric static llvm::StringMap<tok::TokenKind> g_map{ 759*0b57cec5SDimitry Andric #define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name}, 760*0b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.def" 761*0b57cec5SDimitry Andric #undef KEYWORD 762*0b57cec5SDimitry Andric }; 763*0b57cec5SDimitry Andric return g_map; 764*0b57cec5SDimitry Andric } 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric void CPlusPlusNameParser::ExtractTokens() { 767*0b57cec5SDimitry Andric if (m_text.empty()) 768*0b57cec5SDimitry Andric return; 769*0b57cec5SDimitry Andric clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(), 770*0b57cec5SDimitry Andric m_text.data(), m_text.data() + m_text.size()); 771*0b57cec5SDimitry Andric const auto &kw_map = GetKeywordsMap(); 772*0b57cec5SDimitry Andric clang::Token token; 773*0b57cec5SDimitry Andric for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof); 774*0b57cec5SDimitry Andric lexer.LexFromRawLexer(token)) { 775*0b57cec5SDimitry Andric if (token.is(clang::tok::raw_identifier)) { 776*0b57cec5SDimitry Andric auto it = kw_map.find(token.getRawIdentifier()); 777*0b57cec5SDimitry Andric if (it != kw_map.end()) { 778*0b57cec5SDimitry Andric token.setKind(it->getValue()); 779*0b57cec5SDimitry Andric } 780*0b57cec5SDimitry Andric } 781*0b57cec5SDimitry Andric 782*0b57cec5SDimitry Andric m_tokens.push_back(token); 783*0b57cec5SDimitry Andric } 784*0b57cec5SDimitry Andric } 785