clang 24.0.0git
FormatTokenLexer.cpp
Go to the documentation of this file.
1//===--- FormatTokenLexer.cpp - Lex FormatTokens -------------*- C++ ----*-===//
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/// \file
10/// This file implements FormatTokenLexer, which tokenizes a source file
11/// into a FormatToken stream suitable for ClangFormat.
12///
13//===----------------------------------------------------------------------===//
14
15#include "FormatTokenLexer.h"
16#include "FormatToken.h"
20#include "clang/Format/Format.h"
21#include "llvm/Support/Regex.h"
22
23namespace clang {
24namespace format {
25
27 const SourceManager &SourceMgr, FileID ID, unsigned Column,
28 const FormatStyle &Style, encoding::Encoding Encoding,
29 llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
30 IdentifierTable &IdentTable)
31 : FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}),
32 Column(Column), TrailingWhitespace(0),
33 LangOpts(getFormattingLangOpts(Style)), SourceMgr(SourceMgr), ID(ID),
34 Style(Style), IdentTable(IdentTable), Keywords(IdentTable),
35 Encoding(Encoding), Allocator(Allocator), FirstInLineIndex(0),
36 FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
37 MacroBlockEndRegex(Style.MacroBlockEnd), VerilogProtectedBlock(false) {
38 Lex = std::make_unique<Lexer>(ID, SourceMgr.getBufferOrFake(ID), SourceMgr,
39 LangOpts);
40 Lex->SetKeepWhitespaceMode(true);
41
42 for (const std::string &ForEachMacro : Style.ForEachMacros) {
43 auto Identifier = &IdentTable.get(ForEachMacro);
44 Macros.insert({Identifier, TT_ForEachMacro});
45 }
46 for (const std::string &IfMacro : Style.IfMacros) {
47 auto Identifier = &IdentTable.get(IfMacro);
48 Macros.insert({Identifier, TT_IfMacro});
49 }
50 for (const std::string &AttributeMacro : Style.AttributeMacros) {
51 auto Identifier = &IdentTable.get(AttributeMacro);
52 Macros.insert({Identifier, TT_AttributeMacro});
53 }
54 for (const std::string &StatementMacro : Style.StatementMacros) {
55 auto Identifier = &IdentTable.get(StatementMacro);
56 Macros.insert({Identifier, TT_StatementMacro});
57 }
58 for (const std::string &TypenameMacro : Style.TypenameMacros) {
59 auto Identifier = &IdentTable.get(TypenameMacro);
60 Macros.insert({Identifier, TT_TypenameMacro});
61 }
62 for (const std::string &NamespaceMacro : Style.NamespaceMacros) {
63 auto Identifier = &IdentTable.get(NamespaceMacro);
64 Macros.insert({Identifier, TT_NamespaceMacro});
65 }
66 for (const std::string &WhitespaceSensitiveMacro :
67 Style.WhitespaceSensitiveMacros) {
68 auto Identifier = &IdentTable.get(WhitespaceSensitiveMacro);
69 Macros.insert({Identifier, TT_UntouchableMacroFunc});
70 }
71 for (const std::string &StatementAttributeLikeMacro :
72 Style.StatementAttributeLikeMacros) {
73 auto Identifier = &IdentTable.get(StatementAttributeLikeMacro);
74 Macros.insert({Identifier, TT_StatementAttributeLikeMacro});
75 }
76
77 for (const auto &Macro : Style.MacrosSkippedByRemoveParentheses)
78 MacrosSkippedByRemoveParentheses.insert(&IdentTable.get(Macro));
79 for (const auto &TemplateName : Style.TemplateNames)
80 TemplateNames.insert(&IdentTable.get(TemplateName));
81 for (const auto &TypeName : Style.TypeNames)
82 TypeNames.insert(&IdentTable.get(TypeName));
83 for (const auto &VariableTemplate : Style.VariableTemplates)
84 VariableTemplates.insert(&IdentTable.get(VariableTemplate));
85}
86
88 assert(Tokens.empty());
89 assert(FirstInLineIndex == 0);
90
91 enum { FO_None, FO_CurrentLine, FO_NextLine } FormatOff = FO_None;
92 llvm::Regex FormatOffRegex(Style.OneLineFormatOffRegex);
93 do {
94 Tokens.push_back(getNextToken());
95
96 auto &Tok = *Tokens.back();
97 switch (const auto NewlinesBefore = Tok.NewlinesBefore; FormatOff) {
98 case FO_NextLine:
99 if (NewlinesBefore > 1) {
100 FormatOff = FO_None;
101 } else {
102 Tok.Finalized = true;
103 FormatOff = FO_CurrentLine;
104 }
105 break;
106 case FO_CurrentLine:
107 if (NewlinesBefore == 0) {
108 Tok.Finalized = true;
109 break;
110 }
111 FormatOff = FO_None;
112 [[fallthrough]];
113 default:
114 if (!FormattingDisabled && FormatOffRegex.match(Tok.TokenText)) {
115 if (Tok.is(tok::comment) &&
116 (NewlinesBefore > 0 || Tokens.size() == 1)) {
117 Tok.Finalized = true;
118 FormatOff = FO_NextLine;
119 } else {
120 for (auto *Token : reverse(Tokens)) {
121 Token->Finalized = true;
122 if (Token->NewlinesBefore > 0)
123 break;
124 }
125 FormatOff = FO_CurrentLine;
126 }
127 }
128 }
129
130 if (Style.isJavaScript()) {
131 tryParseJSRegexLiteral();
132 handleTemplateStrings();
133 } else if (Style.isTextProto()) {
134 tryParsePythonComment();
135 }
136
137 tryMergePreviousTokens();
138
139 if (Style.isCSharp()) {
140 // This needs to come after tokens have been merged so that C#
141 // string literals are correctly identified.
142 handleCSharpVerbatimAndInterpolatedStrings();
143 } else if (Style.isTableGen()) {
144 handleTableGenMultilineString();
145 handleTableGenNumericLikeIdentifier();
146 }
147
148 if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline)
149 FirstInLineIndex = Tokens.size() - 1;
150 } while (Tokens.back()->isNot(tok::eof));
151
152 if (Style.InsertNewlineAtEOF) {
153 auto &TokEOF = *Tokens.back();
154 if (TokEOF.NewlinesBefore == 0) {
155 TokEOF.NewlinesBefore = 1;
156 TokEOF.OriginalColumn = 0;
157 }
158 }
159
160 return Tokens;
161}
162
163void FormatTokenLexer::tryMergePreviousTokens() {
164 if (tryMerge_TMacro())
165 return;
166 if (tryMergeConflictMarkers())
167 return;
168 if (tryMergeLessLess())
169 return;
170 if (tryMergeGreaterGreater())
171 return;
172 if (tryMergeForEach())
173 return;
174
175 if ((Style.Language == FormatStyle::LK_Cpp ||
176 Style.Language == FormatStyle::LK_ObjC) &&
177 tryMergeUserDefinedLiteral()) {
178 return;
179 }
180
181 if (Style.isJavaScript() || Style.isCSharp()) {
182 static const tok::TokenKind NullishCoalescingOperator[] = {tok::question,
183 tok::question};
184 static const tok::TokenKind NullPropagatingOperator[] = {tok::question,
185 tok::period};
186 static const tok::TokenKind FatArrow[] = {tok::equal, tok::greater};
187
188 if (tryMergeTokens(FatArrow, TT_FatArrow))
189 return;
190 if (tryMergeTokens(NullishCoalescingOperator, TT_NullCoalescingOperator)) {
191 // Treat like the "||" operator (as opposed to the ternary ?).
192 Tokens.back()->Tok.setKind(tok::pipepipe);
193 return;
194 }
195 if (tryMergeTokens(NullPropagatingOperator, TT_NullPropagatingOperator)) {
196 // Treat like a regular "." access.
197 Tokens.back()->Tok.setKind(tok::period);
198 return;
199 }
200 if (tryMergeNullishCoalescingEqual())
201 return;
202
203 if (Style.isCSharp()) {
204 static const tok::TokenKind CSharpNullConditionalLSquare[] = {
205 tok::question, tok::l_square};
206
207 if (tryMergeCSharpKeywordVariables())
208 return;
209 if (tryMergeCSharpStringLiteral())
210 return;
211 if (tryMergeCSharpUtf8StringLiteral())
212 return;
213 if (tryTransformCSharpForEach())
214 return;
215 if (tryMergeTokens(CSharpNullConditionalLSquare,
216 TT_CSharpNullConditionalLSquare)) {
217 // Treat like a regular "[" operator.
218 Tokens.back()->Tok.setKind(tok::l_square);
219 return;
220 }
221 }
222 }
223
224 if (tryMergeNSStringLiteral())
225 return;
226
227 if (Style.isJavaScript()) {
228 static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
229 static const tok::TokenKind JSNotIdentity[] = {tok::exclaimequal,
230 tok::equal};
231 static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
232 tok::greaterequal};
233 static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star};
234 static const tok::TokenKind JSExponentiationEqual[] = {tok::star,
235 tok::starequal};
236 static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, tok::equal};
237 static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
238
239 // FIXME: Investigate what token type gives the correct operator priority.
240 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
241 return;
242 if (tryMergeTokens(JSNotIdentity, TT_BinaryOperator))
243 return;
244 if (tryMergeTokens(JSShiftEqual, TT_BinaryOperator))
245 return;
246 if (tryMergeTokens(JSExponentiation, TT_JsExponentiation))
247 return;
248 if (tryMergeTokens(JSExponentiationEqual, TT_JsExponentiationEqual)) {
249 Tokens.back()->Tok.setKind(tok::starequal);
250 return;
251 }
252 if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) ||
253 tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEqual)) {
254 // Treat like the "=" assignment operator.
255 Tokens.back()->Tok.setKind(tok::equal);
256 return;
257 }
258 if (tryMergeJSPrivateIdentifier())
259 return;
260 } else if (Style.isJava()) {
261 static const tok::TokenKind JavaRightLogicalShiftAssign[] = {
262 tok::greater, tok::greater, tok::greaterequal};
263 if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator))
264 return;
265 } else if (Style.isVerilog()) {
266 // Merge the number following a base like `'h?a0`.
267 if (Tokens.size() >= 3 && Tokens.end()[-3]->is(TT_VerilogNumberBase) &&
268 Tokens.end()[-2]->is(tok::numeric_constant) &&
269 Tokens.back()->isOneOf(tok::numeric_constant, tok::identifier,
270 tok::question) &&
271 tryMergeTokens(2, TT_Unknown)) {
272 return;
273 }
274 // Part select.
275 if (tryMergeTokensAny({{tok::minus, tok::colon}, {tok::plus, tok::colon}},
276 TT_BitFieldColon)) {
277 return;
278 }
279 // Xnor. The combined token is treated as a caret which can also be either a
280 // unary or binary operator. The actual type is determined in
281 // TokenAnnotator. We also check the token length so we know it is not
282 // already a merged token.
283 if (Tokens.back()->TokenText.size() == 1 &&
284 tryMergeTokensAny({{tok::caret, tok::tilde}, {tok::tilde, tok::caret}},
285 TT_BinaryOperator)) {
286 Tokens.back()->Tok.setKind(tok::caret);
287 return;
288 }
289 // Signed shift and distribution weight.
290 if (tryMergeTokens({tok::less, tok::less}, TT_BinaryOperator)) {
291 Tokens.back()->Tok.setKind(tok::lessless);
292 return;
293 }
294 if (tryMergeTokens({tok::greater, tok::greater}, TT_BinaryOperator)) {
295 Tokens.back()->Tok.setKind(tok::greatergreater);
296 return;
297 }
298 if (tryMergeTokensAny({{tok::lessless, tok::equal},
299 {tok::lessless, tok::lessequal},
300 {tok::greatergreater, tok::equal},
301 {tok::greatergreater, tok::greaterequal},
302 {tok::colon, tok::equal},
303 {tok::colon, tok::slash}},
304 TT_BinaryOperator)) {
305 Tokens.back()->ForcedPrecedence = prec::Assignment;
306 return;
307 }
308 // Exponentiation, signed shift, case equality, and wildcard equality.
309 if (tryMergeTokensAny({{tok::star, tok::star},
310 {tok::lessless, tok::less},
311 {tok::greatergreater, tok::greater},
312 {tok::exclaimequal, tok::equal},
313 {tok::exclaimequal, tok::question},
314 {tok::equalequal, tok::equal},
315 {tok::equalequal, tok::question}},
316 TT_BinaryOperator)) {
317 return;
318 }
319 // Module paths in specify blocks and the implication and boolean equality
320 // operators.
321 if (tryMergeTokensAny({{tok::plusequal, tok::greater},
322 {tok::plus, tok::star, tok::greater},
323 {tok::minusequal, tok::greater},
324 {tok::minus, tok::star, tok::greater},
325 {tok::less, tok::arrow},
326 {tok::equal, tok::greater},
327 {tok::star, tok::greater},
328 {tok::pipeequal, tok::greater},
329 {tok::pipe, tok::arrow}},
330 TT_BinaryOperator) ||
331 Tokens.back()->is(tok::arrow)) {
332 Tokens.back()->ForcedPrecedence = prec::Comma;
333 return;
334 }
335 if (Tokens.size() >= 3 &&
336 Tokens[Tokens.size() - 3]->is(Keywords.kw_verilogHash) &&
337 Tokens[Tokens.size() - 2]->isOneOf(tok::minus, tok::equal) &&
338 Tokens[Tokens.size() - 1]->is(Keywords.kw_verilogHash) &&
339 tryMergeTokens(3, TT_BinaryOperator)) {
340 Tokens.back()->setFinalizedType(TT_BinaryOperator);
341 Tokens.back()->ForcedPrecedence = prec::Comma;
342 return;
343 }
344 } else if (Style.isTableGen()) {
345 // TableGen's Multi line string starts with [{
346 if (tryMergeTokens({tok::l_square, tok::l_brace},
347 TT_TableGenMultiLineString)) {
348 // Set again with finalizing. This must never be annotated as other types.
349 Tokens.back()->setFinalizedType(TT_TableGenMultiLineString);
350 Tokens.back()->Tok.setKind(tok::string_literal);
351 return;
352 }
353 // TableGen's bang operator is the form !<name>.
354 // !cond is a special case with specific syntax.
355 if (tryMergeTokens({tok::exclaim, tok::identifier},
356 TT_TableGenBangOperator)) {
357 Tokens.back()->Tok.setKind(tok::identifier);
358 Tokens.back()->Tok.setIdentifierInfo(nullptr);
359 if (Tokens.back()->TokenText == "!cond")
360 Tokens.back()->setFinalizedType(TT_TableGenCondOperator);
361 else
362 Tokens.back()->setFinalizedType(TT_TableGenBangOperator);
363 return;
364 }
365 if (tryMergeTokens({tok::exclaim, tok::kw_if}, TT_TableGenBangOperator)) {
366 // Here, "! if" becomes "!if". That is, ! captures if even when the space
367 // exists. That is only one possibility in TableGen's syntax.
368 Tokens.back()->Tok.setKind(tok::identifier);
369 Tokens.back()->Tok.setIdentifierInfo(nullptr);
370 Tokens.back()->setFinalizedType(TT_TableGenBangOperator);
371 return;
372 }
373 // +, - with numbers are literals. Not unary operators.
374 if (tryMergeTokens({tok::plus, tok::numeric_constant}, TT_Unknown)) {
375 Tokens.back()->Tok.setKind(tok::numeric_constant);
376 return;
377 }
378 if (tryMergeTokens({tok::minus, tok::numeric_constant}, TT_Unknown)) {
379 Tokens.back()->Tok.setKind(tok::numeric_constant);
380 return;
381 }
382 }
383}
384
385bool FormatTokenLexer::tryMergeNSStringLiteral() {
386 if (Tokens.size() < 2)
387 return false;
388 auto &At = *(Tokens.end() - 2);
389 auto &String = *(Tokens.end() - 1);
390 if (At->isNot(tok::at) || String->isNot(tok::string_literal))
391 return false;
392 At->Tok.setKind(tok::string_literal);
393 At->TokenText = StringRef(At->TokenText.begin(),
394 String->TokenText.end() - At->TokenText.begin());
395 At->ColumnWidth += String->ColumnWidth;
396 At->setType(TT_ObjCStringLiteral);
397 Tokens.erase(Tokens.end() - 1);
398 return true;
399}
400
401bool FormatTokenLexer::tryMergeJSPrivateIdentifier() {
402 // Merges #idenfier into a single identifier with the text #identifier
403 // but the token tok::identifier.
404 if (Tokens.size() < 2)
405 return false;
406 auto &Hash = *(Tokens.end() - 2);
407 auto &Identifier = *(Tokens.end() - 1);
408 if (Hash->isNot(tok::hash) || Identifier->isNot(tok::identifier))
409 return false;
410 Hash->Tok.setKind(tok::identifier);
411 Hash->TokenText =
412 StringRef(Hash->TokenText.begin(),
413 Identifier->TokenText.end() - Hash->TokenText.begin());
414 Hash->ColumnWidth += Identifier->ColumnWidth;
415 Hash->setType(TT_JsPrivateIdentifier);
416 Tokens.erase(Tokens.end() - 1);
417 return true;
418}
419
420// Search for verbatim or interpolated string literals @"ABC" or
421// $"aaaaa{abc}aaaaa" i and mark the token as TT_CSharpStringLiteral, and to
422// prevent splitting of @, $ and ".
423// Merging of multiline verbatim strings with embedded '"' is handled in
424// handleCSharpVerbatimAndInterpolatedStrings with lower-level lexing.
425bool FormatTokenLexer::tryMergeCSharpStringLiteral() {
426 if (Tokens.size() < 2)
427 return false;
428
429 // Look for @"aaaaaa" or $"aaaaaa".
430 const auto String = *(Tokens.end() - 1);
431 if (String->isNot(tok::string_literal))
432 return false;
433
434 auto Prefix = *(Tokens.end() - 2);
435 if (Prefix->isNot(tok::at) && Prefix->TokenText != "$")
436 return false;
437
438 if (Tokens.size() > 2) {
439 const auto Tok = *(Tokens.end() - 3);
440 if ((Tok->TokenText == "$" && Prefix->is(tok::at)) ||
441 (Tok->is(tok::at) && Prefix->TokenText == "$")) {
442 // This looks like $@"aaa" or @$"aaa" so we need to combine all 3 tokens.
443 Tok->ColumnWidth += Prefix->ColumnWidth;
444 Tokens.erase(Tokens.end() - 2);
445 Prefix = Tok;
446 }
447 }
448
449 // Convert back into just a string_literal.
450 Prefix->Tok.setKind(tok::string_literal);
451 Prefix->TokenText =
452 StringRef(Prefix->TokenText.begin(),
453 String->TokenText.end() - Prefix->TokenText.begin());
454 Prefix->ColumnWidth += String->ColumnWidth;
455 Prefix->setType(TT_CSharpStringLiteral);
456 Tokens.erase(Tokens.end() - 1);
457 return true;
458}
459
460bool FormatTokenLexer::tryMergeCSharpUtf8StringLiteral() {
461 if (Tokens.size() < 2)
462 return false;
463
464 const auto *Suffix = Tokens.back();
465 if (Suffix->TokenText != "u8" || Suffix->hasWhitespaceBefore())
466 return false;
467
468 auto *String = *(Tokens.end() - 2);
469 if (String->isNot(tok::string_literal))
470 return false;
471
472 String->Tok.setKind(tok::utf8_string_literal);
473 String->TokenText =
474 StringRef(String->TokenText.begin(),
475 Suffix->TokenText.end() - String->TokenText.begin());
476 String->ColumnWidth += Suffix->ColumnWidth;
477 String->setFinalizedType(TT_CSharpStringLiteral);
478 Tokens.pop_back();
479 return true;
480}
481
482// Valid C# attribute targets:
483// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets
484const llvm::StringSet<> FormatTokenLexer::CSharpAttributeTargets = {
485 "assembly", "module", "field", "event", "method",
486 "param", "property", "return", "type",
487};
488
489bool FormatTokenLexer::tryMergeNullishCoalescingEqual() {
490 if (Tokens.size() < 2)
491 return false;
492 auto &NullishCoalescing = *(Tokens.end() - 2);
493 auto &Equal = *(Tokens.end() - 1);
494 if (NullishCoalescing->isNot(TT_NullCoalescingOperator) ||
495 Equal->isNot(tok::equal)) {
496 return false;
497 }
498 NullishCoalescing->Tok.setKind(tok::equal); // no '??=' in clang tokens.
499 NullishCoalescing->TokenText =
500 StringRef(NullishCoalescing->TokenText.begin(),
501 Equal->TokenText.end() - NullishCoalescing->TokenText.begin());
502 NullishCoalescing->ColumnWidth += Equal->ColumnWidth;
503 NullishCoalescing->setType(TT_NullCoalescingEqual);
504 Tokens.erase(Tokens.end() - 1);
505 return true;
506}
507
508bool FormatTokenLexer::tryMergeCSharpKeywordVariables() {
509 if (Tokens.size() < 2)
510 return false;
511 const auto At = *(Tokens.end() - 2);
512 if (At->isNot(tok::at))
513 return false;
514 const auto Keyword = *(Tokens.end() - 1);
515 if (Keyword->TokenText == "$")
516 return false;
517 if (!Keywords.isCSharpKeyword(*Keyword))
518 return false;
519
520 At->Tok.setKind(tok::identifier);
521 At->TokenText = StringRef(At->TokenText.begin(),
522 Keyword->TokenText.end() - At->TokenText.begin());
523 At->ColumnWidth += Keyword->ColumnWidth;
524 At->setType(Keyword->getType());
525 Tokens.erase(Tokens.end() - 1);
526 return true;
527}
528
529// In C# transform identifier foreach into kw_foreach
530bool FormatTokenLexer::tryTransformCSharpForEach() {
531 if (Tokens.empty())
532 return false;
533 auto &Identifier = *(Tokens.end() - 1);
534 if (Identifier->isNot(tok::identifier))
535 return false;
536 if (Identifier->TokenText != "foreach")
537 return false;
538
539 Identifier->setType(TT_ForEachMacro);
540 Identifier->Tok.setKind(tok::kw_for);
541 return true;
542}
543
544bool FormatTokenLexer::tryMergeForEach() {
545 if (Tokens.size() < 2)
546 return false;
547 auto &For = *(Tokens.end() - 2);
548 auto &Each = *(Tokens.end() - 1);
549 if (For->isNot(tok::kw_for))
550 return false;
551 if (Each->isNot(tok::identifier))
552 return false;
553 if (Each->TokenText != "each")
554 return false;
555
556 For->setType(TT_ForEachMacro);
557 For->Tok.setKind(tok::kw_for);
558
559 For->TokenText = StringRef(For->TokenText.begin(),
560 Each->TokenText.end() - For->TokenText.begin());
561 For->ColumnWidth += Each->ColumnWidth;
562 Tokens.erase(Tokens.end() - 1);
563 return true;
564}
565
566bool FormatTokenLexer::tryMergeLessLess() {
567 // Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
568 if (Tokens.size() < 3)
569 return false;
570
571 auto First = Tokens.end() - 3;
572 if (First[0]->isNot(tok::less) || First[1]->isNot(tok::less))
573 return false;
574
575 // Only merge if there currently is no whitespace between the two "<".
576 if (First[1]->hasWhitespaceBefore())
577 return false;
578
579 auto X = Tokens.size() > 3 ? First[-1] : nullptr;
580 if (X && X->is(tok::less))
581 return false;
582
583 auto Y = First[2];
584 if ((!X || X->isNot(tok::kw_operator)) && Y->is(tok::less))
585 return false;
586
587 First[0]->Tok.setKind(tok::lessless);
588 First[0]->TokenText = "<<";
589 First[0]->ColumnWidth += 1;
590 Tokens.erase(Tokens.end() - 2);
591 return true;
592}
593
594bool FormatTokenLexer::tryMergeGreaterGreater() {
595 // Merge kw_operator,greater,greater into kw_operator,greatergreater.
596 if (Tokens.size() < 2)
597 return false;
598
599 auto First = Tokens.end() - 2;
600 if (First[0]->isNot(tok::greater) || First[1]->isNot(tok::greater))
601 return false;
602
603 // Only merge if there currently is no whitespace between the first two ">".
604 if (First[1]->hasWhitespaceBefore())
605 return false;
606
607 auto Tok = Tokens.size() > 2 ? First[-1] : nullptr;
608 if (Tok && Tok->isNot(tok::kw_operator))
609 return false;
610
611 First[0]->Tok.setKind(tok::greatergreater);
612 First[0]->TokenText = ">>";
613 First[0]->ColumnWidth += 1;
614 Tokens.erase(Tokens.end() - 1);
615 return true;
616}
617
618bool FormatTokenLexer::tryMergeUserDefinedLiteral() {
619 if (Tokens.size() < 2)
620 return false;
621
622 auto *First = Tokens.end() - 2;
623 auto &Suffix = First[1];
624 if (Suffix->hasWhitespaceBefore() || Suffix->TokenText != "$")
625 return false;
626
627 auto &Literal = First[0];
628 if (!Literal->Tok.isLiteral())
629 return false;
630
631 auto &Text = Literal->TokenText;
632 if (!Text.ends_with("_"))
633 return false;
634
635 Text = StringRef(Text.data(), Text.size() + 1);
636 ++Literal->ColumnWidth;
637 Tokens.erase(&Suffix);
638 return true;
639}
640
641bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
642 TokenType NewType) {
643 if (Tokens.size() < Kinds.size())
644 return false;
645
646 const auto *First = Tokens.end() - Kinds.size();
647 for (unsigned i = 0; i < Kinds.size(); ++i)
648 if (First[i]->isNot(Kinds[i]))
649 return false;
650
651 return tryMergeTokens(Kinds.size(), NewType);
652}
653
654bool FormatTokenLexer::tryMergeTokens(size_t Count, TokenType NewType) {
655 if (Tokens.size() < Count)
656 return false;
657
658 const auto *First = Tokens.end() - Count;
659 unsigned AddLength = 0;
660 for (size_t i = 1; i < Count; ++i) {
661 // If there is whitespace separating the token and the previous one,
662 // they should not be merged.
663 if (First[i]->hasWhitespaceBefore())
664 return false;
665 AddLength += First[i]->TokenText.size();
666 }
667
668 Tokens.resize(Tokens.size() - Count + 1);
669 First[0]->TokenText = StringRef(First[0]->TokenText.data(),
670 First[0]->TokenText.size() + AddLength);
671 First[0]->ColumnWidth += AddLength;
672 First[0]->setType(NewType);
673 return true;
674}
675
676bool FormatTokenLexer::tryMergeTokensAny(
678 return llvm::any_of(Kinds, [this, NewType](ArrayRef<tok::TokenKind> Kinds) {
679 return tryMergeTokens(Kinds, NewType);
680 });
681}
682
683// Returns \c true if \p Tok can only be followed by an operand in JavaScript.
684bool FormatTokenLexer::precedesOperand(FormatToken *Tok) {
685 // NB: This is not entirely correct, as an r_paren can introduce an operand
686 // location in e.g. `if (foo) /bar/.exec(...);`. That is a rare enough
687 // corner case to not matter in practice, though.
688 return Tok->isOneOf(tok::period, tok::l_paren, tok::comma, tok::l_brace,
689 tok::r_brace, tok::l_square, tok::semi, tok::exclaim,
690 tok::colon, tok::question, tok::tilde) ||
691 Tok->isOneOf(tok::kw_return, tok::kw_do, tok::kw_case, tok::kw_throw,
692 tok::kw_else, tok::kw_void, tok::kw_typeof,
693 Keywords.kw_instanceof, Keywords.kw_in) ||
694 Tok->isPlacementOperator() || Tok->isBinaryOperator();
695}
696
697bool FormatTokenLexer::canPrecedeRegexLiteral(FormatToken *Prev) {
698 if (!Prev)
699 return true;
700
701 // Regex literals can only follow after prefix unary operators, not after
702 // postfix unary operators. If the '++' is followed by a non-operand
703 // introducing token, the slash here is the operand and not the start of a
704 // regex.
705 // `!` is an unary prefix operator, but also a post-fix operator that casts
706 // away nullability, so the same check applies.
707 if (Prev->isOneOf(tok::plusplus, tok::minusminus, tok::exclaim))
708 return Tokens.size() < 3 || precedesOperand(Tokens[Tokens.size() - 3]);
709
710 // The previous token must introduce an operand location where regex
711 // literals can occur.
712 if (!precedesOperand(Prev))
713 return false;
714
715 return true;
716}
717
718void FormatTokenLexer::tryParseJavaTextBlock() {
719 if (FormatTok->TokenText != "\"\"")
720 return;
721
722 const auto *S = Lex->getBufferLocation();
723 const auto *End = Lex->getBuffer().end();
724
725 if (S == End || *S != '\"')
726 return;
727
728 ++S; // Skip the `"""` that begins a text block.
729
730 // Find the `"""` that ends the text block.
731 bool Escaped = false;
732 for (int Count = 0; Count < 3 && S < End; ++S) {
733 if (Escaped) {
734 Escaped = false;
735 continue;
736 }
737 switch (*S) {
738 case '\"':
739 ++Count;
740 break;
741 case '\\':
742 Escaped = true;
743 [[fallthrough]];
744 default:
745 Count = 0;
746 }
747 }
748
749 // Ignore the possibly invalid text block.
750 resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(S)));
751}
752
753// Tries to parse a JavaScript Regex literal starting at the current token,
754// if that begins with a slash and is in a location where JavaScript allows
755// regex literals. Changes the current token to a regex literal and updates
756// its text if successful.
757void FormatTokenLexer::tryParseJSRegexLiteral() {
758 FormatToken *RegexToken = Tokens.back();
759 if (RegexToken->isNoneOf(tok::slash, tok::slashequal))
760 return;
761
762 FormatToken *Prev = nullptr;
763 for (FormatToken *FT : llvm::drop_begin(llvm::reverse(Tokens))) {
764 // NB: Because previous pointers are not initialized yet, this cannot use
765 // Token.getPreviousNonComment.
766 if (FT->isNot(tok::comment)) {
767 Prev = FT;
768 break;
769 }
770 }
771
772 if (!canPrecedeRegexLiteral(Prev))
773 return;
774
775 // 'Manually' lex ahead in the current file buffer.
776 const char *Offset = Lex->getBufferLocation();
777 const char *RegexBegin = Offset - RegexToken->TokenText.size();
778 StringRef Buffer = Lex->getBuffer();
779 bool InCharacterClass = false;
780 bool HaveClosingSlash = false;
781 for (; !HaveClosingSlash && Offset != Buffer.end(); ++Offset) {
782 // Regular expressions are terminated with a '/', which can only be
783 // escaped using '\' or a character class between '[' and ']'.
784 // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5.
785 switch (*Offset) {
786 case '\\':
787 // Skip the escaped character.
788 ++Offset;
789 break;
790 case '[':
791 InCharacterClass = true;
792 break;
793 case ']':
794 InCharacterClass = false;
795 break;
796 case '/':
797 if (!InCharacterClass)
798 HaveClosingSlash = true;
799 break;
800 }
801 }
802
803 RegexToken->setType(TT_RegexLiteral);
804 // Treat regex literals like other string_literals.
805 RegexToken->Tok.setKind(tok::string_literal);
806 RegexToken->TokenText = StringRef(RegexBegin, Offset - RegexBegin);
807 RegexToken->ColumnWidth = RegexToken->TokenText.size();
808
809 resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
810}
811
812static auto lexCSharpString(const char *Begin, const char *End, bool Verbatim,
813 bool Interpolated) {
814 auto Repeated = [&Begin, End]() {
815 return Begin + 1 < End && Begin[1] == Begin[0];
816 };
817
818 // Look for a terminating '"' in the current file buffer.
819 // Make no effort to format code within an interpolated or verbatim string.
820 //
821 // Interpolated strings could contain { } with " characters inside.
822 // $"{x ?? "null"}"
823 // should not be split into $"{x ?? ", null, "}" but should be treated as a
824 // single string-literal.
825 //
826 // We opt not to try and format expressions inside {} within a C#
827 // interpolated string. Formatting expressions within an interpolated string
828 // would require similar work as that done for JavaScript template strings
829 // in `handleTemplateStrings()`.
830 for (int UnmatchedOpeningBraceCount = 0; Begin < End; ++Begin) {
831 switch (*Begin) {
832 case '\\':
833 if (!Verbatim)
834 ++Begin;
835 break;
836 case '{':
837 if (Interpolated) {
838 // {{ inside an interpolated string is escaped, so skip it.
839 if (Repeated())
840 ++Begin;
841 else
842 ++UnmatchedOpeningBraceCount;
843 }
844 break;
845 case '}':
846 if (Interpolated) {
847 // }} inside an interpolated string is escaped, so skip it.
848 if (Repeated())
849 ++Begin;
850 else if (UnmatchedOpeningBraceCount > 0)
851 --UnmatchedOpeningBraceCount;
852 else
853 return End;
854 }
855 break;
856 case '"':
857 if (UnmatchedOpeningBraceCount > 0)
858 break;
859 // "" within a verbatim string is an escaped double quote: skip it.
860 if (Verbatim && Repeated()) {
861 ++Begin;
862 break;
863 }
864 return Begin;
865 }
866 }
867
868 return End;
869}
870
871void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
872 FormatToken *CSharpStringLiteral = Tokens.back();
873
874 if (CSharpStringLiteral->isNot(TT_CSharpStringLiteral))
875 return;
876
877 auto &TokenText = CSharpStringLiteral->TokenText;
878
879 bool Verbatim = false;
880 bool Interpolated = false;
881 const bool Utf8 = TokenText.ends_with("u8");
882 if (TokenText.starts_with(R"($@")") || TokenText.starts_with(R"(@$")")) {
883 Verbatim = true;
884 Interpolated = true;
885 } else if (TokenText.starts_with(R"(@")")) {
886 Verbatim = true;
887 } else if (TokenText.starts_with(R"($")")) {
888 Interpolated = true;
889 }
890
891 // Deal with multiline strings.
892 if (!Verbatim && !Interpolated)
893 return;
894
895 const char *StrBegin = Lex->getBufferLocation() - TokenText.size();
896 const char *Offset = StrBegin;
897 Offset += Verbatim && Interpolated ? 3 : 2;
898
899 const auto End = Lex->getBuffer().end();
900 Offset = lexCSharpString(Offset, End, Verbatim, Interpolated);
901
902 if (Utf8)
903 Offset += 2;
904
905 // Make no attempt to format code properly if a verbatim string is
906 // unterminated.
907 if (Offset >= End)
908 return;
909
910 StringRef LiteralText(StrBegin, Offset - StrBegin + 1);
911 TokenText = LiteralText;
912
913 // Adjust width for potentially multiline string literals.
914 size_t FirstBreak = LiteralText.find('\n');
915 StringRef FirstLineText = FirstBreak == StringRef::npos
916 ? LiteralText
917 : LiteralText.substr(0, FirstBreak);
918 CSharpStringLiteral->ColumnWidth = encoding::columnWidthWithTabs(
919 FirstLineText, CSharpStringLiteral->OriginalColumn, Style.TabWidth,
920 Encoding);
921 size_t LastBreak = LiteralText.rfind('\n');
922 if (LastBreak != StringRef::npos) {
923 CSharpStringLiteral->IsMultiline = true;
924 unsigned StartColumn = 0;
925 CSharpStringLiteral->LastLineColumnWidth =
926 encoding::columnWidthWithTabs(LiteralText.substr(LastBreak + 1),
927 StartColumn, Style.TabWidth, Encoding);
928 }
929
930 assert(Offset < End);
931 resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset + 1)));
932}
933
934void FormatTokenLexer::handleTableGenMultilineString() {
935 FormatToken *MultiLineString = Tokens.back();
936 if (MultiLineString->isNot(TT_TableGenMultiLineString))
937 return;
938
939 auto OpenOffset = Lex->getCurrentBufferOffset() - 2 /* "[{" */;
940 // "}]" is the end of multi line string.
941 auto CloseOffset = Lex->getBuffer().find("}]", OpenOffset);
942 if (CloseOffset == StringRef::npos)
943 return;
944 auto Text = Lex->getBuffer().substr(OpenOffset, CloseOffset - OpenOffset + 2);
945 MultiLineString->TokenText = Text;
946 resetLexer(SourceMgr.getFileOffset(
947 Lex->getSourceLocation(Lex->getBufferLocation() - 2 + Text.size())));
948 auto FirstLineText = Text;
949 auto FirstBreak = Text.find('\n');
950 // Set ColumnWidth and LastLineColumnWidth when it has multiple lines.
951 if (FirstBreak != StringRef::npos) {
952 MultiLineString->IsMultiline = true;
953 FirstLineText = Text.substr(0, FirstBreak + 1);
954 // LastLineColumnWidth holds the width of the last line.
955 auto LastBreak = Text.rfind('\n');
956 MultiLineString->LastLineColumnWidth = encoding::columnWidthWithTabs(
957 Text.substr(LastBreak + 1), MultiLineString->OriginalColumn,
958 Style.TabWidth, Encoding);
959 }
960 // ColumnWidth holds only the width of the first line.
961 MultiLineString->ColumnWidth = encoding::columnWidthWithTabs(
962 FirstLineText, MultiLineString->OriginalColumn, Style.TabWidth, Encoding);
963}
964
965void FormatTokenLexer::handleTableGenNumericLikeIdentifier() {
966 FormatToken *Tok = Tokens.back();
967 // TableGen identifiers can begin with digits. Such tokens are lexed as
968 // numeric_constant now.
969 if (Tok->isNot(tok::numeric_constant))
970 return;
971 StringRef Text = Tok->TokenText;
972 // The following check is based on llvm::TGLexer::LexToken.
973 // That lexes the token as a number if any of the following holds:
974 // 1. It starts with '+', '-'.
975 // 2. All the characters are digits.
976 // 3. The first non-digit character is 'b', and the next is '0' or '1'.
977 // 4. The first non-digit character is 'x', and the next is a hex digit.
978 // Note that in the case 3 and 4, if the next character does not exists in
979 // this token, the token is an identifier.
980 if (Text.empty() || Text[0] == '+' || Text[0] == '-')
981 return;
982 const auto NonDigitPos = Text.find_if([](char C) { return !isdigit(C); });
983 // All the characters are digits
984 if (NonDigitPos == StringRef::npos)
985 return;
986 char FirstNonDigit = Text[NonDigitPos];
987 if (NonDigitPos < Text.size() - 1) {
988 char TheNext = Text[NonDigitPos + 1];
989 // Regarded as a binary number.
990 if (FirstNonDigit == 'b' && (TheNext == '0' || TheNext == '1'))
991 return;
992 // Regarded as hex number.
993 if (FirstNonDigit == 'x' && isxdigit(TheNext))
994 return;
995 }
996 if (isalpha(FirstNonDigit) || FirstNonDigit == '_') {
997 // This is actually an identifier in TableGen.
998 Tok->Tok.setKind(tok::identifier);
999 Tok->Tok.setIdentifierInfo(nullptr);
1000 }
1001}
1002
1003void FormatTokenLexer::handleTemplateStrings() {
1004 FormatToken *BacktickToken = Tokens.back();
1005
1006 if (BacktickToken->is(tok::l_brace)) {
1007 StateStack.push(LexerState::NORMAL);
1008 return;
1009 }
1010 if (BacktickToken->is(tok::r_brace)) {
1011 if (StateStack.size() == 1)
1012 return;
1013 StateStack.pop();
1014 if (StateStack.top() != LexerState::TEMPLATE_STRING)
1015 return;
1016 // If back in TEMPLATE_STRING, fallthrough and continue parsing the
1017 } else if (BacktickToken->is(tok::unknown) &&
1018 BacktickToken->TokenText == "`") {
1019 StateStack.push(LexerState::TEMPLATE_STRING);
1020 } else {
1021 return; // Not actually a template
1022 }
1023
1024 // 'Manually' lex ahead in the current file buffer.
1025 const char *Offset = Lex->getBufferLocation();
1026 const char *TmplBegin = Offset - BacktickToken->TokenText.size(); // at "`"
1027 for (; Offset != Lex->getBuffer().end(); ++Offset) {
1028 if (Offset[0] == '`') {
1029 StateStack.pop();
1030 ++Offset;
1031 break;
1032 }
1033 if (Offset[0] == '\\') {
1034 ++Offset; // Skip the escaped character.
1035 } else if (Offset + 1 < Lex->getBuffer().end() && Offset[0] == '$' &&
1036 Offset[1] == '{') {
1037 // '${' introduces an expression interpolation in the template string.
1038 StateStack.push(LexerState::NORMAL);
1039 Offset += 2;
1040 break;
1041 }
1042 }
1043
1044 StringRef LiteralText(TmplBegin, Offset - TmplBegin);
1045 BacktickToken->setType(TT_TemplateString);
1046 BacktickToken->Tok.setKind(tok::string_literal);
1047 BacktickToken->TokenText = LiteralText;
1048
1049 // Adjust width for potentially multiline string literals.
1050 size_t FirstBreak = LiteralText.find('\n');
1051 StringRef FirstLineText = FirstBreak == StringRef::npos
1052 ? LiteralText
1053 : LiteralText.substr(0, FirstBreak);
1054 BacktickToken->ColumnWidth = encoding::columnWidthWithTabs(
1055 FirstLineText, BacktickToken->OriginalColumn, Style.TabWidth, Encoding);
1056 size_t LastBreak = LiteralText.rfind('\n');
1057 if (LastBreak != StringRef::npos) {
1058 BacktickToken->IsMultiline = true;
1059 unsigned StartColumn = 0; // The template tail spans the entire line.
1060 BacktickToken->LastLineColumnWidth =
1061 encoding::columnWidthWithTabs(LiteralText.substr(LastBreak + 1),
1062 StartColumn, Style.TabWidth, Encoding);
1063 }
1064
1065 SourceLocation loc = Lex->getSourceLocation(Offset);
1066 resetLexer(SourceMgr.getFileOffset(loc));
1067}
1068
1069void FormatTokenLexer::tryParsePythonComment() {
1070 FormatToken *HashToken = Tokens.back();
1071 if (HashToken->isNoneOf(tok::hash, tok::hashhash))
1072 return;
1073 // Turn the remainder of this line into a comment.
1074 const char *CommentBegin =
1075 Lex->getBufferLocation() - HashToken->TokenText.size(); // at "#"
1076 size_t From = CommentBegin - Lex->getBuffer().begin();
1077 size_t To = Lex->getBuffer().find_first_of('\n', From);
1078 if (To == StringRef::npos)
1079 To = Lex->getBuffer().size();
1080 size_t Len = To - From;
1081 HashToken->setType(TT_LineComment);
1082 HashToken->Tok.setKind(tok::comment);
1083 HashToken->TokenText = Lex->getBuffer().substr(From, Len);
1084 SourceLocation Loc = To < Lex->getBuffer().size()
1085 ? Lex->getSourceLocation(CommentBegin + Len)
1086 : SourceMgr.getLocForEndOfFile(ID);
1087 resetLexer(SourceMgr.getFileOffset(Loc));
1088}
1089
1090bool FormatTokenLexer::tryMerge_TMacro() {
1091 if (Tokens.size() < 4)
1092 return false;
1093 FormatToken *Last = Tokens.back();
1094 if (Last->isNot(tok::r_paren))
1095 return false;
1096
1097 FormatToken *String = Tokens[Tokens.size() - 2];
1098 if (String->isNot(tok::string_literal) || String->IsMultiline)
1099 return false;
1100
1101 if (Tokens[Tokens.size() - 3]->isNot(tok::l_paren))
1102 return false;
1103
1104 FormatToken *Macro = Tokens[Tokens.size() - 4];
1105 if (Macro->TokenText != "_T")
1106 return false;
1107
1108 const char *Start = Macro->TokenText.data();
1109 const char *End = Last->TokenText.data() + Last->TokenText.size();
1110 String->TokenText = StringRef(Start, End - Start);
1111 String->IsFirst = Macro->IsFirst;
1112 String->LastNewlineOffset = Macro->LastNewlineOffset;
1113 String->WhitespaceRange = Macro->WhitespaceRange;
1114 String->OriginalColumn = Macro->OriginalColumn;
1115 String->ColumnWidth = encoding::columnWidthWithTabs(
1116 String->TokenText, String->OriginalColumn, Style.TabWidth, Encoding);
1117 String->NewlinesBefore = Macro->NewlinesBefore;
1118 String->HasUnescapedNewline = Macro->HasUnescapedNewline;
1119
1120 Tokens.pop_back();
1121 Tokens.pop_back();
1122 Tokens.pop_back();
1123 Tokens.back() = String;
1124 if (FirstInLineIndex >= Tokens.size())
1125 FirstInLineIndex = Tokens.size() - 1;
1126 return true;
1127}
1128
1129bool FormatTokenLexer::tryMergeConflictMarkers() {
1130 if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof))
1131 return false;
1132
1133 // Conflict lines look like:
1134 // <marker> <text from the vcs>
1135 // For example:
1136 // >>>>>>> /file/in/file/system at revision 1234
1137 //
1138 // We merge all tokens in a line that starts with a conflict marker
1139 // into a single token with a special token type that the unwrapped line
1140 // parser will use to correctly rebuild the underlying code.
1141
1142 FileID ID;
1143 // Get the position of the first token in the line.
1144 unsigned FirstInLineOffset;
1145 std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc(
1146 Tokens[FirstInLineIndex]->getStartOfNonWhitespace());
1147 StringRef Buffer = SourceMgr.getBufferOrFake(ID).getBuffer();
1148 // Calculate the offset of the start of the current line.
1149 auto LineOffset = Buffer.rfind('\n', FirstInLineOffset);
1150 if (LineOffset == StringRef::npos)
1151 LineOffset = 0;
1152 else
1153 ++LineOffset;
1154
1155 auto FirstSpace = Buffer.find_first_of(" \n", LineOffset);
1156 StringRef LineStart;
1157 if (FirstSpace == StringRef::npos)
1158 LineStart = Buffer.substr(LineOffset);
1159 else
1160 LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
1161
1162 TokenType Type = TT_Unknown;
1163 if (LineStart == "<<<<<<<" || LineStart == ">>>>") {
1164 Type = TT_ConflictStart;
1165 } else if (LineStart == "|||||||" || LineStart == "=======" ||
1166 LineStart == "====") {
1167 Type = TT_ConflictAlternative;
1168 } else if (LineStart == ">>>>>>>" || LineStart == "<<<<") {
1169 Type = TT_ConflictEnd;
1170 }
1171
1172 if (Type != TT_Unknown) {
1173 FormatToken *Next = Tokens.back();
1174
1175 Tokens.resize(FirstInLineIndex + 1);
1176 // We do not need to build a complete token here, as we will skip it
1177 // during parsing anyway (as we must not touch whitespace around conflict
1178 // markers).
1179 Tokens.back()->setType(Type);
1180 Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
1181
1182 Tokens.push_back(Next);
1183 return true;
1184 }
1185
1186 return false;
1187}
1188
1189FormatToken *FormatTokenLexer::getStashedToken() {
1190 // Create a synthesized second '>' or '<' token.
1191 Token Tok = FormatTok->Tok;
1192 StringRef TokenText = FormatTok->TokenText;
1193
1194 unsigned OriginalColumn = FormatTok->OriginalColumn;
1195 FormatTok = new (Allocator.Allocate()) FormatToken;
1196 FormatTok->Tok = Tok;
1197 SourceLocation TokLocation =
1198 FormatTok->Tok.getLocation().getLocWithOffset(Tok.getLength() - 1);
1199 FormatTok->Tok.setLocation(TokLocation);
1200 FormatTok->WhitespaceRange = SourceRange(TokLocation, TokLocation);
1201 FormatTok->TokenText = TokenText;
1202 FormatTok->ColumnWidth = 1;
1203 FormatTok->OriginalColumn = OriginalColumn + 1;
1204
1205 return FormatTok;
1206}
1207
1208/// Truncate the current token to the new length and make the lexer continue
1209/// from the end of the truncated token. Used for other languages that have
1210/// different token boundaries, like JavaScript in which a comment ends at a
1211/// line break regardless of whether the line break follows a backslash. Also
1212/// used to set the lexer to the end of whitespace if the lexer regards
1213/// whitespace and an unrecognized symbol as one token.
1214void FormatTokenLexer::truncateToken(size_t NewLen) {
1215 assert(NewLen <= FormatTok->TokenText.size());
1216 resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(
1217 Lex->getBufferLocation() - FormatTok->TokenText.size() + NewLen)));
1218 FormatTok->TokenText = FormatTok->TokenText.substr(0, NewLen);
1219 FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
1220 FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth,
1221 Encoding);
1222 FormatTok->Tok.setLength(NewLen);
1223}
1224
1225/// Count the length of leading whitespace in a token.
1226static size_t countLeadingWhitespace(StringRef Text) {
1227 // Basically counting the length matched by this regex.
1228 // "^([\n\r\f\v \t]|\\\\[\n\r])+"
1229 // Directly using the regex turned out to be slow. With the regex
1230 // version formatting all files in this directory took about 1.25
1231 // seconds. This version took about 0.5 seconds.
1232 const unsigned char *const Begin = Text.bytes_begin();
1233 const unsigned char *const End = Text.bytes_end();
1234 const unsigned char *Cur = Begin;
1235 while (Cur < End) {
1236 if (isWhitespace(Cur[0])) {
1237 ++Cur;
1238 } else if (Cur[0] == '\\') {
1239 // A backslash followed by optional horizontal whitespaces (P22232R2) and
1240 // then a newline always escapes the newline.
1241 // The source has a null byte at the end. So the end of the entire input
1242 // isn't reached yet. Also the lexer doesn't break apart an escaped
1243 // newline.
1244 const auto *Lookahead = Cur + 1;
1245 while (isHorizontalWhitespace(*Lookahead))
1246 ++Lookahead;
1247 // No line splice found; the backslash is a token.
1248 if (!isVerticalWhitespace(*Lookahead))
1249 break;
1250 // Splice found, consume it.
1251 Cur = Lookahead + 1;
1252 } else {
1253 break;
1254 }
1255 }
1256 return Cur - Begin;
1257}
1258
1259FormatToken *FormatTokenLexer::getNextToken() {
1260 if (StateStack.top() == LexerState::TOKEN_STASHED) {
1261 StateStack.pop();
1262 return getStashedToken();
1263 }
1264
1265 FormatTok = new (Allocator.Allocate()) FormatToken;
1266 readRawToken(*FormatTok);
1267 SourceLocation WhitespaceStart =
1268 FormatTok->Tok.getLocation().getLocWithOffset(-TrailingWhitespace);
1269 FormatTok->IsFirst = IsFirstToken;
1270 IsFirstToken = false;
1271
1272 // Consume and record whitespace until we find a significant token.
1273 // Some tok::unknown tokens are not just whitespace, e.g. whitespace
1274 // followed by a symbol such as backtick. Those symbols may be
1275 // significant in other languages.
1276 unsigned WhitespaceLength = TrailingWhitespace;
1277 while (FormatTok->isNot(tok::eof)) {
1278 auto LeadingWhitespace = countLeadingWhitespace(FormatTok->TokenText);
1279 if (LeadingWhitespace == 0)
1280 break;
1281 if (LeadingWhitespace < FormatTok->TokenText.size())
1282 truncateToken(LeadingWhitespace);
1283 StringRef Text = FormatTok->TokenText;
1284 bool InEscape = false;
1285 for (int i = 0, e = Text.size(); i != e; ++i) {
1286 switch (Text[i]) {
1287 case '\r':
1288 // If this is a CRLF sequence, break here and the LF will be handled on
1289 // the next loop iteration. Otherwise, this is a single Mac CR, treat it
1290 // the same as a single LF.
1291 if (i + 1 < e && Text[i + 1] == '\n')
1292 break;
1293 [[fallthrough]];
1294 case '\n':
1295 ++FormatTok->NewlinesBefore;
1296 if (!InEscape)
1297 FormatTok->HasUnescapedNewline = true;
1298 else
1299 InEscape = false;
1300 FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
1301 Column = 0;
1302 break;
1303 case '\f':
1304 if (Style.KeepFormFeed && !FormatTok->HasFormFeedBefore &&
1305 // The form feed is immediately preceded and followed by a newline.
1306 i > 0 && Text[i - 1] == '\n' &&
1307 ((i + 1 < e && Text[i + 1] == '\n') ||
1308 (i + 2 < e && Text[i + 1] == '\r' && Text[i + 2] == '\n'))) {
1309 FormatTok->HasFormFeedBefore = true;
1310 }
1311 [[fallthrough]];
1312 case '\v':
1313 Column = 0;
1314 break;
1315 case ' ':
1316 ++Column;
1317 break;
1318 case '\t':
1319 Column +=
1320 Style.TabWidth - (Style.TabWidth ? Column % Style.TabWidth : 0);
1321 break;
1322 case '\\':
1323 // The code preceding the loop and in the countLeadingWhitespace
1324 // function guarantees that Text is entirely whitespace, not including
1325 // comments but including escaped newlines. So the character shows up,
1326 // then it has to be in an escape sequence.
1327 assert([&]() -> bool {
1328 size_t j = i + 1;
1329 while (j < Text.size() && isHorizontalWhitespace(Text[j]))
1330 ++j;
1331 return j < Text.size() && (Text[j] == '\n' || Text[j] == '\r');
1332 }());
1333 InEscape = true;
1334 break;
1335 default:
1336 // This shouldn't happen.
1337 assert(false);
1338 break;
1339 }
1340 }
1341 WhitespaceLength += Text.size();
1342 readRawToken(*FormatTok);
1343 }
1344
1345 if (FormatTok->is(tok::unknown))
1346 FormatTok->setType(TT_ImplicitStringLiteral);
1347
1348 const bool IsCpp = Style.isCpp();
1349
1350 // JavaScript and Java do not allow to escape the end of the line with a
1351 // backslash. Backslashes are syntax errors in plain source, but can occur in
1352 // comments. When a single line comment ends with a \, it'll cause the next
1353 // line of code to be lexed as a comment, breaking formatting. The code below
1354 // finds comments that contain a backslash followed by a line break, truncates
1355 // the comment token at the backslash, and resets the lexer to restart behind
1356 // the backslash.
1357 if (const auto Text = FormatTok->TokenText;
1358 Text.starts_with("//") &&
1359 (IsCpp || Style.isJavaScript() || Style.isJava())) {
1360 assert(FormatTok->is(tok::comment));
1361 for (auto Pos = Text.find('\\'); Pos++ != StringRef::npos;
1362 Pos = Text.find('\\', Pos)) {
1363 if (Pos < Text.size() && Text[Pos] == '\n' &&
1364 (!IsCpp || Text.substr(Pos + 1).ltrim().starts_with("//"))) {
1365 truncateToken(Pos);
1366 break;
1367 }
1368 }
1369 }
1370
1371 if (Style.isVerilog()) {
1372 static const llvm::Regex NumberBase("^s?[bdho]", llvm::Regex::IgnoreCase);
1373 SmallVector<StringRef, 1> Matches;
1374 // Verilog uses the backtick instead of the hash for preprocessor stuff.
1375 // And it uses the hash for delays and parameter lists. In order to continue
1376 // using `tok::hash` in other places, the backtick gets marked as the hash
1377 // here. And in order to tell the backtick and hash apart for
1378 // Verilog-specific stuff, the hash becomes an identifier.
1379 if (FormatTok->is(tok::numeric_constant)) {
1380 // In Verilog the quote is not part of a number.
1381 auto Quote = FormatTok->TokenText.find('\'');
1382 if (Quote != StringRef::npos)
1383 truncateToken(Quote);
1384 } else if (FormatTok->isOneOf(tok::hash, tok::hashhash)) {
1385 FormatTok->Tok.setKind(tok::raw_identifier);
1386 } else if (FormatTok->is(tok::raw_identifier)) {
1387 if (FormatTok->TokenText == "`") {
1388 FormatTok->Tok.setIdentifierInfo(nullptr);
1389 FormatTok->Tok.setKind(tok::hash);
1390 } else if (FormatTok->TokenText == "``") {
1391 FormatTok->Tok.setIdentifierInfo(nullptr);
1392 FormatTok->Tok.setKind(tok::hashhash);
1393 } else if (!Tokens.empty() && Tokens.back()->is(Keywords.kw_apostrophe) &&
1394 NumberBase.match(FormatTok->TokenText, &Matches)) {
1395 // In Verilog in a based number literal like `'b10`, there may be
1396 // whitespace between `'b` and `10`. Therefore we handle the base and
1397 // the rest of the number literal as two tokens. But if there is no
1398 // space in the input code, we need to manually separate the two parts.
1399 truncateToken(Matches[0].size());
1400 FormatTok->setFinalizedType(TT_VerilogNumberBase);
1401 }
1402 }
1403 }
1404
1405 FormatTok->WhitespaceRange = SourceRange(
1406 WhitespaceStart, WhitespaceStart.getLocWithOffset(WhitespaceLength));
1407
1408 FormatTok->OriginalColumn = Column;
1409
1410 TrailingWhitespace = 0;
1411 if (FormatTok->is(tok::comment)) {
1412 // FIXME: Add the trimmed whitespace to Column.
1413 StringRef UntrimmedText = FormatTok->TokenText;
1414 FormatTok->TokenText = FormatTok->TokenText.rtrim(" \t\v\f");
1415 TrailingWhitespace = UntrimmedText.size() - FormatTok->TokenText.size();
1416 } else if (FormatTok->is(tok::raw_identifier)) {
1417 IdentifierInfo &Info = IdentTable.get(FormatTok->TokenText);
1418 FormatTok->Tok.setIdentifierInfo(&Info);
1419 FormatTok->Tok.setKind(Info.getTokenID());
1420 if (Style.isJava() &&
1421 FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete,
1422 tok::kw_operator)) {
1423 FormatTok->Tok.setKind(tok::identifier);
1424 } else if (Style.isJavaScript() &&
1425 FormatTok->isOneOf(tok::kw_struct, tok::kw_union,
1426 tok::kw_operator)) {
1427 FormatTok->Tok.setKind(tok::identifier);
1428 } else if (Style.isTableGen() && !Keywords.isTableGenKeyword(*FormatTok)) {
1429 FormatTok->Tok.setKind(tok::identifier);
1430 } else if (Style.isVerilog()) {
1431 if (Keywords.isVerilogIdentifier(*FormatTok))
1432 FormatTok->Tok.setKind(tok::identifier);
1433 // Look for the protect line. The next lines needs to be lexed as a single
1434 // token.
1435 if (Tokens.size() - FirstInLineIndex >= 3u &&
1436 Tokens[FirstInLineIndex]->is(tok::hash) &&
1437 Tokens[FirstInLineIndex + 1u]->is(tok::pp_pragma) &&
1438 Tokens[FirstInLineIndex + 2u]->is(Keywords.kw_protect) &&
1439 FormatTok->isOneOf(
1440 Keywords.kw_data_block, Keywords.kw_data_decrypt_key,
1441 Keywords.kw_data_public_key, Keywords.kw_digest_block,
1442 Keywords.kw_digest_decrypt_key, Keywords.kw_digest_public_key,
1443 Keywords.kw_key_block, Keywords.kw_key_public_key)) {
1444 VerilogProtectedBlock = true;
1445 }
1446 }
1447 } else if (const bool Greater = FormatTok->is(tok::greatergreater);
1448 Greater || FormatTok->is(tok::lessless)) {
1449 FormatTok->Tok.setKind(Greater ? tok::greater : tok::less);
1450 FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
1451 ++Column;
1452 StateStack.push(LexerState::TOKEN_STASHED);
1453 } else if (Style.isJava() && FormatTok->is(tok::string_literal)) {
1454 tryParseJavaTextBlock();
1455 }
1456
1457 if (Style.isVerilog() && !Tokens.empty() &&
1458 Tokens.back()->is(TT_VerilogNumberBase) &&
1459 FormatTok->Tok.isOneOf(tok::identifier, tok::question)) {
1460 // Mark the number following a base like `'h?a0` as a number.
1461 FormatTok->Tok.setKind(tok::numeric_constant);
1462 }
1463
1464 // Now FormatTok is the next non-whitespace token.
1465
1466 StringRef Text = FormatTok->TokenText;
1467 size_t FirstNewlinePos = Text.find('\n');
1468 if (FirstNewlinePos == StringRef::npos) {
1469 // FIXME: ColumnWidth actually depends on the start column, we need to
1470 // take this into account when the token is moved.
1471 FormatTok->ColumnWidth =
1472 encoding::columnWidthWithTabs(Text, Column, Style.TabWidth, Encoding);
1473 Column += FormatTok->ColumnWidth;
1474 } else {
1475 FormatTok->IsMultiline = true;
1476 // FIXME: ColumnWidth actually depends on the start column, we need to
1477 // take this into account when the token is moved.
1478 FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
1479 Text.substr(0, FirstNewlinePos), Column, Style.TabWidth, Encoding);
1480
1481 // The last line of the token always starts in column 0.
1482 // Thus, the length can be precomputed even in the presence of tabs.
1483 FormatTok->LastLineColumnWidth = encoding::columnWidthWithTabs(
1484 Text.substr(Text.find_last_of('\n') + 1), 0, Style.TabWidth, Encoding);
1485 Column = FormatTok->LastLineColumnWidth;
1486 }
1487
1488 if (IsCpp) {
1489 auto *Identifier = FormatTok->Tok.getIdentifierInfo();
1490 auto it = Macros.find(Identifier);
1491 if ((Tokens.empty() || !Tokens.back()->Tok.getIdentifierInfo() ||
1492 Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() !=
1493 tok::pp_define) &&
1494 it != Macros.end()) {
1495 FormatTok->setType(it->second);
1496 if (it->second == TT_IfMacro) {
1497 // The lexer token currently has type tok::kw_unknown. However, for this
1498 // substitution to be treated correctly in the TokenAnnotator, faking
1499 // the tok value seems to be needed. Not sure if there's a more elegant
1500 // way.
1501 FormatTok->Tok.setKind(tok::kw_if);
1502 }
1503 } else if (FormatTok->is(tok::identifier)) {
1504 if (MacroBlockBeginRegex.match(Text))
1505 FormatTok->setType(TT_MacroBlockBegin);
1506 else if (MacroBlockEndRegex.match(Text))
1507 FormatTok->setType(TT_MacroBlockEnd);
1508 else if (MacrosSkippedByRemoveParentheses.contains(Identifier))
1509 FormatTok->setFinalizedType(TT_FunctionLikeMacro);
1510 else if (TemplateNames.contains(Identifier))
1511 FormatTok->setFinalizedType(TT_TemplateName);
1512 else if (TypeNames.contains(Identifier))
1513 FormatTok->setFinalizedType(TT_TypeName);
1514 else if (VariableTemplates.contains(Identifier))
1515 FormatTok->setFinalizedType(TT_VariableTemplate);
1516 }
1517 }
1518
1519 return FormatTok;
1520}
1521
1522bool FormatTokenLexer::readVerilogProtected(FormatToken &Tok) {
1523 // The block follows the pragma line.
1524 if (!VerilogProtectedBlock || Tok.NewlinesBefore == 0)
1525 return false;
1526 VerilogProtectedBlock = false;
1527
1528 // The block can be empty. Then no token is necessary. A backtick on its own
1529 // line is likely a uuencode line. A backtick followed by something is assumed
1530 // to be the pragma line that ends the block.
1531 const char *const Start = Lex->getBufferLocation();
1532 size_t Len = Lex->getBuffer().end() - Start;
1533 if (Len == 0 ||
1534 (Len >= 2 && Start[0] == '`' && !isVerticalWhitespace(Start[1]))) {
1535 return false;
1536 }
1537
1538 // The block ends when the next pragma line starts.
1539 static const llvm::Regex NextDirective("[\n\r][ \t]*`[^\n\r]");
1540 SmallVector<StringRef, 1> Matches;
1541 if (NextDirective.match(StringRef(Start, Len), &Matches)) {
1542 assert(Matches.size() == 1);
1543 Len = Matches[0].begin() - Start;
1544 }
1545
1546 Tok.Tok.setKind(tok::string_literal);
1547 Tok.Tok.setLength(Len);
1548 Tok.Tok.setLocation(Lex->getSourceLocation(Start, Len));
1549 Tok.setFinalizedType(TT_VerilogProtected);
1550 Lex->seek(Lex->getCurrentBufferOffset() + Len,
1551 /*IsAtStartOfLine=*/false);
1552 return true;
1553}
1554
1555bool FormatTokenLexer::readRawTokenVerilogSpecific(FormatToken &Tok) {
1556 if (readVerilogProtected(Tok))
1557 return true;
1558 const char *Start = Lex->getBufferLocation();
1559 size_t Len;
1560 switch (Start[0]) {
1561 // In Verilog the quote is not a character literal.
1562 case '\'':
1563 Len = 1;
1564 break;
1565 // Make the backtick and double backtick identifiers to match against them
1566 // more easily.
1567 case '`':
1568 if (Start[1] == '`')
1569 Len = 2;
1570 else
1571 Len = 1;
1572 break;
1573 // In Verilog an escaped identifier starts with a backslash and ends with
1574 // whitespace. Unless that whitespace is an escaped newline.
1575 // FIXME: If there is an escaped newline in the middle of an escaped
1576 // identifier, allow for pasting the two lines together, But escaped
1577 // identifiers usually occur only in generated code anyway.
1578 case '\\':
1579 // A backslash can also begin an escaped newline outside of an escaped
1580 // identifier.
1581 if (Start[1] == '\r' || Start[1] == '\n')
1582 return false;
1583 Len = 1;
1584 while (Start[Len] != '\0' && Start[Len] != '\f' && Start[Len] != '\n' &&
1585 Start[Len] != '\r' && Start[Len] != '\t' && Start[Len] != '\v' &&
1586 Start[Len] != ' ') {
1587 // There is a null byte at the end of the buffer, so we don't have to
1588 // check whether the next byte is within the buffer.
1589 if (Start[Len] == '\\' && Start[Len + 1] == '\r' &&
1590 Start[Len + 2] == '\n') {
1591 Len += 3;
1592 } else if (Start[Len] == '\\' &&
1593 (Start[Len + 1] == '\r' || Start[Len + 1] == '\n')) {
1594 Len += 2;
1595 } else {
1596 Len += 1;
1597 }
1598 }
1599 break;
1600 default:
1601 return false;
1602 }
1603
1604 // The kind has to be an identifier so we can match it against those defined
1605 // in Keywords. The kind has to be set before the length because the setLength
1606 // function checks that the kind is not an annotation.
1607 Tok.Tok.setKind(tok::raw_identifier);
1608 Tok.Tok.setLength(Len);
1609 Tok.Tok.setLocation(Lex->getSourceLocation(Start, Len));
1610 Tok.Tok.setRawIdentifierData(Start);
1611 Lex->seek(Lex->getCurrentBufferOffset() + Len, /*IsAtStartofline=*/false);
1612 return true;
1613}
1614
1615void FormatTokenLexer::readRawToken(FormatToken &Tok) {
1616 // For Verilog, first see if there is a special token, and fall back to the
1617 // normal lexer if there isn't one.
1618 if (!Style.isVerilog() || !readRawTokenVerilogSpecific(Tok))
1619 Lex->LexFromRawLexer(Tok.Tok);
1620 Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
1621 Tok.Tok.getLength());
1622 // For formatting, treat unterminated string literals like normal string
1623 // literals.
1624 if (Tok.is(tok::unknown)) {
1625 if (Tok.TokenText.starts_with("\"")) {
1626 Tok.Tok.setKind(tok::string_literal);
1627 Tok.IsUnterminatedLiteral = true;
1628 } else if (Style.isJavaScript() && Tok.TokenText == "''") {
1629 Tok.Tok.setKind(tok::string_literal);
1630 }
1631 }
1632
1633 if ((Style.isJavaScript() || Style.isProto()) && Tok.is(tok::char_constant))
1634 Tok.Tok.setKind(tok::string_literal);
1635
1636 if (Tok.is(tok::comment) && isClangFormatOn(Tok.TokenText))
1637 FormattingDisabled = false;
1638
1639 Tok.Finalized = FormattingDisabled;
1640
1641 if (Tok.is(tok::comment) && isClangFormatOff(Tok.TokenText))
1642 FormattingDisabled = true;
1643}
1644
1645void FormatTokenLexer::resetLexer(unsigned Offset) {
1646 StringRef Buffer = SourceMgr.getBufferData(ID);
1647 Lex = std::make_unique<Lexer>(SourceMgr.getLocForStartOfFile(ID), LangOpts,
1648 Buffer.begin(), Buffer.begin() + Offset,
1649 Buffer.end());
1650 Lex->SetKeepWhitespaceMode(true);
1651 TrailingWhitespace = 0;
1652}
1653
1654} // namespace format
1655} // namespace clang
This file contains FormatTokenLexer, which tokenizes a source file into a token stream suitable for C...
This file contains the declaration of the FormatToken, a wrapper around Token with additional informa...
bool is(tok::TokenKind Kind) const
StringRef TokenText
The raw text of the token.
FormatToken()
Token Tok
The Token.
unsigned NewlinesBefore
The number of newlines immediately before the Token.
unsigned OriginalColumn
The original 0-based column of this token, including expanded tabs.
bool isNot(T Kind) const
FormatToken * Next
The next token in the unwrapped line.
Various functions to configurably format source code.
#define X(type, name)
Definition Value.h:97
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements an efficient mapping from strings to IdentifierInfo nodes.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
Token - This structure provides full information about a lexed token.
Definition Token.h:36
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition Token.h:142
FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, unsigned Column, const FormatStyle &Style, encoding::Encoding Encoding, llvm::SpecificBumpPtrAllocator< FormatToken > &Allocator, IdentifierTable &IdentTable)
ArrayRef< FormatToken * > lex()
uint32_t Literal
Literals are represented as positive integers.
Definition CNFFormula.h:35
unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn, unsigned TabWidth, Encoding Encoding)
Returns the number of columns required to display the Text, starting from the StartColumn on a termin...
Definition Encoding.h:60
static auto lexCSharpString(const char *Begin, const char *End, bool Verbatim, bool Interpolated)
static size_t countLeadingWhitespace(StringRef Text)
Count the length of leading whitespace in a token.
bool isClangFormatOff(StringRef Comment)
Definition Format.cpp:4904
bool isClangFormatOn(StringRef Comment)
Definition Format.cpp:4900
TokenType
Determines the semantic type of a syntactic token, e.g.
LangOptions getFormattingLangOpts(const FormatStyle &Style)
Definition Format.cpp:4498
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Definition TokenKinds.h:33
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
Definition CharInfo.h:99
std::vector< std::string > Macros
A list of macros of the form <definition>=<expansion> .
Definition Format.h:3951
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
std::vector< std::string > TypeNames
A vector of non-keyword identifiers that should be interpreted as type names.
Definition Format.h:5942
LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)
Returns true if this character is horizontal ASCII whitespace: ' ', '\t', '\f', '\v'.
Definition CharInfo.h:91
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
Definition CharInfo.h:108
@ Keyword
The name has been typo-corrected to a keyword.
Definition Sema.h:562
@ Type
The name was classified as a type.
Definition Sema.h:564
std::vector< std::string > MacrosSkippedByRemoveParentheses
A vector of function-like macros whose invocations should be skipped by RemoveParentheses.
Definition Format.h:3956
std::vector< std::string > TemplateNames
A vector of non-keyword identifiers that should be interpreted as template names.
Definition Format.h:5932
std::vector< std::string > VariableTemplates
A vector of non-keyword identifiers that should be interpreted as variable template names.
Definition Format.h:5993
#define true
Definition stdbool.h:25
A wrapper around a Token storing information about the whitespace characters preceding it.
bool isNot(T Kind) const
StringRef TokenText
The raw text of the token.
unsigned LastNewlineOffset
The offset just past the last ' ' in this token's leading whitespace (relative to WhiteSpaceStart).
unsigned NewlinesBefore
The number of newlines immediately before the Token.
unsigned HasUnescapedNewline
Whether there is at least one unescaped newline before the Token.
bool HasFormFeedBefore
Has "\n\f\n" or "\n\f\r\n" before TokenText.
unsigned IsFirst
Indicates that this is the first token of the file.