Coverage Report

Created: 2022-01-22 13:19

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- CPlusPlusNameParser.cpp -------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "CPlusPlusNameParser.h"
10
11
#include "clang/Basic/IdentifierTable.h"
12
#include "llvm/ADT/StringMap.h"
13
#include "llvm/Support/Threading.h"
14
15
using namespace lldb;
16
using namespace lldb_private;
17
using llvm::Optional;
18
using llvm::None;
19
using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
20
using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
21
namespace tok = clang::tok;
22
23
16.2k
Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
24
16.2k
  m_next_token_index = 0;
25
16.2k
  Optional<ParsedFunction> result(None);
26
27
  // Try to parse the name as function without a return type specified e.g.
28
  // main(int, char*[])
29
16.2k
  {
30
16.2k
    Bookmark start_position = SetBookmark();
31
16.2k
    result = ParseFunctionImpl(false);
32
16.2k
    if (result && 
!HasMoreTokens()61
)
33
60
      return result;
34
16.2k
  }
35
36
  // Try to parse the name as function with function pointer return type e.g.
37
  // void (*get_func(const char*))()
38
16.2k
  result = ParseFuncPtr(true);
39
16.2k
  if (result)
40
3
    return result;
41
42
  // Finally try to parse the name as a function with non-function return type
43
  // e.g. int main(int, char*[])
44
16.2k
  result = ParseFunctionImpl(true);
45
16.2k
  if (HasMoreTokens())
46
16.1k
    return None;
47
72
  return result;
48
16.2k
}
49
50
34.6k
Optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
51
34.6k
  m_next_token_index = 0;
52
34.6k
  Optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
53
34.6k
  if (!name_ranges)
54
67
    return None;
55
34.5k
  if (HasMoreTokens())
56
1.37k
    return None;
57
33.1k
  ParsedName result;
58
33.1k
  result.basename = GetTextForRange(name_ranges.getValue().basename_range);
59
33.1k
  result.context = GetTextForRange(name_ranges.getValue().context_range);
60
33.1k
  return result;
61
34.5k
}
62
63
655k
bool CPlusPlusNameParser::HasMoreTokens() {
64
655k
  return m_next_token_index < m_tokens.size();
65
655k
}
66
67
94.4k
void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
68
69
2
void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
70
71
51.9k
bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
72
51.9k
  if (!HasMoreTokens())
73
14.8k
    return false;
74
75
37.1k
  if (!Peek().is(kind))
76
33.7k
    return false;
77
78
3.40k
  Advance();
79
3.40k
  return true;
80
37.1k
}
81
82
97.4k
template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
83
97.4k
  if (!HasMoreTokens())
84
59.1k
    return false;
85
86
38.2k
  if (!Peek().isOneOf(kinds...))
87
38.2k
    return false;
88
89
39
  Advance();
90
39
  return true;
91
38.2k
}
bool lldb_private::CPlusPlusNameParser::ConsumeToken<clang::tok::TokenKind, clang::tok::TokenKind>(clang::tok::TokenKind, clang::tok::TokenKind)
Line
Count
Source
82
64.7k
template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
83
64.7k
  if (!HasMoreTokens())
84
29.4k
    return false;
85
86
35.3k
  if (!Peek().isOneOf(kinds...))
87
35.3k
    return false;
88
89
4
  Advance();
90
4
  return true;
91
35.3k
}
bool lldb_private::CPlusPlusNameParser::ConsumeToken<clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind>(clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind)
Line
Count
Source
82
298
template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
83
298
  if (!HasMoreTokens())
84
267
    return false;
85
86
31
  if (!Peek().isOneOf(kinds...))
87
18
    return false;
88
89
13
  Advance();
90
13
  return true;
91
31
}
bool lldb_private::CPlusPlusNameParser::ConsumeToken<clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind>(clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind)
Line
Count
Source
82
32.3k
template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
83
32.3k
  if (!HasMoreTokens())
84
29.4k
    return false;
