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