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