85
86
2.91k
  if (!Peek().isOneOf(kinds...))
87
2.89k
    return false;
88
89
22
  Advance();
90
22
  return true;
91
2.91k
}
92
93
249k
CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
94
249k
  return Bookmark(m_next_token_index);
95
249k
}
96
97
100k
size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
98
99
211k
clang::Token &CPlusPlusNameParser::Peek() {
100
211k
  assert(HasMoreTokens());
101
0
  return m_tokens[m_next_token_index];
102
211k
}
103
104
Optional<ParsedFunction>
105
32.4k
CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
106
32.4k
  Bookmark start_position = SetBookmark();
107
32.4k
  if (expect_return_type) {
108
    // Consume return type if it's expected.
109
16.2k
    if (!ConsumeTypename())
110
36
      return None;
111
16.2k
  }
112
113
32.4k
  auto maybe_name = ParseFullNameImpl();
114
32.4k
  if (!maybe_name) {
115
16.2k
    return None;
116
16.2k
  }
117
118
16.2k
  size_t argument_start = GetCurrentPosition();
119
16.2k
  if (!ConsumeArguments()) {
120
16.1k
    return None;
121
16.1k
  }
122
123
134
  size_t qualifiers_start = GetCurrentPosition();
124
134
  SkipFunctionQualifiers();
125
134
  size_t end_position = GetCurrentPosition();
126
127
134
  ParsedFunction result;
128
134
  result.name.basename = GetTextForRange(maybe_name.getValue().basename_range);
129
134
  result.name.context = GetTextForRange(maybe_name.getValue().context_range);
130
134
  result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
131
134
  result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
132
134
  start_position.Remove();
133
134
  return result;
134
16.2k
}
135
136
Optional<ParsedFunction>
137
16.2k
CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
138
16.2k
  Bookmark start_position = SetBookmark();
139
16.2k
  if (expect_return_type) {
140
    // Consume return type.
141
16.2k
    if (!ConsumeTypename())
142
36
      return None;
143
16.2k
  }
144
145
16.1k
  if (!ConsumeToken(tok::l_paren))
146
16.1k
    return None;
147
11
  if (!ConsumePtrsAndRefs())
148
0
    return None;
149
150
11
  {
151
11
    Bookmark before_inner_function_pos = SetBookmark();
152
11
    auto maybe_inner_function_name = ParseFunctionImpl(false);
153
11
    if (maybe_inner_function_name)
154
3
      if (ConsumeToken(tok::r_paren))
155
3
        if (ConsumeArguments()) {
156
3
          SkipFunctionQualifiers();
157
3
          start_position.Remove();
158
3
          before_inner_function_pos.Remove();
159
3
          return maybe_inner_function_name;
160
3
        }
161
11
  }
162
163
8
  auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
164
8
  if (maybe_inner_function_ptr_name)
165
7
    if (ConsumeToken(tok::r_paren))
166
7
      if (ConsumeArguments()) {
167
7
        SkipFunctionQualifiers();
168
7
        start_position.Remove();
169
7
        return maybe_inner_function_ptr_name;
170
7
      }
171
1
  return None;
172
8
}
173
174
16.4k
bool CPlusPlusNameParser::ConsumeArguments() {
175
16.4k
  return ConsumeBrackets(tok::l_paren, tok::r_paren);
176
16.4k
}
177
178
165
bool CPlusPlusNameParser::ConsumeTemplateArgs() {
179
165
  Bookmark start_position = SetBookmark();
180
165
  if (!HasMoreTokens() || Peek().getKind() != tok::less)
181
0
    return false;
182
165
  Advance();
183
184
  // Consuming template arguments is a bit trickier than consuming function
185
  // arguments, because '<' '>' brackets are not always trivially balanced. In
186
  // some rare cases tokens '<' and '>' can appear inside template arguments as
187
  // arithmetic or shift operators not as template brackets. Examples:
188
  // std::enable_if<(10u)<(64), bool>
189
  //           f<A<operator<(X,Y)::Subclass>>
190
  // Good thing that compiler makes sure that really ambiguous cases of '>'
191
  // usage should be enclosed within '()' brackets.
192
165
  int template_counter = 1;
193
165
  bool can_open_template = false;
194
1.72k
  while (HasMoreTokens() && 
template_counter > 01.71k
) {
195
1.56k
    tok::TokenKind kind = Peek().getKind();
196
1.56k
    switch (kind) {
197
4
    case tok::greatergreater:
198
4
      template_counter -= 2;
199
4
      can_open_template = false;
200
4
      Advance();
201
4
      break;
202
279
    case tok::greater:
203
279
      --template_counter;
204
279
      can_open_template = false;
205
279
      Advance();
206
279
      break;
207
126
    case tok::less:
208
      // '<' is an attempt to open a subteamplte
209
      // check if parser is at the point where it's actually possible,
210
      // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No
211
      // need to do the same for '>' because compiler actually makes sure that
212
      // '>' always surrounded by brackets to avoid ambiguity.
213
126
      if (can_open_template)
214
121
        ++template_counter;
215
126
      can_open_template = false;
216
126
      Advance();
217
126
      break;
218
1
    case tok::kw_operator: // C++ operator overloading.
219
1
      if (!ConsumeOperator())
220
0
        return false;
221
1
      can_open_template = true;
222
1
      break;
223
474
    case tok::raw_identifier:
224
474
      can_open_template = true;
225
474
      Advance();
226
474
      break;
227
0
    case tok::l_square:
228
0
      if (!ConsumeBrackets(tok::l_square, tok::r_square))
229
0
        return false;
230
0
      can_open_template = false;
231
0
      break;
232
13
    case tok::l_paren:
233
13
      if (!ConsumeArguments())
234
0
        return false;
235
13
      can_open_template = false;
236
13
      break;
237
663
    default:
238
663
      can_open_template = false;
239
663
      Advance();
240
663
      break;
241
1.56k
    }
242
1.56k
  }
243
244
165
  if (template_counter != 0) {
245
1
    return false;
246
1
  }
247
164
  start_position.Remove();
248
164
  return true;
249
165
}
250
251
11
bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
252
11
  Bookmark start_position = SetBookmark();
253
11
  if (!ConsumeToken(tok::l_paren)) {
254
0
    return false;
255
0
  }
256
11
  constexpr llvm::StringLiteral g_anonymous("anonymous");
257
11
  if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
258
11
      
Peek().getRawIdentifier() == g_anonymous4
) {
259
4
    Advance();
260
7
  } else {
261
7
    return false;
262
7
  }
263
264
4
  if (!ConsumeToken(tok::kw_namespace)) {
265
0
    return false;
266
0
  }
267
268
4
  if (!ConsumeToken(tok::r_paren)) {
269
0
    return false;
270
0
  }
271
4
  start_position.Remove();
272
4
  return true;
273
4
}
274
275
2
bool CPlusPlusNameParser::ConsumeLambda() {
276
2
  Bookmark start_position = SetBookmark();
277
2
  if (!ConsumeToken(tok::l_brace)) {
278
0
    return false;
279
0
  }
280
2
  constexpr llvm::StringLiteral g_lambda("lambda");
281
2
  if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
282
2
      Peek().getRawIdentifier() == g_lambda) {
283
    // Put the matched brace back so we can use ConsumeBrackets
284
2
    TakeBack();
285
2
  } else {
286
0
    return false;
287
0
  }
288
289
2
  if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) {
290
0
    return false;
291
0
  }
292
293
2
  start_position.Remove();
294
2
  return true;
295
2
}
296
297
bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
298
16.6k
                                          tok::TokenKind right) {
299
16.6k
  Bookmark start_position = SetBookmark();
300
16.6k
  if (!HasMoreTokens() || 
Peek().getKind() != left1.96k
)
301
16.1k
    return false;
302
590
  Advance();
303
304
590
  int counter = 1;
305
5.09k
  while (HasMoreTokens() && 
counter > 04.56k
) {
306
4.50k
    tok::TokenKind kind = Peek().getKind();
307
4.50k
    if (kind == right)
308
687
      --counter;
309
3.81k
    else if (kind == left)
310
97
      ++counter;
311
4.50k
    Advance();
312
4.50k
  }
313
314
590
  assert(counter >= 0);
315
590
  if (counter > 0) {
316
0
    return false;
317
0
  }
318
590
  start_position.Remove();
319
590
  return true;
320
590
}
321
322
3.33k
bool CPlusPlusNameParser::ConsumeOperator() {
323
3.33k
  Bookmark start_position = SetBookmark();
324
3.33k
  if (!ConsumeToken(tok::kw_operator))
325
0
    return false;
326
327
3.33k
  if (!HasMoreTokens()) {
328
0
    return false;
329
0
  }
330
331
3.33k
  const auto &token = Peek();
332
333
  // When clang generates debug info it adds template parameters to names.
334
  // Since clang doesn't add a space between the name and the template parameter
335
  // in some cases we are not generating valid C++ names e.g.:
336
  //
337
  //   operator<<A::B>
338
  //
339
  // In some of these cases we will not parse them correctly. This fixes the
340
  // issue by detecting this case and inserting tok::less in place of
341
  // tok::lessless and returning successfully that we consumed the operator.
342
3.33k
  if (token.getKind() == tok::lessless) {
343
    // Make sure we have more tokens before attempting to look ahead one more.
344
60
    if (m_next_token_index + 1 < m_tokens.size()) {
345
      // Look ahead two tokens.
346
24
      clang::Token n_token = m_tokens[m_next_token_index + 1];
347
      // If we find ( or < then this is indeed operator<< no need for fix.
348
24
      if (n_token.getKind() != tok::l_paren && 
n_token.getKind() != tok::less6
) {
349
2
        clang::Token tmp_tok;
350
2
        tmp_tok.startToken();
351
2
        tmp_tok.setLength(1);
352
2
        tmp_tok.setLocation(token.getLocation().getLocWithOffset(1));
353
2
        tmp_tok.setKind(tok::less);
354
355
2
        m_tokens[m_next_token_index] = tmp_tok;
356
357
2
        start_position.Remove();
358
2
        return true;
359
2
      }
360
24
    }
361
60
  }
362
363
3.32k
  switch (token.getKind()) {
364
247
  case tok::kw_new:
365
518
  case tok::kw_delete:
366
    // This is 'new' or 'delete' operators.
367
518
    Advance();
368
    // Check for array new/delete.
369
518
    if (HasMoreTokens() && 
Peek().is(tok::l_square)272
) {
370
      // Consume the '[' and ']'.
371
271
      if (!ConsumeBrackets(tok::l_square, tok::r_square))
372
0
        return false;
373
271
    }
374
518
    break;
375
376
518
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \
377
2.80k
  case tok::Token:                                                             \
378
2.80k
    Advance();                                                                 \
379
2.80k
    break;
380
518
#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
381
518
#include "clang/Basic/OperatorKinds.def"
382
0
#undef OVERLOADED_OPERATOR
383
0
#undef OVERLOADED_OPERATOR_MULTI
384
385
4
  case tok::l_paren:
386
    // Call operator consume '(' ... ')'.
387
4
    if (ConsumeBrackets(tok::l_paren, tok::r_paren))
388
4
      break;
389
0
    return false;
390
391
5
  case tok::l_square:
392
    // This is a [] operator.
393
    // Consume the '[' and ']'.
394
5
    if (ConsumeBrackets(tok::l_square, tok::r_square))
395
5
      break;
396
0
    return false;
397
398
1
  default:
399
    // This might be a cast operator.
400
1
    if (ConsumeTypename())
401
1
      break;
402
0
    return false;
403
3.32k
  }
404
3.32k
  start_position.Remove();
405
3.32k
  return true;
406
3.32k
}
407
408
64.7k
void CPlusPlusNameParser::SkipTypeQualifiers() {
409
64.7k
  while (ConsumeToken(tok::kw_const, tok::kw_volatile))
410
5
    ;
411
64.7k
}
412
413
285
void CPlusPlusNameParser::SkipFunctionQualifiers() {
414
298
  while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
415
13
    ;
416
285
}
417
418
32.4k
bool CPlusPlusNameParser::ConsumeBuiltinType() {
419
32.4k
  bool result = false;
420
32.4k
  bool continue_parsing = true;
421
  // Built-in types can be made of a few keywords like 'unsigned long long
422
  // int'. This function consumes all built-in type keywords without checking
423
  // if they make sense like 'unsigned char void'.
424
64.9k
  while (continue_parsing && 
HasMoreTokens()32.5k
) {
425
32.5k
    switch (Peek().getKind()) {
426
0
    case tok::kw_short:
427
2
    case tok::kw_long:
428
2
    case tok::kw___int64:
429
2
    case tok::kw___int128:
430
2
    case tok::kw_signed:
431
4
    case tok::kw_unsigned:
432
14
    case tok::kw_void:
433
14
    case tok::kw_char:
434
88
    case tok::kw_int:
435
88
    case tok::kw_half:
436
88
    case tok::kw_float:
437
112
    case tok::kw_double:
438
112
    case tok::kw___float128:
439
112
    case tok::kw_wchar_t:
440
121
    case tok::kw_bool:
441
121
    case tok::kw_char16_t:
442
121
    case tok::kw_char32_t:
443
121
      result = true;
444
121
      Advance();
445
121
      break;
446
32.4k
    default:
447
32.4k
      continue_parsing = false;
448
32.4k
      break;
449
32.5k
    }
450
32.5k
  }
451
32.4k
  return result;
452
32.4k
}
453
454
32.3k
void CPlusPlusNameParser::SkipPtrsAndRefs() {
455
  // Ignoring result.
456
32.3k
  ConsumePtrsAndRefs();
457
32.3k
}
458
459
32.3k
bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
460
32.3k
  bool found = false;
461
32.3k
  SkipTypeQualifiers();
462
32.3k
  while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
463
32.3k
                      tok::kw_volatile)) {
464
22
    found = true;
465
22
    SkipTypeQualifiers();
466
22
  }
467
32.3k
  return found;
468
32.3k
}
469
470
32.2k
bool CPlusPlusNameParser::ConsumeDecltype() {
471
32.2k
  Bookmark start_position = SetBookmark();
472
32.2k
  if (!ConsumeToken(tok::kw_decltype))
473
32.2k
    return false;
474
475
11
  if (!ConsumeArguments())
476
0
    return false;
477
478
11
  start_position.Remove();
479
11
  return true;
480
11
}
481
482
32.4k
bool CPlusPlusNameParser::ConsumeTypename() {
483
32.4k
  Bookmark start_position = SetBookmark();
484
32.4k
  SkipTypeQualifiers();
485
32.4k
  if (!ConsumeBuiltinType() && 
!ConsumeDecltype()32.2k
) {
486
32.2k
    if (!ParseFullNameImpl())
487
72
      return false;
488
32.2k
  }
489
32.3k
  SkipPtrsAndRefs();
490
32.3k
  start_position.Remove();
491
32.3k
  return true;
492
32.4k
}
493
494
Optional<CPlusPlusNameParser::ParsedNameRanges>
495
99.3k
CPlusPlusNameParser::ParseFullNameImpl() {
496
  // Name parsing state machine.
497
99.3k
  enum class State {
498
99.3k
    Beginning,       // start of the name
499
99.3k
    AfterTwoColons,  // right after ::
500
99.3k
    AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
501
99.3k
    AfterTemplate,   // right after template brackets (<something>)
502
99.3k
    AfterOperator,   // right after name of C++ operator
503
99.3k
  };
504
505
99.3k
  Bookmark start_position = SetBookmark();
506
99.3k
  State state = State::Beginning;
507
99.3k
  bool continue_parsing = true;
508
99.3k
  Optional<size_t> last_coloncolon_position = None;
509
510
190k
  while (continue_parsing && 
HasMoreTokens()183k
) {
511
91.4k
    const auto &token = Peek();
512
91.4k
    switch (token.getKind()) {
513
80.1k
    case tok::raw_identifier: // Just a name.
514
80.1k
      if (state != State::Beginning && 
state != State::AfterTwoColons476
) {
515
21
        continue_parsing = false;
516
21
        break;
517
21
      }
518
80.1k
      Advance();
519
80.1k
      state = State::AfterIdentifier;
520
80.1k
      break;
521
150
    case tok::l_paren: {
522
150
      if (state == State::Beginning || 
state == State::AfterTwoColons142
) {
523
        // (anonymous namespace)
524
11
        if (ConsumeAnonymousNamespace()) {
525
4
          state = State::AfterIdentifier;
526
4
          break;
527
4
        }
528
11
      }
529
530
      // Type declared inside a function 'func()::Type'
531
146
      if (state != State::AfterIdentifier && 
state != State::AfterTemplate141
&&
532
146
          
state != State::AfterOperator52
) {
533
7
        continue_parsing = false;
534
7
        break;
535
7
      }
536
139
      Bookmark l_paren_position = SetBookmark();
537
      // Consume the '(' ... ') [const]'.
538
139
      if (!ConsumeArguments()) {
539
0
        continue_parsing = false;
540
0
        break;
541
0
      }
542
139
      SkipFunctionQualifiers();
543
544
      // Consume '::'
545
139
      size_t coloncolon_position = GetCurrentPosition();
546
139
      if (!ConsumeToken(tok::coloncolon)) {
547
137
        continue_parsing = false;
548
137
        break;
549
137
      }
550
2
      l_paren_position.Remove();
551
2
      last_coloncolon_position = coloncolon_position;
552
2
      state = State::AfterTwoColons;
553
2
      break;
554
139
    }
555
2
    case tok::l_brace:
556
2
      if (state == State::Beginning || state == State::AfterTwoColons) {
557
2
        if (ConsumeLambda()) {
558
2
          state = State::AfterIdentifier;
559
2
          break;
560
2
        }
561
2
      }
562
0
      continue_parsing = false;
563
0
      break;
564
527
    case tok::coloncolon: // Type nesting delimiter.
565
527
      if (state != State::Beginning && state != State::AfterIdentifier &&
566
527
          
state != State::AfterTemplate47
) {
567
0
        continue_parsing = false;
568
0
        break;
569
0
      }
570
527
      last_coloncolon_position = GetCurrentPosition();
571
527
      Advance();
572
527
      state = State::AfterTwoColons;
573
527
      break;
574
165
    case tok::less: // Template brackets.
575
165
      if (state != State::AfterIdentifier && 
state != State::AfterOperator15
) {
576
0
        continue_parsing = false;
577
0
        break;
578
0
      }
579
165
      if (!ConsumeTemplateArgs()) {
580
1
        continue_parsing = false;
581
1
        break;
582
1
      }
583
164
      state = State::AfterTemplate;
584
164
      break;
585
3.32k
    case tok::kw_operator: // C++ operator overloading.
586
3.32k
      if (state != State::Beginning && 
state != State::AfterTwoColons55
) {
587
0
        continue_parsing = false;
588
0
        break;
589
0
      }
590
3.32k
      if (!ConsumeOperator()) {
591
0
        continue_parsing = false;
592
0
        break;
593
0
      }
594
3.32k
      state = State::AfterOperator;
595
3.32k
      break;
596
25
    case tok::tilde: // Destructor.
597
25
      if (state != State::Beginning && 
state != State::AfterTwoColons13
) {
598
0
        continue_parsing = false;
599
0
        break;
600
0
      }
601
25
      Advance();
602
25
      if (ConsumeToken(tok::raw_identifier)) {
603
25
        state = State::AfterIdentifier;
604
25
      } else {
605
0
        TakeBack();
606
0
        continue_parsing = false;
607
0
      }
608
25
      break;
609
7.07k
    default:
610
7.07k
      continue_parsing = false;
611
7.07k
      break;
612
91.4k
    }
613
91.4k
  }
614
615
99.3k
  if (state == State::AfterIdentifier || 
state == State::AfterOperator19.7k
||
616
99.3k
      
state == State::AfterTemplate16.4k
) {
617
82.9k
    ParsedNameRanges result;
618
82.9k
    if (last_coloncolon_position) {
619
316
      result.context_range = Range(start_position.GetSavedPosition(),
620
316
                                   last_coloncolon_position.getValue());
621
316
      result.basename_range =
622
316
          Range(last_coloncolon_position.getValue() + 1, GetCurrentPosition());
623
82.6k
    } else {
624
82.6k
      result.basename_range =
625
82.6k
          Range(start_position.GetSavedPosition(), GetCurrentPosition());
626
82.6k
    }
627
82.9k
    start_position.Remove();
628
82.9k
    return result;
629
82.9k
  } else {
630
16.3k
    return None;
631
16.3k
  }
632
99.3k
}
633
634
66.8k
llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
635
66.8k
  if (range.empty())
636
33.2k
    return llvm::StringRef();
637
33.6k
  assert(range.begin_index < range.end_index);
638
0
  assert(range.begin_index < m_tokens.size());
639
0
  assert(range.end_index <= m_tokens.size());
640
0
  clang::Token &first_token = m_tokens[range.begin_index];
641
33.6k
  clang::Token &last_token = m_tokens[range.end_index - 1];
642
33.6k
  clang::SourceLocation start_loc = first_token.getLocation();
643
33.6k
  clang::SourceLocation end_loc = last_token.getLocation();
644
33.6k
  unsigned start_pos = start_loc.getRawEncoding();
645
33.6k
  unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
646
33.6k
  return m_text.take_front(end_pos).drop_front(start_pos);
647
66.8k
}
648
649
50.8k
static const clang::LangOptions &GetLangOptions() {
650
50.8k
  static clang::LangOptions g_options;
651
50.8k
  static llvm::once_flag g_once_flag;
652
50.8k
  llvm::call_once(g_once_flag, []() {
653
803
    g_options.LineComment = true;
654
803
    g_options.C99 = true;
655
803
    g_options.C11 = true;
656
803
    g_options.CPlusPlus = true;
657
803
    g_options.CPlusPlus11 = true;
658
803
    g_options.CPlusPlus14 = true;
659
803
    g_options.CPlusPlus17 = true;
660
803
  });
661
50.8k
  return g_options;
662
50.8k
}
663
664
50.8k
static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
665
50.8k
  static llvm::StringMap<tok::TokenKind> g_map{
666
14.0M
#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
667
50.8k
#include "clang/Basic/TokenKinds.def"
668
50.8k
#undef KEYWORD
669
50.8k
  };
670
50.8k
  return g_map;
671
50.8k
}
672
673
50.8k
void CPlusPlusNameParser::ExtractTokens() {
674
50.8k
  if (m_text.empty())
675
2
    return;
676
50.8k
  clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
677
50.8k
                     m_text.data(), m_text.data() + m_text.size());
678
50.8k
  const auto &kw_map = GetKeywordsMap();
679
50.8k
  clang::Token token;
680
136k
  for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
681
85.8k
       lexer.LexFromRawLexer(token)) {
682
85.8k
    if (token.is(clang::tok::raw_identifier)) {
683
65.0k
      auto it = kw_map.find(token.getRawIdentifier());
684
65.0k
      if (it != kw_map.end()) {
685
4.49k
        token.setKind(it->getValue());
686
4.49k
      }
687
65.0k
    }
688
689
85.8k
    m_tokens.push_back(token);
690
85.8k
  }
691
50.8k
}