xref: /freebsd-src/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp (revision 6e516c87b6d779911edde7481d8aef165b837a03)
10b57cec5SDimitry Andric //===--- FormatTokenLexer.cpp - Lex FormatTokens -------------*- C++ ----*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements FormatTokenLexer, which tokenizes a source file
110b57cec5SDimitry Andric /// into a FormatToken stream suitable for ClangFormat.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "FormatTokenLexer.h"
160b57cec5SDimitry Andric #include "FormatToken.h"
170b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
180b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
190b57cec5SDimitry Andric #include "clang/Format/Format.h"
200b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace clang {
230b57cec5SDimitry Andric namespace format {
240b57cec5SDimitry Andric 
255ffd83dbSDimitry Andric FormatTokenLexer::FormatTokenLexer(
265ffd83dbSDimitry Andric     const SourceManager &SourceMgr, FileID ID, unsigned Column,
275ffd83dbSDimitry Andric     const FormatStyle &Style, encoding::Encoding Encoding,
285ffd83dbSDimitry Andric     llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
295ffd83dbSDimitry Andric     IdentifierTable &IdentTable)
300b57cec5SDimitry Andric     : FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}),
3181ad6265SDimitry Andric       Column(Column), TrailingWhitespace(0),
3281ad6265SDimitry Andric       LangOpts(getFormattingLangOpts(Style)), SourceMgr(SourceMgr), ID(ID),
335ffd83dbSDimitry Andric       Style(Style), IdentTable(IdentTable), Keywords(IdentTable),
345ffd83dbSDimitry Andric       Encoding(Encoding), Allocator(Allocator), FirstInLineIndex(0),
350b57cec5SDimitry Andric       FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
360b57cec5SDimitry Andric       MacroBlockEndRegex(Style.MacroBlockEnd) {
3781ad6265SDimitry Andric   Lex.reset(new Lexer(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts));
380b57cec5SDimitry Andric   Lex->SetKeepWhitespaceMode(true);
390b57cec5SDimitry Andric 
404824e7fdSDimitry Andric   for (const std::string &ForEachMacro : Style.ForEachMacros) {
414824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(ForEachMacro);
424824e7fdSDimitry Andric     Macros.insert({Identifier, TT_ForEachMacro});
434824e7fdSDimitry Andric   }
444824e7fdSDimitry Andric   for (const std::string &IfMacro : Style.IfMacros) {
454824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(IfMacro);
464824e7fdSDimitry Andric     Macros.insert({Identifier, TT_IfMacro});
474824e7fdSDimitry Andric   }
484824e7fdSDimitry Andric   for (const std::string &AttributeMacro : Style.AttributeMacros) {
494824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(AttributeMacro);
504824e7fdSDimitry Andric     Macros.insert({Identifier, TT_AttributeMacro});
514824e7fdSDimitry Andric   }
524824e7fdSDimitry Andric   for (const std::string &StatementMacro : Style.StatementMacros) {
534824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(StatementMacro);
544824e7fdSDimitry Andric     Macros.insert({Identifier, TT_StatementMacro});
554824e7fdSDimitry Andric   }
564824e7fdSDimitry Andric   for (const std::string &TypenameMacro : Style.TypenameMacros) {
574824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(TypenameMacro);
584824e7fdSDimitry Andric     Macros.insert({Identifier, TT_TypenameMacro});
594824e7fdSDimitry Andric   }
604824e7fdSDimitry Andric   for (const std::string &NamespaceMacro : Style.NamespaceMacros) {
614824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(NamespaceMacro);
624824e7fdSDimitry Andric     Macros.insert({Identifier, TT_NamespaceMacro});
634824e7fdSDimitry Andric   }
645ffd83dbSDimitry Andric   for (const std::string &WhitespaceSensitiveMacro :
655ffd83dbSDimitry Andric        Style.WhitespaceSensitiveMacros) {
664824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(WhitespaceSensitiveMacro);
674824e7fdSDimitry Andric     Macros.insert({Identifier, TT_UntouchableMacroFunc});
685ffd83dbSDimitry Andric   }
69e8d8bef9SDimitry Andric   for (const std::string &StatementAttributeLikeMacro :
704824e7fdSDimitry Andric        Style.StatementAttributeLikeMacros) {
714824e7fdSDimitry Andric     auto Identifier = &IdentTable.get(StatementAttributeLikeMacro);
724824e7fdSDimitry Andric     Macros.insert({Identifier, TT_StatementAttributeLikeMacro});
734824e7fdSDimitry Andric   }
7406c3fb27SDimitry Andric 
7506c3fb27SDimitry Andric   for (const auto &TypeName : Style.TypeNames)
7606c3fb27SDimitry Andric     TypeNames.insert(&IdentTable.get(TypeName));
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric ArrayRef<FormatToken *> FormatTokenLexer::lex() {
800b57cec5SDimitry Andric   assert(Tokens.empty());
810b57cec5SDimitry Andric   assert(FirstInLineIndex == 0);
820b57cec5SDimitry Andric   do {
830b57cec5SDimitry Andric     Tokens.push_back(getNextToken());
840eae32dcSDimitry Andric     if (Style.isJavaScript()) {
850b57cec5SDimitry Andric       tryParseJSRegexLiteral();
860b57cec5SDimitry Andric       handleTemplateStrings();
870b57cec5SDimitry Andric     }
880b57cec5SDimitry Andric     if (Style.Language == FormatStyle::LK_TextProto)
890b57cec5SDimitry Andric       tryParsePythonComment();
900b57cec5SDimitry Andric     tryMergePreviousTokens();
9181ad6265SDimitry Andric     if (Style.isCSharp()) {
925ffd83dbSDimitry Andric       // This needs to come after tokens have been merged so that C#
935ffd83dbSDimitry Andric       // string literals are correctly identified.
945ffd83dbSDimitry Andric       handleCSharpVerbatimAndInterpolatedStrings();
9581ad6265SDimitry Andric     }
967a6dacacSDimitry Andric     if (Style.isTableGen()) {
977a6dacacSDimitry Andric       handleTableGenMultilineString();
987a6dacacSDimitry Andric       handleTableGenNumericLikeIdentifier();
997a6dacacSDimitry Andric     }
1000b57cec5SDimitry Andric     if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline)
1010b57cec5SDimitry Andric       FirstInLineIndex = Tokens.size() - 1;
10281ad6265SDimitry Andric   } while (Tokens.back()->isNot(tok::eof));
103*6e516c87SDimitry Andric   if (Style.InsertNewlineAtEOF) {
104*6e516c87SDimitry Andric     auto &TokEOF = *Tokens.back();
105*6e516c87SDimitry Andric     if (TokEOF.NewlinesBefore == 0) {
106*6e516c87SDimitry Andric       TokEOF.NewlinesBefore = 1;
107*6e516c87SDimitry Andric       TokEOF.OriginalColumn = 0;
108*6e516c87SDimitry Andric     }
109*6e516c87SDimitry Andric   }
1100b57cec5SDimitry Andric   return Tokens;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric void FormatTokenLexer::tryMergePreviousTokens() {
1140b57cec5SDimitry Andric   if (tryMerge_TMacro())
1150b57cec5SDimitry Andric     return;
1160b57cec5SDimitry Andric   if (tryMergeConflictMarkers())
1170b57cec5SDimitry Andric     return;
1180b57cec5SDimitry Andric   if (tryMergeLessLess())
1190b57cec5SDimitry Andric     return;
12006c3fb27SDimitry Andric   if (tryMergeGreaterGreater())
12106c3fb27SDimitry Andric     return;
1225ffd83dbSDimitry Andric   if (tryMergeForEach())
1235ffd83dbSDimitry Andric     return;
1245ffd83dbSDimitry Andric   if (Style.isCpp() && tryTransformTryUsageForC())
1255ffd83dbSDimitry Andric     return;
1260b57cec5SDimitry Andric 
1270eae32dcSDimitry Andric   if (Style.isJavaScript() || Style.isCSharp()) {
128fe6060f1SDimitry Andric     static const tok::TokenKind NullishCoalescingOperator[] = {tok::question,
129fe6060f1SDimitry Andric                                                                tok::question};
130fe6060f1SDimitry Andric     static const tok::TokenKind NullPropagatingOperator[] = {tok::question,
131fe6060f1SDimitry Andric                                                              tok::period};
132fe6060f1SDimitry Andric     static const tok::TokenKind FatArrow[] = {tok::equal, tok::greater};
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric     if (tryMergeTokens(FatArrow, TT_FatArrow))
135fe6060f1SDimitry Andric       return;
136fe6060f1SDimitry Andric     if (tryMergeTokens(NullishCoalescingOperator, TT_NullCoalescingOperator)) {
137fe6060f1SDimitry Andric       // Treat like the "||" operator (as opposed to the ternary ?).
138fe6060f1SDimitry Andric       Tokens.back()->Tok.setKind(tok::pipepipe);
139fe6060f1SDimitry Andric       return;
140fe6060f1SDimitry Andric     }
141fe6060f1SDimitry Andric     if (tryMergeTokens(NullPropagatingOperator, TT_NullPropagatingOperator)) {
142fe6060f1SDimitry Andric       // Treat like a regular "." access.
143fe6060f1SDimitry Andric       Tokens.back()->Tok.setKind(tok::period);
144fe6060f1SDimitry Andric       return;
145fe6060f1SDimitry Andric     }
14681ad6265SDimitry Andric     if (tryMergeNullishCoalescingEqual())
147fe6060f1SDimitry Andric       return;
148fe6060f1SDimitry Andric   }
149fe6060f1SDimitry Andric 
1500b57cec5SDimitry Andric   if (Style.isCSharp()) {
151fe6060f1SDimitry Andric     static const tok::TokenKind CSharpNullConditionalLSquare[] = {
152fe6060f1SDimitry Andric         tok::question, tok::l_square};
153fe6060f1SDimitry Andric 
1540b57cec5SDimitry Andric     if (tryMergeCSharpKeywordVariables())
1550b57cec5SDimitry Andric       return;
1565ffd83dbSDimitry Andric     if (tryMergeCSharpStringLiteral())
1570b57cec5SDimitry Andric       return;
158a7dea167SDimitry Andric     if (tryTransformCSharpForEach())
159a7dea167SDimitry Andric       return;
160fe6060f1SDimitry Andric     if (tryMergeTokens(CSharpNullConditionalLSquare,
161fe6060f1SDimitry Andric                        TT_CSharpNullConditionalLSquare)) {
162fe6060f1SDimitry Andric       // Treat like a regular "[" operator.
163fe6060f1SDimitry Andric       Tokens.back()->Tok.setKind(tok::l_square);
1640b57cec5SDimitry Andric       return;
1650b57cec5SDimitry Andric     }
166fe6060f1SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   if (tryMergeNSStringLiteral())
1690b57cec5SDimitry Andric     return;
1700b57cec5SDimitry Andric 
1710eae32dcSDimitry Andric   if (Style.isJavaScript()) {
1720b57cec5SDimitry Andric     static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
1730b57cec5SDimitry Andric     static const tok::TokenKind JSNotIdentity[] = {tok::exclaimequal,
1740b57cec5SDimitry Andric                                                    tok::equal};
1750b57cec5SDimitry Andric     static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
1760b57cec5SDimitry Andric                                                   tok::greaterequal};
1770b57cec5SDimitry Andric     static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star};
1780b57cec5SDimitry Andric     static const tok::TokenKind JSExponentiationEqual[] = {tok::star,
1790b57cec5SDimitry Andric                                                            tok::starequal};
180e8d8bef9SDimitry Andric     static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, tok::equal};
181e8d8bef9SDimitry Andric     static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     // FIXME: Investigate what token type gives the correct operator priority.
1840b57cec5SDimitry Andric     if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
1850b57cec5SDimitry Andric       return;
1860b57cec5SDimitry Andric     if (tryMergeTokens(JSNotIdentity, TT_BinaryOperator))
1870b57cec5SDimitry Andric       return;
1880b57cec5SDimitry Andric     if (tryMergeTokens(JSShiftEqual, TT_BinaryOperator))
1890b57cec5SDimitry Andric       return;
1900b57cec5SDimitry Andric     if (tryMergeTokens(JSExponentiation, TT_JsExponentiation))
1910b57cec5SDimitry Andric       return;
1920b57cec5SDimitry Andric     if (tryMergeTokens(JSExponentiationEqual, TT_JsExponentiationEqual)) {
1930b57cec5SDimitry Andric       Tokens.back()->Tok.setKind(tok::starequal);
1940b57cec5SDimitry Andric       return;
1950b57cec5SDimitry Andric     }
196e8d8bef9SDimitry Andric     if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) ||
197fe6060f1SDimitry Andric         tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEqual)) {
198e8d8bef9SDimitry Andric       // Treat like the "=" assignment operator.
199e8d8bef9SDimitry Andric       Tokens.back()->Tok.setKind(tok::equal);
200e8d8bef9SDimitry Andric       return;
201e8d8bef9SDimitry Andric     }
2020b57cec5SDimitry Andric     if (tryMergeJSPrivateIdentifier())
2030b57cec5SDimitry Andric       return;
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   if (Style.Language == FormatStyle::LK_Java) {
2070b57cec5SDimitry Andric     static const tok::TokenKind JavaRightLogicalShiftAssign[] = {
2080b57cec5SDimitry Andric         tok::greater, tok::greater, tok::greaterequal};
2090b57cec5SDimitry Andric     if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator))
2100b57cec5SDimitry Andric       return;
2110b57cec5SDimitry Andric   }
212bdd1243dSDimitry Andric 
213bdd1243dSDimitry Andric   if (Style.isVerilog()) {
214bdd1243dSDimitry Andric     // Merge the number following a base like `'h?a0`.
215bdd1243dSDimitry Andric     if (Tokens.size() >= 3 && Tokens.end()[-3]->is(TT_VerilogNumberBase) &&
216bdd1243dSDimitry Andric         Tokens.end()[-2]->is(tok::numeric_constant) &&
217bdd1243dSDimitry Andric         Tokens.back()->isOneOf(tok::numeric_constant, tok::identifier,
218bdd1243dSDimitry Andric                                tok::question) &&
219bdd1243dSDimitry Andric         tryMergeTokens(2, TT_Unknown)) {
220bdd1243dSDimitry Andric       return;
221bdd1243dSDimitry Andric     }
222bdd1243dSDimitry Andric     // Part select.
223bdd1243dSDimitry Andric     if (tryMergeTokensAny({{tok::minus, tok::colon}, {tok::plus, tok::colon}},
224bdd1243dSDimitry Andric                           TT_BitFieldColon)) {
225bdd1243dSDimitry Andric       return;
226bdd1243dSDimitry Andric     }
227bdd1243dSDimitry Andric     // Xnor. The combined token is treated as a caret which can also be either a
228bdd1243dSDimitry Andric     // unary or binary operator. The actual type is determined in
229bdd1243dSDimitry Andric     // TokenAnnotator. We also check the token length so we know it is not
230bdd1243dSDimitry Andric     // already a merged token.
231bdd1243dSDimitry Andric     if (Tokens.back()->TokenText.size() == 1 &&
232bdd1243dSDimitry Andric         tryMergeTokensAny({{tok::caret, tok::tilde}, {tok::tilde, tok::caret}},
233bdd1243dSDimitry Andric                           TT_BinaryOperator)) {
234bdd1243dSDimitry Andric       Tokens.back()->Tok.setKind(tok::caret);
235bdd1243dSDimitry Andric       return;
236bdd1243dSDimitry Andric     }
237bdd1243dSDimitry Andric     // Signed shift and distribution weight.
238bdd1243dSDimitry Andric     if (tryMergeTokens({tok::less, tok::less}, TT_BinaryOperator)) {
239bdd1243dSDimitry Andric       Tokens.back()->Tok.setKind(tok::lessless);
240bdd1243dSDimitry Andric       return;
241bdd1243dSDimitry Andric     }
242bdd1243dSDimitry Andric     if (tryMergeTokens({tok::greater, tok::greater}, TT_BinaryOperator)) {
243bdd1243dSDimitry Andric       Tokens.back()->Tok.setKind(tok::greatergreater);
244bdd1243dSDimitry Andric       return;
245bdd1243dSDimitry Andric     }
246bdd1243dSDimitry Andric     if (tryMergeTokensAny({{tok::lessless, tok::equal},
247bdd1243dSDimitry Andric                            {tok::lessless, tok::lessequal},
248bdd1243dSDimitry Andric                            {tok::greatergreater, tok::equal},
249bdd1243dSDimitry Andric                            {tok::greatergreater, tok::greaterequal},
250bdd1243dSDimitry Andric                            {tok::colon, tok::equal},
251bdd1243dSDimitry Andric                            {tok::colon, tok::slash}},
252bdd1243dSDimitry Andric                           TT_BinaryOperator)) {
253bdd1243dSDimitry Andric       Tokens.back()->ForcedPrecedence = prec::Assignment;
254bdd1243dSDimitry Andric       return;
255bdd1243dSDimitry Andric     }
256bdd1243dSDimitry Andric     // Exponentiation, signed shift, case equality, and wildcard equality.
257bdd1243dSDimitry Andric     if (tryMergeTokensAny({{tok::star, tok::star},
258bdd1243dSDimitry Andric                            {tok::lessless, tok::less},
259bdd1243dSDimitry Andric                            {tok::greatergreater, tok::greater},
260bdd1243dSDimitry Andric                            {tok::exclaimequal, tok::equal},
261bdd1243dSDimitry Andric                            {tok::exclaimequal, tok::question},
262bdd1243dSDimitry Andric                            {tok::equalequal, tok::equal},
263bdd1243dSDimitry Andric                            {tok::equalequal, tok::question}},
264bdd1243dSDimitry Andric                           TT_BinaryOperator)) {
265bdd1243dSDimitry Andric       return;
266bdd1243dSDimitry Andric     }
2675f757f3fSDimitry Andric     // Module paths in specify blocks and the implication and boolean equality
2685f757f3fSDimitry Andric     // operators.
269bdd1243dSDimitry Andric     if (tryMergeTokensAny({{tok::plusequal, tok::greater},
270bdd1243dSDimitry Andric                            {tok::plus, tok::star, tok::greater},
271bdd1243dSDimitry Andric                            {tok::minusequal, tok::greater},
272bdd1243dSDimitry Andric                            {tok::minus, tok::star, tok::greater},
273bdd1243dSDimitry Andric                            {tok::less, tok::arrow},
274bdd1243dSDimitry Andric                            {tok::equal, tok::greater},
275bdd1243dSDimitry Andric                            {tok::star, tok::greater},
276bdd1243dSDimitry Andric                            {tok::pipeequal, tok::greater},
277bdd1243dSDimitry Andric                            {tok::pipe, tok::arrow},
278bdd1243dSDimitry Andric                            {tok::hash, tok::minus, tok::hash},
279bdd1243dSDimitry Andric                            {tok::hash, tok::equal, tok::hash}},
2805f757f3fSDimitry Andric                           TT_BinaryOperator) ||
2815f757f3fSDimitry Andric         Tokens.back()->is(tok::arrow)) {
282bdd1243dSDimitry Andric       Tokens.back()->ForcedPrecedence = prec::Comma;
283bdd1243dSDimitry Andric       return;
284bdd1243dSDimitry Andric     }
285bdd1243dSDimitry Andric   }
2860fca6ea1SDimitry Andric   if (Style.isTableGen()) {
2877a6dacacSDimitry Andric     // TableGen's Multi line string starts with [{
2880fca6ea1SDimitry Andric     if (tryMergeTokens({tok::l_square, tok::l_brace},
2897a6dacacSDimitry Andric                        TT_TableGenMultiLineString)) {
2907a6dacacSDimitry Andric       // Set again with finalizing. This must never be annotated as other types.
2917a6dacacSDimitry Andric       Tokens.back()->setFinalizedType(TT_TableGenMultiLineString);
2927a6dacacSDimitry Andric       Tokens.back()->Tok.setKind(tok::string_literal);
2937a6dacacSDimitry Andric       return;
2947a6dacacSDimitry Andric     }
2950fca6ea1SDimitry Andric     // TableGen's bang operator is the form !<name>.
2960fca6ea1SDimitry Andric     // !cond is a special case with specific syntax.
2970fca6ea1SDimitry Andric     if (tryMergeTokens({tok::exclaim, tok::identifier},
2980fca6ea1SDimitry Andric                        TT_TableGenBangOperator)) {
2990fca6ea1SDimitry Andric       Tokens.back()->Tok.setKind(tok::identifier);
3000fca6ea1SDimitry Andric       Tokens.back()->Tok.setIdentifierInfo(nullptr);
3010fca6ea1SDimitry Andric       if (Tokens.back()->TokenText == "!cond")
3020fca6ea1SDimitry Andric         Tokens.back()->setFinalizedType(TT_TableGenCondOperator);
3030fca6ea1SDimitry Andric       else
3040fca6ea1SDimitry Andric         Tokens.back()->setFinalizedType(TT_TableGenBangOperator);
3050fca6ea1SDimitry Andric       return;
3060fca6ea1SDimitry Andric     }
3070fca6ea1SDimitry Andric     if (tryMergeTokens({tok::exclaim, tok::kw_if}, TT_TableGenBangOperator)) {
3080fca6ea1SDimitry Andric       // Here, "! if" becomes "!if".  That is, ! captures if even when the space
3090fca6ea1SDimitry Andric       // exists. That is only one possibility in TableGen's syntax.
3100fca6ea1SDimitry Andric       Tokens.back()->Tok.setKind(tok::identifier);
3110fca6ea1SDimitry Andric       Tokens.back()->Tok.setIdentifierInfo(nullptr);
3120fca6ea1SDimitry Andric       Tokens.back()->setFinalizedType(TT_TableGenBangOperator);
3130fca6ea1SDimitry Andric       return;
3140fca6ea1SDimitry Andric     }
3150fca6ea1SDimitry Andric     // +, - with numbers are literals. Not unary operators.
3160fca6ea1SDimitry Andric     if (tryMergeTokens({tok::plus, tok::numeric_constant}, TT_Unknown)) {
3170fca6ea1SDimitry Andric       Tokens.back()->Tok.setKind(tok::numeric_constant);
3180fca6ea1SDimitry Andric       return;
3190fca6ea1SDimitry Andric     }
3200fca6ea1SDimitry Andric     if (tryMergeTokens({tok::minus, tok::numeric_constant}, TT_Unknown)) {
3210fca6ea1SDimitry Andric       Tokens.back()->Tok.setKind(tok::numeric_constant);
3220fca6ea1SDimitry Andric       return;
3230fca6ea1SDimitry Andric     }
3240fca6ea1SDimitry Andric   }
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric bool FormatTokenLexer::tryMergeNSStringLiteral() {
3280b57cec5SDimitry Andric   if (Tokens.size() < 2)
3290b57cec5SDimitry Andric     return false;
3300b57cec5SDimitry Andric   auto &At = *(Tokens.end() - 2);
3310b57cec5SDimitry Andric   auto &String = *(Tokens.end() - 1);
3325f757f3fSDimitry Andric   if (At->isNot(tok::at) || String->isNot(tok::string_literal))
3330b57cec5SDimitry Andric     return false;
3340b57cec5SDimitry Andric   At->Tok.setKind(tok::string_literal);
3350b57cec5SDimitry Andric   At->TokenText = StringRef(At->TokenText.begin(),
3360b57cec5SDimitry Andric                             String->TokenText.end() - At->TokenText.begin());
3370b57cec5SDimitry Andric   At->ColumnWidth += String->ColumnWidth;
3385ffd83dbSDimitry Andric   At->setType(TT_ObjCStringLiteral);
3390b57cec5SDimitry Andric   Tokens.erase(Tokens.end() - 1);
3400b57cec5SDimitry Andric   return true;
3410b57cec5SDimitry Andric }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric bool FormatTokenLexer::tryMergeJSPrivateIdentifier() {
3440b57cec5SDimitry Andric   // Merges #idenfier into a single identifier with the text #identifier
3450b57cec5SDimitry Andric   // but the token tok::identifier.
3460b57cec5SDimitry Andric   if (Tokens.size() < 2)
3470b57cec5SDimitry Andric     return false;
3480b57cec5SDimitry Andric   auto &Hash = *(Tokens.end() - 2);
3490b57cec5SDimitry Andric   auto &Identifier = *(Tokens.end() - 1);
3505f757f3fSDimitry Andric   if (Hash->isNot(tok::hash) || Identifier->isNot(tok::identifier))
3510b57cec5SDimitry Andric     return false;
3520b57cec5SDimitry Andric   Hash->Tok.setKind(tok::identifier);
3530b57cec5SDimitry Andric   Hash->TokenText =
3540b57cec5SDimitry Andric       StringRef(Hash->TokenText.begin(),
3550b57cec5SDimitry Andric                 Identifier->TokenText.end() - Hash->TokenText.begin());
3560b57cec5SDimitry Andric   Hash->ColumnWidth += Identifier->ColumnWidth;
3575ffd83dbSDimitry Andric   Hash->setType(TT_JsPrivateIdentifier);
3580b57cec5SDimitry Andric   Tokens.erase(Tokens.end() - 1);
3590b57cec5SDimitry Andric   return true;
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric // Search for verbatim or interpolated string literals @"ABC" or
3630b57cec5SDimitry Andric // $"aaaaa{abc}aaaaa" i and mark the token as TT_CSharpStringLiteral, and to
3640b57cec5SDimitry Andric // prevent splitting of @, $ and ".
3655ffd83dbSDimitry Andric // Merging of multiline verbatim strings with embedded '"' is handled in
3665ffd83dbSDimitry Andric // handleCSharpVerbatimAndInterpolatedStrings with lower-level lexing.
3675ffd83dbSDimitry Andric bool FormatTokenLexer::tryMergeCSharpStringLiteral() {
3680b57cec5SDimitry Andric   if (Tokens.size() < 2)
3690b57cec5SDimitry Andric     return false;
3700b57cec5SDimitry Andric 
3715ffd83dbSDimitry Andric   // Look for @"aaaaaa" or $"aaaaaa".
372bdd1243dSDimitry Andric   const auto String = *(Tokens.end() - 1);
373bdd1243dSDimitry Andric   if (String->isNot(tok::string_literal))
3740b57cec5SDimitry Andric     return false;
3750b57cec5SDimitry Andric 
376bdd1243dSDimitry Andric   auto Prefix = *(Tokens.end() - 2);
377bdd1243dSDimitry Andric   if (Prefix->isNot(tok::at) && Prefix->TokenText != "$")
3785ffd83dbSDimitry Andric     return false;
3795ffd83dbSDimitry Andric 
380bdd1243dSDimitry Andric   if (Tokens.size() > 2) {
381bdd1243dSDimitry Andric     const auto Tok = *(Tokens.end() - 3);
382bdd1243dSDimitry Andric     if ((Tok->TokenText == "$" && Prefix->is(tok::at)) ||
383bdd1243dSDimitry Andric         (Tok->is(tok::at) && Prefix->TokenText == "$")) {
384bdd1243dSDimitry Andric       // This looks like $@"aaa" or @$"aaa" so we need to combine all 3 tokens.
385bdd1243dSDimitry Andric       Tok->ColumnWidth += Prefix->ColumnWidth;
3860b57cec5SDimitry Andric       Tokens.erase(Tokens.end() - 2);
387bdd1243dSDimitry Andric       Prefix = Tok;
3880b57cec5SDimitry Andric     }
3890b57cec5SDimitry Andric   }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   // Convert back into just a string_literal.
392bdd1243dSDimitry Andric   Prefix->Tok.setKind(tok::string_literal);
393bdd1243dSDimitry Andric   Prefix->TokenText =
394bdd1243dSDimitry Andric       StringRef(Prefix->TokenText.begin(),
395bdd1243dSDimitry Andric                 String->TokenText.end() - Prefix->TokenText.begin());
396bdd1243dSDimitry Andric   Prefix->ColumnWidth += String->ColumnWidth;
397bdd1243dSDimitry Andric   Prefix->setType(TT_CSharpStringLiteral);
3980b57cec5SDimitry Andric   Tokens.erase(Tokens.end() - 1);
3990b57cec5SDimitry Andric   return true;
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric 
4025ffd83dbSDimitry Andric // Valid C# attribute targets:
4035ffd83dbSDimitry Andric // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets
4045ffd83dbSDimitry Andric const llvm::StringSet<> FormatTokenLexer::CSharpAttributeTargets = {
4055ffd83dbSDimitry Andric     "assembly", "module",   "field",  "event", "method",
4065ffd83dbSDimitry Andric     "param",    "property", "return", "type",
4075ffd83dbSDimitry Andric };
4085ffd83dbSDimitry Andric 
409fe6060f1SDimitry Andric bool FormatTokenLexer::tryMergeNullishCoalescingEqual() {
4100b57cec5SDimitry Andric   if (Tokens.size() < 2)
4110b57cec5SDimitry Andric     return false;
412fe6060f1SDimitry Andric   auto &NullishCoalescing = *(Tokens.end() - 2);
413fe6060f1SDimitry Andric   auto &Equal = *(Tokens.end() - 1);
4140fca6ea1SDimitry Andric   if (NullishCoalescing->isNot(TT_NullCoalescingOperator) ||
4155f757f3fSDimitry Andric       Equal->isNot(tok::equal)) {
4160b57cec5SDimitry Andric     return false;
41781ad6265SDimitry Andric   }
418fe6060f1SDimitry Andric   NullishCoalescing->Tok.setKind(tok::equal); // no '??=' in clang tokens.
419fe6060f1SDimitry Andric   NullishCoalescing->TokenText =
420fe6060f1SDimitry Andric       StringRef(NullishCoalescing->TokenText.begin(),
421fe6060f1SDimitry Andric                 Equal->TokenText.end() - NullishCoalescing->TokenText.begin());
422fe6060f1SDimitry Andric   NullishCoalescing->ColumnWidth += Equal->ColumnWidth;
423fe6060f1SDimitry Andric   NullishCoalescing->setType(TT_NullCoalescingEqual);
4240b57cec5SDimitry Andric   Tokens.erase(Tokens.end() - 1);
4250b57cec5SDimitry Andric   return true;
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric bool FormatTokenLexer::tryMergeCSharpKeywordVariables() {
4290b57cec5SDimitry Andric   if (Tokens.size() < 2)
4300b57cec5SDimitry Andric     return false;
431bdd1243dSDimitry Andric   const auto At = *(Tokens.end() - 2);
432bdd1243dSDimitry Andric   if (At->isNot(tok::at))
433bdd1243dSDimitry Andric     return false;
434bdd1243dSDimitry Andric   const auto Keyword = *(Tokens.end() - 1);
435bdd1243dSDimitry Andric   if (Keyword->TokenText == "$")
4360b57cec5SDimitry Andric     return false;
4370b57cec5SDimitry Andric   if (!Keywords.isCSharpKeyword(*Keyword))
4380b57cec5SDimitry Andric     return false;
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   At->Tok.setKind(tok::identifier);
4410b57cec5SDimitry Andric   At->TokenText = StringRef(At->TokenText.begin(),
4420b57cec5SDimitry Andric                             Keyword->TokenText.end() - At->TokenText.begin());
4430b57cec5SDimitry Andric   At->ColumnWidth += Keyword->ColumnWidth;
4445ffd83dbSDimitry Andric   At->setType(Keyword->getType());
4450b57cec5SDimitry Andric   Tokens.erase(Tokens.end() - 1);
4460b57cec5SDimitry Andric   return true;
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
449a7dea167SDimitry Andric // In C# transform identifier foreach into kw_foreach
450a7dea167SDimitry Andric bool FormatTokenLexer::tryTransformCSharpForEach() {
451a7dea167SDimitry Andric   if (Tokens.size() < 1)
452a7dea167SDimitry Andric     return false;
453a7dea167SDimitry Andric   auto &Identifier = *(Tokens.end() - 1);
4545f757f3fSDimitry Andric   if (Identifier->isNot(tok::identifier))
455a7dea167SDimitry Andric     return false;
456a7dea167SDimitry Andric   if (Identifier->TokenText != "foreach")
457a7dea167SDimitry Andric     return false;
458a7dea167SDimitry Andric 
4595ffd83dbSDimitry Andric   Identifier->setType(TT_ForEachMacro);
460a7dea167SDimitry Andric   Identifier->Tok.setKind(tok::kw_for);
461a7dea167SDimitry Andric   return true;
462a7dea167SDimitry Andric }
463a7dea167SDimitry Andric 
4645ffd83dbSDimitry Andric bool FormatTokenLexer::tryMergeForEach() {
4655ffd83dbSDimitry Andric   if (Tokens.size() < 2)
4665ffd83dbSDimitry Andric     return false;
4675ffd83dbSDimitry Andric   auto &For = *(Tokens.end() - 2);
4685ffd83dbSDimitry Andric   auto &Each = *(Tokens.end() - 1);
4695f757f3fSDimitry Andric   if (For->isNot(tok::kw_for))
4705ffd83dbSDimitry Andric     return false;
4715f757f3fSDimitry Andric   if (Each->isNot(tok::identifier))
4725ffd83dbSDimitry Andric     return false;
4735ffd83dbSDimitry Andric   if (Each->TokenText != "each")
4745ffd83dbSDimitry Andric     return false;
4755ffd83dbSDimitry Andric 
4765ffd83dbSDimitry Andric   For->setType(TT_ForEachMacro);
4775ffd83dbSDimitry Andric   For->Tok.setKind(tok::kw_for);
4785ffd83dbSDimitry Andric 
4795ffd83dbSDimitry Andric   For->TokenText = StringRef(For->TokenText.begin(),
4805ffd83dbSDimitry Andric                              Each->TokenText.end() - For->TokenText.begin());
4815ffd83dbSDimitry Andric   For->ColumnWidth += Each->ColumnWidth;
4825ffd83dbSDimitry Andric   Tokens.erase(Tokens.end() - 1);
4835ffd83dbSDimitry Andric   return true;
4845ffd83dbSDimitry Andric }
4855ffd83dbSDimitry Andric 
4865ffd83dbSDimitry Andric bool FormatTokenLexer::tryTransformTryUsageForC() {
4875ffd83dbSDimitry Andric   if (Tokens.size() < 2)
4885ffd83dbSDimitry Andric     return false;
4895ffd83dbSDimitry Andric   auto &Try = *(Tokens.end() - 2);
4905f757f3fSDimitry Andric   if (Try->isNot(tok::kw_try))
4915ffd83dbSDimitry Andric     return false;
4925ffd83dbSDimitry Andric   auto &Next = *(Tokens.end() - 1);
493e8d8bef9SDimitry Andric   if (Next->isOneOf(tok::l_brace, tok::colon, tok::hash, tok::comment))
4945ffd83dbSDimitry Andric     return false;
4955ffd83dbSDimitry Andric 
4965ffd83dbSDimitry Andric   if (Tokens.size() > 2) {
4975ffd83dbSDimitry Andric     auto &At = *(Tokens.end() - 3);
4985ffd83dbSDimitry Andric     if (At->is(tok::at))
4995ffd83dbSDimitry Andric       return false;
5005ffd83dbSDimitry Andric   }
5015ffd83dbSDimitry Andric 
5025ffd83dbSDimitry Andric   Try->Tok.setKind(tok::identifier);
5035ffd83dbSDimitry Andric   return true;
5045ffd83dbSDimitry Andric }
5055ffd83dbSDimitry Andric 
5060b57cec5SDimitry Andric bool FormatTokenLexer::tryMergeLessLess() {
5070b57cec5SDimitry Andric   // Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
5080b57cec5SDimitry Andric   if (Tokens.size() < 3)
5090b57cec5SDimitry Andric     return false;
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric   auto First = Tokens.end() - 3;
51204eeddc0SDimitry Andric   if (First[0]->isNot(tok::less) || First[1]->isNot(tok::less))
5130b57cec5SDimitry Andric     return false;
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric   // Only merge if there currently is no whitespace between the two "<".
51604eeddc0SDimitry Andric   if (First[1]->hasWhitespaceBefore())
51704eeddc0SDimitry Andric     return false;
51804eeddc0SDimitry Andric 
51904eeddc0SDimitry Andric   auto X = Tokens.size() > 3 ? First[-1] : nullptr;
52006c3fb27SDimitry Andric   if (X && X->is(tok::less))
52104eeddc0SDimitry Andric     return false;
52204eeddc0SDimitry Andric 
52306c3fb27SDimitry Andric   auto Y = First[2];
52406c3fb27SDimitry Andric   if ((!X || X->isNot(tok::kw_operator)) && Y->is(tok::less))
5250b57cec5SDimitry Andric     return false;
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric   First[0]->Tok.setKind(tok::lessless);
5280b57cec5SDimitry Andric   First[0]->TokenText = "<<";
5290b57cec5SDimitry Andric   First[0]->ColumnWidth += 1;
5300b57cec5SDimitry Andric   Tokens.erase(Tokens.end() - 2);
5310b57cec5SDimitry Andric   return true;
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric 
53406c3fb27SDimitry Andric bool FormatTokenLexer::tryMergeGreaterGreater() {
53506c3fb27SDimitry Andric   // Merge kw_operator,greater,greater into kw_operator,greatergreater.
53606c3fb27SDimitry Andric   if (Tokens.size() < 2)
53706c3fb27SDimitry Andric     return false;
53806c3fb27SDimitry Andric 
53906c3fb27SDimitry Andric   auto First = Tokens.end() - 2;
54006c3fb27SDimitry Andric   if (First[0]->isNot(tok::greater) || First[1]->isNot(tok::greater))
54106c3fb27SDimitry Andric     return false;
54206c3fb27SDimitry Andric 
54306c3fb27SDimitry Andric   // Only merge if there currently is no whitespace between the first two ">".
54406c3fb27SDimitry Andric   if (First[1]->hasWhitespaceBefore())
54506c3fb27SDimitry Andric     return false;
54606c3fb27SDimitry Andric 
54706c3fb27SDimitry Andric   auto Tok = Tokens.size() > 2 ? First[-1] : nullptr;
54806c3fb27SDimitry Andric   if (Tok && Tok->isNot(tok::kw_operator))
54906c3fb27SDimitry Andric     return false;
55006c3fb27SDimitry Andric 
55106c3fb27SDimitry Andric   First[0]->Tok.setKind(tok::greatergreater);
55206c3fb27SDimitry Andric   First[0]->TokenText = ">>";
55306c3fb27SDimitry Andric   First[0]->ColumnWidth += 1;
55406c3fb27SDimitry Andric   Tokens.erase(Tokens.end() - 1);
55506c3fb27SDimitry Andric   return true;
55606c3fb27SDimitry Andric }
55706c3fb27SDimitry Andric 
5580b57cec5SDimitry Andric bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
5590b57cec5SDimitry Andric                                       TokenType NewType) {
5600b57cec5SDimitry Andric   if (Tokens.size() < Kinds.size())
5610b57cec5SDimitry Andric     return false;
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric   SmallVectorImpl<FormatToken *>::const_iterator First =
5640b57cec5SDimitry Andric       Tokens.end() - Kinds.size();
565bdd1243dSDimitry Andric   for (unsigned i = 0; i < Kinds.size(); ++i)
5665f757f3fSDimitry Andric     if (First[i]->isNot(Kinds[i]))
5670b57cec5SDimitry Andric       return false;
568bdd1243dSDimitry Andric 
569bdd1243dSDimitry Andric   return tryMergeTokens(Kinds.size(), NewType);
570bdd1243dSDimitry Andric }
571bdd1243dSDimitry Andric 
572bdd1243dSDimitry Andric bool FormatTokenLexer::tryMergeTokens(size_t Count, TokenType NewType) {
573bdd1243dSDimitry Andric   if (Tokens.size() < Count)
574bdd1243dSDimitry Andric     return false;
575bdd1243dSDimitry Andric 
576bdd1243dSDimitry Andric   SmallVectorImpl<FormatToken *>::const_iterator First = Tokens.end() - Count;
5770b57cec5SDimitry Andric   unsigned AddLength = 0;
578bdd1243dSDimitry Andric   for (size_t i = 1; i < Count; ++i) {
579bdd1243dSDimitry Andric     // If there is whitespace separating the token and the previous one,
580bdd1243dSDimitry Andric     // they should not be merged.
581bdd1243dSDimitry Andric     if (First[i]->hasWhitespaceBefore())
5820b57cec5SDimitry Andric       return false;
5830b57cec5SDimitry Andric     AddLength += First[i]->TokenText.size();
5840b57cec5SDimitry Andric   }
585bdd1243dSDimitry Andric 
586bdd1243dSDimitry Andric   Tokens.resize(Tokens.size() - Count + 1);
5870b57cec5SDimitry Andric   First[0]->TokenText = StringRef(First[0]->TokenText.data(),
5880b57cec5SDimitry Andric                                   First[0]->TokenText.size() + AddLength);
5890b57cec5SDimitry Andric   First[0]->ColumnWidth += AddLength;
5905ffd83dbSDimitry Andric   First[0]->setType(NewType);
5910b57cec5SDimitry Andric   return true;
5920b57cec5SDimitry Andric }
5930b57cec5SDimitry Andric 
594bdd1243dSDimitry Andric bool FormatTokenLexer::tryMergeTokensAny(
595bdd1243dSDimitry Andric     ArrayRef<ArrayRef<tok::TokenKind>> Kinds, TokenType NewType) {
596bdd1243dSDimitry Andric   return llvm::any_of(Kinds, [this, NewType](ArrayRef<tok::TokenKind> Kinds) {
597bdd1243dSDimitry Andric     return tryMergeTokens(Kinds, NewType);
598bdd1243dSDimitry Andric   });
599bdd1243dSDimitry Andric }
600bdd1243dSDimitry Andric 
6010b57cec5SDimitry Andric // Returns \c true if \p Tok can only be followed by an operand in JavaScript.
6020b57cec5SDimitry Andric bool FormatTokenLexer::precedesOperand(FormatToken *Tok) {
6030b57cec5SDimitry Andric   // NB: This is not entirely correct, as an r_paren can introduce an operand
6040b57cec5SDimitry Andric   // location in e.g. `if (foo) /bar/.exec(...);`. That is a rare enough
6050b57cec5SDimitry Andric   // corner case to not matter in practice, though.
6060b57cec5SDimitry Andric   return Tok->isOneOf(tok::period, tok::l_paren, tok::comma, tok::l_brace,
6070b57cec5SDimitry Andric                       tok::r_brace, tok::l_square, tok::semi, tok::exclaim,
6080b57cec5SDimitry Andric                       tok::colon, tok::question, tok::tilde) ||
6090b57cec5SDimitry Andric          Tok->isOneOf(tok::kw_return, tok::kw_do, tok::kw_case, tok::kw_throw,
6100b57cec5SDimitry Andric                       tok::kw_else, tok::kw_new, tok::kw_delete, tok::kw_void,
6110b57cec5SDimitry Andric                       tok::kw_typeof, Keywords.kw_instanceof, Keywords.kw_in) ||
6120b57cec5SDimitry Andric          Tok->isBinaryOperator();
6130b57cec5SDimitry Andric }
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric bool FormatTokenLexer::canPrecedeRegexLiteral(FormatToken *Prev) {
6160b57cec5SDimitry Andric   if (!Prev)
6170b57cec5SDimitry Andric     return true;
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   // Regex literals can only follow after prefix unary operators, not after
6200b57cec5SDimitry Andric   // postfix unary operators. If the '++' is followed by a non-operand
6210b57cec5SDimitry Andric   // introducing token, the slash here is the operand and not the start of a
6220b57cec5SDimitry Andric   // regex.
6230b57cec5SDimitry Andric   // `!` is an unary prefix operator, but also a post-fix operator that casts
6240b57cec5SDimitry Andric   // away nullability, so the same check applies.
6250b57cec5SDimitry Andric   if (Prev->isOneOf(tok::plusplus, tok::minusminus, tok::exclaim))
62681ad6265SDimitry Andric     return Tokens.size() < 3 || precedesOperand(Tokens[Tokens.size() - 3]);
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric   // The previous token must introduce an operand location where regex
6290b57cec5SDimitry Andric   // literals can occur.
6300b57cec5SDimitry Andric   if (!precedesOperand(Prev))
6310b57cec5SDimitry Andric     return false;
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   return true;
6340b57cec5SDimitry Andric }
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric // Tries to parse a JavaScript Regex literal starting at the current token,
6370b57cec5SDimitry Andric // if that begins with a slash and is in a location where JavaScript allows
6380b57cec5SDimitry Andric // regex literals. Changes the current token to a regex literal and updates
6390b57cec5SDimitry Andric // its text if successful.
6400b57cec5SDimitry Andric void FormatTokenLexer::tryParseJSRegexLiteral() {
6410b57cec5SDimitry Andric   FormatToken *RegexToken = Tokens.back();
6420b57cec5SDimitry Andric   if (!RegexToken->isOneOf(tok::slash, tok::slashequal))
6430b57cec5SDimitry Andric     return;
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   FormatToken *Prev = nullptr;
646349cc55cSDimitry Andric   for (FormatToken *FT : llvm::drop_begin(llvm::reverse(Tokens))) {
6470b57cec5SDimitry Andric     // NB: Because previous pointers are not initialized yet, this cannot use
6480b57cec5SDimitry Andric     // Token.getPreviousNonComment.
649349cc55cSDimitry Andric     if (FT->isNot(tok::comment)) {
650349cc55cSDimitry Andric       Prev = FT;
6510b57cec5SDimitry Andric       break;
6520b57cec5SDimitry Andric     }
6530b57cec5SDimitry Andric   }
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric   if (!canPrecedeRegexLiteral(Prev))
6560b57cec5SDimitry Andric     return;
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric   // 'Manually' lex ahead in the current file buffer.
6590b57cec5SDimitry Andric   const char *Offset = Lex->getBufferLocation();
6600b57cec5SDimitry Andric   const char *RegexBegin = Offset - RegexToken->TokenText.size();
6610b57cec5SDimitry Andric   StringRef Buffer = Lex->getBuffer();
6620b57cec5SDimitry Andric   bool InCharacterClass = false;
6630b57cec5SDimitry Andric   bool HaveClosingSlash = false;
6640b57cec5SDimitry Andric   for (; !HaveClosingSlash && Offset != Buffer.end(); ++Offset) {
6650b57cec5SDimitry Andric     // Regular expressions are terminated with a '/', which can only be
6660b57cec5SDimitry Andric     // escaped using '\' or a character class between '[' and ']'.
6670b57cec5SDimitry Andric     // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5.
6680b57cec5SDimitry Andric     switch (*Offset) {
6690b57cec5SDimitry Andric     case '\\':
6700b57cec5SDimitry Andric       // Skip the escaped character.
6710b57cec5SDimitry Andric       ++Offset;
6720b57cec5SDimitry Andric       break;
6730b57cec5SDimitry Andric     case '[':
6740b57cec5SDimitry Andric       InCharacterClass = true;
6750b57cec5SDimitry Andric       break;
6760b57cec5SDimitry Andric     case ']':
6770b57cec5SDimitry Andric       InCharacterClass = false;
6780b57cec5SDimitry Andric       break;
6790b57cec5SDimitry Andric     case '/':
6800b57cec5SDimitry Andric       if (!InCharacterClass)
6810b57cec5SDimitry Andric         HaveClosingSlash = true;
6820b57cec5SDimitry Andric       break;
6830b57cec5SDimitry Andric     }
6840b57cec5SDimitry Andric   }
6850b57cec5SDimitry Andric 
6865ffd83dbSDimitry Andric   RegexToken->setType(TT_RegexLiteral);
6870b57cec5SDimitry Andric   // Treat regex literals like other string_literals.
6880b57cec5SDimitry Andric   RegexToken->Tok.setKind(tok::string_literal);
6890b57cec5SDimitry Andric   RegexToken->TokenText = StringRef(RegexBegin, Offset - RegexBegin);
6900b57cec5SDimitry Andric   RegexToken->ColumnWidth = RegexToken->TokenText.size();
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
6930b57cec5SDimitry Andric }
6940b57cec5SDimitry Andric 
695972a253aSDimitry Andric static auto lexCSharpString(const char *Begin, const char *End, bool Verbatim,
696972a253aSDimitry Andric                             bool Interpolated) {
697972a253aSDimitry Andric   auto Repeated = [&Begin, End]() {
698972a253aSDimitry Andric     return Begin + 1 < End && Begin[1] == Begin[0];
699972a253aSDimitry Andric   };
7005ffd83dbSDimitry Andric 
7015ffd83dbSDimitry Andric   // Look for a terminating '"' in the current file buffer.
7025ffd83dbSDimitry Andric   // Make no effort to format code within an interpolated or verbatim string.
703972a253aSDimitry Andric   //
704972a253aSDimitry Andric   // Interpolated strings could contain { } with " characters inside.
705972a253aSDimitry Andric   // $"{x ?? "null"}"
706972a253aSDimitry Andric   // should not be split into $"{x ?? ", null, "}" but should be treated as a
707972a253aSDimitry Andric   // single string-literal.
708972a253aSDimitry Andric   //
709972a253aSDimitry Andric   // We opt not to try and format expressions inside {} within a C#
710972a253aSDimitry Andric   // interpolated string. Formatting expressions within an interpolated string
711972a253aSDimitry Andric   // would require similar work as that done for JavaScript template strings
712972a253aSDimitry Andric   // in `handleTemplateStrings()`.
713972a253aSDimitry Andric   for (int UnmatchedOpeningBraceCount = 0; Begin < End; ++Begin) {
714972a253aSDimitry Andric     switch (*Begin) {
715972a253aSDimitry Andric     case '\\':
716972a253aSDimitry Andric       if (!Verbatim)
717972a253aSDimitry Andric         ++Begin;
718972a253aSDimitry Andric       break;
719972a253aSDimitry Andric     case '{':
720972a253aSDimitry Andric       if (Interpolated) {
721972a253aSDimitry Andric         // {{ inside an interpolated string is escaped, so skip it.
722972a253aSDimitry Andric         if (Repeated())
723972a253aSDimitry Andric           ++Begin;
7245ffd83dbSDimitry Andric         else
725972a253aSDimitry Andric           ++UnmatchedOpeningBraceCount;
726972a253aSDimitry Andric       }
727972a253aSDimitry Andric       break;
728972a253aSDimitry Andric     case '}':
729972a253aSDimitry Andric       if (Interpolated) {
730972a253aSDimitry Andric         // }} inside an interpolated string is escaped, so skip it.
731972a253aSDimitry Andric         if (Repeated())
732972a253aSDimitry Andric           ++Begin;
733972a253aSDimitry Andric         else if (UnmatchedOpeningBraceCount > 0)
734972a253aSDimitry Andric           --UnmatchedOpeningBraceCount;
735972a253aSDimitry Andric         else
736972a253aSDimitry Andric           return End;
737972a253aSDimitry Andric       }
738972a253aSDimitry Andric       break;
739972a253aSDimitry Andric     case '"':
740972a253aSDimitry Andric       if (UnmatchedOpeningBraceCount > 0)
741972a253aSDimitry Andric         break;
742972a253aSDimitry Andric       // "" within a verbatim string is an escaped double quote: skip it.
743972a253aSDimitry Andric       if (Verbatim && Repeated()) {
744972a253aSDimitry Andric         ++Begin;
7455ffd83dbSDimitry Andric         break;
7465ffd83dbSDimitry Andric       }
747972a253aSDimitry Andric       return Begin;
7485ffd83dbSDimitry Andric     }
749972a253aSDimitry Andric   }
750972a253aSDimitry Andric 
751972a253aSDimitry Andric   return End;
752972a253aSDimitry Andric }
753972a253aSDimitry Andric 
754972a253aSDimitry Andric void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
755972a253aSDimitry Andric   FormatToken *CSharpStringLiteral = Tokens.back();
756972a253aSDimitry Andric 
757972a253aSDimitry Andric   if (CSharpStringLiteral->isNot(TT_CSharpStringLiteral))
758972a253aSDimitry Andric     return;
759972a253aSDimitry Andric 
760972a253aSDimitry Andric   auto &TokenText = CSharpStringLiteral->TokenText;
761972a253aSDimitry Andric 
762972a253aSDimitry Andric   bool Verbatim = false;
763972a253aSDimitry Andric   bool Interpolated = false;
7645f757f3fSDimitry Andric   if (TokenText.starts_with(R"($@")") || TokenText.starts_with(R"(@$")")) {
765972a253aSDimitry Andric     Verbatim = true;
766972a253aSDimitry Andric     Interpolated = true;
7675f757f3fSDimitry Andric   } else if (TokenText.starts_with(R"(@")")) {
768972a253aSDimitry Andric     Verbatim = true;
7695f757f3fSDimitry Andric   } else if (TokenText.starts_with(R"($")")) {
770972a253aSDimitry Andric     Interpolated = true;
771972a253aSDimitry Andric   }
772972a253aSDimitry Andric 
773972a253aSDimitry Andric   // Deal with multiline strings.
774972a253aSDimitry Andric   if (!Verbatim && !Interpolated)
775972a253aSDimitry Andric     return;
776972a253aSDimitry Andric 
777972a253aSDimitry Andric   const char *StrBegin = Lex->getBufferLocation() - TokenText.size();
778972a253aSDimitry Andric   const char *Offset = StrBegin;
779972a253aSDimitry Andric   if (Verbatim && Interpolated)
780972a253aSDimitry Andric     Offset += 3;
781972a253aSDimitry Andric   else
782972a253aSDimitry Andric     Offset += 2;
783972a253aSDimitry Andric 
784972a253aSDimitry Andric   const auto End = Lex->getBuffer().end();
785972a253aSDimitry Andric   Offset = lexCSharpString(Offset, End, Verbatim, Interpolated);
7865ffd83dbSDimitry Andric 
7875ffd83dbSDimitry Andric   // Make no attempt to format code properly if a verbatim string is
7885ffd83dbSDimitry Andric   // unterminated.
789972a253aSDimitry Andric   if (Offset >= End)
7905ffd83dbSDimitry Andric     return;
7915ffd83dbSDimitry Andric 
7925ffd83dbSDimitry Andric   StringRef LiteralText(StrBegin, Offset - StrBegin + 1);
793972a253aSDimitry Andric   TokenText = LiteralText;
7945ffd83dbSDimitry Andric 
7955ffd83dbSDimitry Andric   // Adjust width for potentially multiline string literals.
7965ffd83dbSDimitry Andric   size_t FirstBreak = LiteralText.find('\n');
7975ffd83dbSDimitry Andric   StringRef FirstLineText = FirstBreak == StringRef::npos
7985ffd83dbSDimitry Andric                                 ? LiteralText
7995ffd83dbSDimitry Andric                                 : LiteralText.substr(0, FirstBreak);
8005ffd83dbSDimitry Andric   CSharpStringLiteral->ColumnWidth = encoding::columnWidthWithTabs(
8015ffd83dbSDimitry Andric       FirstLineText, CSharpStringLiteral->OriginalColumn, Style.TabWidth,
8025ffd83dbSDimitry Andric       Encoding);
8035ffd83dbSDimitry Andric   size_t LastBreak = LiteralText.rfind('\n');
8045ffd83dbSDimitry Andric   if (LastBreak != StringRef::npos) {
8055ffd83dbSDimitry Andric     CSharpStringLiteral->IsMultiline = true;
8065ffd83dbSDimitry Andric     unsigned StartColumn = 0;
80781ad6265SDimitry Andric     CSharpStringLiteral->LastLineColumnWidth =
80881ad6265SDimitry Andric         encoding::columnWidthWithTabs(LiteralText.substr(LastBreak + 1),
80981ad6265SDimitry Andric                                       StartColumn, Style.TabWidth, Encoding);
8105ffd83dbSDimitry Andric   }
8115ffd83dbSDimitry Andric 
812972a253aSDimitry Andric   assert(Offset < End);
813972a253aSDimitry Andric   resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset + 1)));
8145ffd83dbSDimitry Andric }
8155ffd83dbSDimitry Andric 
8167a6dacacSDimitry Andric void FormatTokenLexer::handleTableGenMultilineString() {
8177a6dacacSDimitry Andric   FormatToken *MultiLineString = Tokens.back();
8187a6dacacSDimitry Andric   if (MultiLineString->isNot(TT_TableGenMultiLineString))
8197a6dacacSDimitry Andric     return;
8207a6dacacSDimitry Andric 
8217a6dacacSDimitry Andric   auto OpenOffset = Lex->getCurrentBufferOffset() - 2 /* "[{" */;
8227a6dacacSDimitry Andric   // "}]" is the end of multi line string.
8237a6dacacSDimitry Andric   auto CloseOffset = Lex->getBuffer().find("}]", OpenOffset);
8247a6dacacSDimitry Andric   if (CloseOffset == StringRef::npos)
8257a6dacacSDimitry Andric     return;
8260fca6ea1SDimitry Andric   auto Text = Lex->getBuffer().substr(OpenOffset, CloseOffset - OpenOffset + 2);
8277a6dacacSDimitry Andric   MultiLineString->TokenText = Text;
8287a6dacacSDimitry Andric   resetLexer(SourceMgr.getFileOffset(
8297a6dacacSDimitry Andric       Lex->getSourceLocation(Lex->getBufferLocation() - 2 + Text.size())));
8307a6dacacSDimitry Andric   auto FirstLineText = Text;
8317a6dacacSDimitry Andric   auto FirstBreak = Text.find('\n');
8327a6dacacSDimitry Andric   // Set ColumnWidth and LastLineColumnWidth when it has multiple lines.
8337a6dacacSDimitry Andric   if (FirstBreak != StringRef::npos) {
8347a6dacacSDimitry Andric     MultiLineString->IsMultiline = true;
8357a6dacacSDimitry Andric     FirstLineText = Text.substr(0, FirstBreak + 1);
8367a6dacacSDimitry Andric     // LastLineColumnWidth holds the width of the last line.
8377a6dacacSDimitry Andric     auto LastBreak = Text.rfind('\n');
8387a6dacacSDimitry Andric     MultiLineString->LastLineColumnWidth = encoding::columnWidthWithTabs(
8397a6dacacSDimitry Andric         Text.substr(LastBreak + 1), MultiLineString->OriginalColumn,
8407a6dacacSDimitry Andric         Style.TabWidth, Encoding);
8417a6dacacSDimitry Andric   }
8427a6dacacSDimitry Andric   // ColumnWidth holds only the width of the first line.
8437a6dacacSDimitry Andric   MultiLineString->ColumnWidth = encoding::columnWidthWithTabs(
8447a6dacacSDimitry Andric       FirstLineText, MultiLineString->OriginalColumn, Style.TabWidth, Encoding);
8457a6dacacSDimitry Andric }
8467a6dacacSDimitry Andric 
8477a6dacacSDimitry Andric void FormatTokenLexer::handleTableGenNumericLikeIdentifier() {
8487a6dacacSDimitry Andric   FormatToken *Tok = Tokens.back();
8497a6dacacSDimitry Andric   // TableGen identifiers can begin with digits. Such tokens are lexed as
8507a6dacacSDimitry Andric   // numeric_constant now.
8517a6dacacSDimitry Andric   if (Tok->isNot(tok::numeric_constant))
8527a6dacacSDimitry Andric     return;
8537a6dacacSDimitry Andric   StringRef Text = Tok->TokenText;
8547a6dacacSDimitry Andric   // The following check is based on llvm::TGLexer::LexToken.
8557a6dacacSDimitry Andric   // That lexes the token as a number if any of the following holds:
8567a6dacacSDimitry Andric   // 1. It starts with '+', '-'.
8577a6dacacSDimitry Andric   // 2. All the characters are digits.
8587a6dacacSDimitry Andric   // 3. The first non-digit character is 'b', and the next is '0' or '1'.
8597a6dacacSDimitry Andric   // 4. The first non-digit character is 'x', and the next is a hex digit.
8607a6dacacSDimitry Andric   // Note that in the case 3 and 4, if the next character does not exists in
8617a6dacacSDimitry Andric   // this token, the token is an identifier.
8627a6dacacSDimitry Andric   if (Text.size() < 1 || Text[0] == '+' || Text[0] == '-')
8637a6dacacSDimitry Andric     return;
8647a6dacacSDimitry Andric   const auto NonDigitPos = Text.find_if([](char C) { return !isdigit(C); });
8657a6dacacSDimitry Andric   // All the characters are digits
8667a6dacacSDimitry Andric   if (NonDigitPos == StringRef::npos)
8677a6dacacSDimitry Andric     return;
8687a6dacacSDimitry Andric   char FirstNonDigit = Text[NonDigitPos];
8697a6dacacSDimitry Andric   if (NonDigitPos < Text.size() - 1) {
8707a6dacacSDimitry Andric     char TheNext = Text[NonDigitPos + 1];
8717a6dacacSDimitry Andric     // Regarded as a binary number.
8727a6dacacSDimitry Andric     if (FirstNonDigit == 'b' && (TheNext == '0' || TheNext == '1'))
8737a6dacacSDimitry Andric       return;
8747a6dacacSDimitry Andric     // Regarded as hex number.
8757a6dacacSDimitry Andric     if (FirstNonDigit == 'x' && isxdigit(TheNext))
8767a6dacacSDimitry Andric       return;
8777a6dacacSDimitry Andric   }
8787a6dacacSDimitry Andric   if (isalpha(FirstNonDigit) || FirstNonDigit == '_') {
8797a6dacacSDimitry Andric     // This is actually an identifier in TableGen.
8807a6dacacSDimitry Andric     Tok->Tok.setKind(tok::identifier);
8817a6dacacSDimitry Andric     Tok->Tok.setIdentifierInfo(nullptr);
8827a6dacacSDimitry Andric   }
8837a6dacacSDimitry Andric }
8847a6dacacSDimitry Andric 
8850b57cec5SDimitry Andric void FormatTokenLexer::handleTemplateStrings() {
8860b57cec5SDimitry Andric   FormatToken *BacktickToken = Tokens.back();
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric   if (BacktickToken->is(tok::l_brace)) {
8890b57cec5SDimitry Andric     StateStack.push(LexerState::NORMAL);
8900b57cec5SDimitry Andric     return;
8910b57cec5SDimitry Andric   }
8920b57cec5SDimitry Andric   if (BacktickToken->is(tok::r_brace)) {
8930b57cec5SDimitry Andric     if (StateStack.size() == 1)
8940b57cec5SDimitry Andric       return;
8950b57cec5SDimitry Andric     StateStack.pop();
8960b57cec5SDimitry Andric     if (StateStack.top() != LexerState::TEMPLATE_STRING)
8970b57cec5SDimitry Andric       return;
8980b57cec5SDimitry Andric     // If back in TEMPLATE_STRING, fallthrough and continue parsing the
8990b57cec5SDimitry Andric   } else if (BacktickToken->is(tok::unknown) &&
9000b57cec5SDimitry Andric              BacktickToken->TokenText == "`") {
9010b57cec5SDimitry Andric     StateStack.push(LexerState::TEMPLATE_STRING);
9020b57cec5SDimitry Andric   } else {
9030b57cec5SDimitry Andric     return; // Not actually a template
9040b57cec5SDimitry Andric   }
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric   // 'Manually' lex ahead in the current file buffer.
9070b57cec5SDimitry Andric   const char *Offset = Lex->getBufferLocation();
9080b57cec5SDimitry Andric   const char *TmplBegin = Offset - BacktickToken->TokenText.size(); // at "`"
9090b57cec5SDimitry Andric   for (; Offset != Lex->getBuffer().end(); ++Offset) {
9100b57cec5SDimitry Andric     if (Offset[0] == '`') {
9110b57cec5SDimitry Andric       StateStack.pop();
912bdd1243dSDimitry Andric       ++Offset;
9130b57cec5SDimitry Andric       break;
9140b57cec5SDimitry Andric     }
9150b57cec5SDimitry Andric     if (Offset[0] == '\\') {
9160b57cec5SDimitry Andric       ++Offset; // Skip the escaped character.
9170b57cec5SDimitry Andric     } else if (Offset + 1 < Lex->getBuffer().end() && Offset[0] == '$' &&
9180b57cec5SDimitry Andric                Offset[1] == '{') {
9190b57cec5SDimitry Andric       // '${' introduces an expression interpolation in the template string.
9200b57cec5SDimitry Andric       StateStack.push(LexerState::NORMAL);
921bdd1243dSDimitry Andric       Offset += 2;
9220b57cec5SDimitry Andric       break;
9230b57cec5SDimitry Andric     }
9240b57cec5SDimitry Andric   }
9250b57cec5SDimitry Andric 
926bdd1243dSDimitry Andric   StringRef LiteralText(TmplBegin, Offset - TmplBegin);
9275ffd83dbSDimitry Andric   BacktickToken->setType(TT_TemplateString);
9280b57cec5SDimitry Andric   BacktickToken->Tok.setKind(tok::string_literal);
9290b57cec5SDimitry Andric   BacktickToken->TokenText = LiteralText;
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric   // Adjust width for potentially multiline string literals.
9320b57cec5SDimitry Andric   size_t FirstBreak = LiteralText.find('\n');
9330b57cec5SDimitry Andric   StringRef FirstLineText = FirstBreak == StringRef::npos
9340b57cec5SDimitry Andric                                 ? LiteralText
9350b57cec5SDimitry Andric                                 : LiteralText.substr(0, FirstBreak);
9360b57cec5SDimitry Andric   BacktickToken->ColumnWidth = encoding::columnWidthWithTabs(
9370b57cec5SDimitry Andric       FirstLineText, BacktickToken->OriginalColumn, Style.TabWidth, Encoding);
9380b57cec5SDimitry Andric   size_t LastBreak = LiteralText.rfind('\n');
9390b57cec5SDimitry Andric   if (LastBreak != StringRef::npos) {
9400b57cec5SDimitry Andric     BacktickToken->IsMultiline = true;
9410b57cec5SDimitry Andric     unsigned StartColumn = 0; // The template tail spans the entire line.
94281ad6265SDimitry Andric     BacktickToken->LastLineColumnWidth =
94381ad6265SDimitry Andric         encoding::columnWidthWithTabs(LiteralText.substr(LastBreak + 1),
94481ad6265SDimitry Andric                                       StartColumn, Style.TabWidth, Encoding);
9450b57cec5SDimitry Andric   }
9460b57cec5SDimitry Andric 
947bdd1243dSDimitry Andric   SourceLocation loc = Lex->getSourceLocation(Offset);
9480b57cec5SDimitry Andric   resetLexer(SourceMgr.getFileOffset(loc));
9490b57cec5SDimitry Andric }
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric void FormatTokenLexer::tryParsePythonComment() {
9520b57cec5SDimitry Andric   FormatToken *HashToken = Tokens.back();
9530b57cec5SDimitry Andric   if (!HashToken->isOneOf(tok::hash, tok::hashhash))
9540b57cec5SDimitry Andric     return;
9550b57cec5SDimitry Andric   // Turn the remainder of this line into a comment.
9560b57cec5SDimitry Andric   const char *CommentBegin =
9570b57cec5SDimitry Andric       Lex->getBufferLocation() - HashToken->TokenText.size(); // at "#"
9580b57cec5SDimitry Andric   size_t From = CommentBegin - Lex->getBuffer().begin();
9590b57cec5SDimitry Andric   size_t To = Lex->getBuffer().find_first_of('\n', From);
9600b57cec5SDimitry Andric   if (To == StringRef::npos)
9610b57cec5SDimitry Andric     To = Lex->getBuffer().size();
9620b57cec5SDimitry Andric   size_t Len = To - From;
9635ffd83dbSDimitry Andric   HashToken->setType(TT_LineComment);
9640b57cec5SDimitry Andric   HashToken->Tok.setKind(tok::comment);
9650b57cec5SDimitry Andric   HashToken->TokenText = Lex->getBuffer().substr(From, Len);
9660b57cec5SDimitry Andric   SourceLocation Loc = To < Lex->getBuffer().size()
9670b57cec5SDimitry Andric                            ? Lex->getSourceLocation(CommentBegin + Len)
9680b57cec5SDimitry Andric                            : SourceMgr.getLocForEndOfFile(ID);
9690b57cec5SDimitry Andric   resetLexer(SourceMgr.getFileOffset(Loc));
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric bool FormatTokenLexer::tryMerge_TMacro() {
9730b57cec5SDimitry Andric   if (Tokens.size() < 4)
9740b57cec5SDimitry Andric     return false;
9750b57cec5SDimitry Andric   FormatToken *Last = Tokens.back();
9765f757f3fSDimitry Andric   if (Last->isNot(tok::r_paren))
9770b57cec5SDimitry Andric     return false;
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric   FormatToken *String = Tokens[Tokens.size() - 2];
9805f757f3fSDimitry Andric   if (String->isNot(tok::string_literal) || String->IsMultiline)
9810b57cec5SDimitry Andric     return false;
9820b57cec5SDimitry Andric 
9835f757f3fSDimitry Andric   if (Tokens[Tokens.size() - 3]->isNot(tok::l_paren))
9840b57cec5SDimitry Andric     return false;
9850b57cec5SDimitry Andric 
9860b57cec5SDimitry Andric   FormatToken *Macro = Tokens[Tokens.size() - 4];
9870b57cec5SDimitry Andric   if (Macro->TokenText != "_T")
9880b57cec5SDimitry Andric     return false;
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric   const char *Start = Macro->TokenText.data();
9910b57cec5SDimitry Andric   const char *End = Last->TokenText.data() + Last->TokenText.size();
9920b57cec5SDimitry Andric   String->TokenText = StringRef(Start, End - Start);
9930b57cec5SDimitry Andric   String->IsFirst = Macro->IsFirst;
9940b57cec5SDimitry Andric   String->LastNewlineOffset = Macro->LastNewlineOffset;
9950b57cec5SDimitry Andric   String->WhitespaceRange = Macro->WhitespaceRange;
9960b57cec5SDimitry Andric   String->OriginalColumn = Macro->OriginalColumn;
9970b57cec5SDimitry Andric   String->ColumnWidth = encoding::columnWidthWithTabs(
9980b57cec5SDimitry Andric       String->TokenText, String->OriginalColumn, Style.TabWidth, Encoding);
9990b57cec5SDimitry Andric   String->NewlinesBefore = Macro->NewlinesBefore;
10000b57cec5SDimitry Andric   String->HasUnescapedNewline = Macro->HasUnescapedNewline;
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric   Tokens.pop_back();
10030b57cec5SDimitry Andric   Tokens.pop_back();
10040b57cec5SDimitry Andric   Tokens.pop_back();
10050b57cec5SDimitry Andric   Tokens.back() = String;
10064824e7fdSDimitry Andric   if (FirstInLineIndex >= Tokens.size())
10074824e7fdSDimitry Andric     FirstInLineIndex = Tokens.size() - 1;
10080b57cec5SDimitry Andric   return true;
10090b57cec5SDimitry Andric }
10100b57cec5SDimitry Andric 
10110b57cec5SDimitry Andric bool FormatTokenLexer::tryMergeConflictMarkers() {
10120b57cec5SDimitry Andric   if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof))
10130b57cec5SDimitry Andric     return false;
10140b57cec5SDimitry Andric 
10150b57cec5SDimitry Andric   // Conflict lines look like:
10160b57cec5SDimitry Andric   // <marker> <text from the vcs>
10170b57cec5SDimitry Andric   // For example:
10180b57cec5SDimitry Andric   // >>>>>>> /file/in/file/system at revision 1234
10190b57cec5SDimitry Andric   //
10200b57cec5SDimitry Andric   // We merge all tokens in a line that starts with a conflict marker
10210b57cec5SDimitry Andric   // into a single token with a special token type that the unwrapped line
10220b57cec5SDimitry Andric   // parser will use to correctly rebuild the underlying code.
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric   FileID ID;
10250b57cec5SDimitry Andric   // Get the position of the first token in the line.
10260b57cec5SDimitry Andric   unsigned FirstInLineOffset;
10270b57cec5SDimitry Andric   std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc(
10280b57cec5SDimitry Andric       Tokens[FirstInLineIndex]->getStartOfNonWhitespace());
1029e8d8bef9SDimitry Andric   StringRef Buffer = SourceMgr.getBufferOrFake(ID).getBuffer();
10300b57cec5SDimitry Andric   // Calculate the offset of the start of the current line.
10310b57cec5SDimitry Andric   auto LineOffset = Buffer.rfind('\n', FirstInLineOffset);
103281ad6265SDimitry Andric   if (LineOffset == StringRef::npos)
10330b57cec5SDimitry Andric     LineOffset = 0;
103481ad6265SDimitry Andric   else
10350b57cec5SDimitry Andric     ++LineOffset;
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric   auto FirstSpace = Buffer.find_first_of(" \n", LineOffset);
10380b57cec5SDimitry Andric   StringRef LineStart;
103981ad6265SDimitry Andric   if (FirstSpace == StringRef::npos)
10400b57cec5SDimitry Andric     LineStart = Buffer.substr(LineOffset);
104181ad6265SDimitry Andric   else
10420b57cec5SDimitry Andric     LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric   TokenType Type = TT_Unknown;
10450b57cec5SDimitry Andric   if (LineStart == "<<<<<<<" || LineStart == ">>>>") {
10460b57cec5SDimitry Andric     Type = TT_ConflictStart;
10470b57cec5SDimitry Andric   } else if (LineStart == "|||||||" || LineStart == "=======" ||
10480b57cec5SDimitry Andric              LineStart == "====") {
10490b57cec5SDimitry Andric     Type = TT_ConflictAlternative;
10500b57cec5SDimitry Andric   } else if (LineStart == ">>>>>>>" || LineStart == "<<<<") {
10510b57cec5SDimitry Andric     Type = TT_ConflictEnd;
10520b57cec5SDimitry Andric   }
10530b57cec5SDimitry Andric 
10540b57cec5SDimitry Andric   if (Type != TT_Unknown) {
10550b57cec5SDimitry Andric     FormatToken *Next = Tokens.back();
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric     Tokens.resize(FirstInLineIndex + 1);
10580b57cec5SDimitry Andric     // We do not need to build a complete token here, as we will skip it
10590b57cec5SDimitry Andric     // during parsing anyway (as we must not touch whitespace around conflict
10600b57cec5SDimitry Andric     // markers).
10615ffd83dbSDimitry Andric     Tokens.back()->setType(Type);
10620b57cec5SDimitry Andric     Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric     Tokens.push_back(Next);
10650b57cec5SDimitry Andric     return true;
10660b57cec5SDimitry Andric   }
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric   return false;
10690b57cec5SDimitry Andric }
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric FormatToken *FormatTokenLexer::getStashedToken() {
10720b57cec5SDimitry Andric   // Create a synthesized second '>' or '<' token.
10730b57cec5SDimitry Andric   Token Tok = FormatTok->Tok;
10740b57cec5SDimitry Andric   StringRef TokenText = FormatTok->TokenText;
10750b57cec5SDimitry Andric 
10760b57cec5SDimitry Andric   unsigned OriginalColumn = FormatTok->OriginalColumn;
10770b57cec5SDimitry Andric   FormatTok = new (Allocator.Allocate()) FormatToken;
10780b57cec5SDimitry Andric   FormatTok->Tok = Tok;
10790b57cec5SDimitry Andric   SourceLocation TokLocation =
10800b57cec5SDimitry Andric       FormatTok->Tok.getLocation().getLocWithOffset(Tok.getLength() - 1);
10810b57cec5SDimitry Andric   FormatTok->Tok.setLocation(TokLocation);
10820b57cec5SDimitry Andric   FormatTok->WhitespaceRange = SourceRange(TokLocation, TokLocation);
10830b57cec5SDimitry Andric   FormatTok->TokenText = TokenText;
10840b57cec5SDimitry Andric   FormatTok->ColumnWidth = 1;
10850b57cec5SDimitry Andric   FormatTok->OriginalColumn = OriginalColumn + 1;
10860b57cec5SDimitry Andric 
10870b57cec5SDimitry Andric   return FormatTok;
10880b57cec5SDimitry Andric }
10890b57cec5SDimitry Andric 
109081ad6265SDimitry Andric /// Truncate the current token to the new length and make the lexer continue
109181ad6265SDimitry Andric /// from the end of the truncated token. Used for other languages that have
109281ad6265SDimitry Andric /// different token boundaries, like JavaScript in which a comment ends at a
109381ad6265SDimitry Andric /// line break regardless of whether the line break follows a backslash. Also
109481ad6265SDimitry Andric /// used to set the lexer to the end of whitespace if the lexer regards
109581ad6265SDimitry Andric /// whitespace and an unrecognized symbol as one token.
109681ad6265SDimitry Andric void FormatTokenLexer::truncateToken(size_t NewLen) {
109781ad6265SDimitry Andric   assert(NewLen <= FormatTok->TokenText.size());
109881ad6265SDimitry Andric   resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(
109981ad6265SDimitry Andric       Lex->getBufferLocation() - FormatTok->TokenText.size() + NewLen)));
110081ad6265SDimitry Andric   FormatTok->TokenText = FormatTok->TokenText.substr(0, NewLen);
110181ad6265SDimitry Andric   FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
110281ad6265SDimitry Andric       FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth,
110381ad6265SDimitry Andric       Encoding);
110481ad6265SDimitry Andric   FormatTok->Tok.setLength(NewLen);
110581ad6265SDimitry Andric }
110681ad6265SDimitry Andric 
110781ad6265SDimitry Andric /// Count the length of leading whitespace in a token.
110881ad6265SDimitry Andric static size_t countLeadingWhitespace(StringRef Text) {
110981ad6265SDimitry Andric   // Basically counting the length matched by this regex.
111081ad6265SDimitry Andric   // "^([\n\r\f\v \t]|(\\\\|\\?\\?/)[\n\r])+"
111181ad6265SDimitry Andric   // Directly using the regex turned out to be slow. With the regex
111281ad6265SDimitry Andric   // version formatting all files in this directory took about 1.25
111381ad6265SDimitry Andric   // seconds. This version took about 0.5 seconds.
111481ad6265SDimitry Andric   const unsigned char *const Begin = Text.bytes_begin();
111581ad6265SDimitry Andric   const unsigned char *const End = Text.bytes_end();
111681ad6265SDimitry Andric   const unsigned char *Cur = Begin;
111781ad6265SDimitry Andric   while (Cur < End) {
111881ad6265SDimitry Andric     if (isspace(Cur[0])) {
111981ad6265SDimitry Andric       ++Cur;
112081ad6265SDimitry Andric     } else if (Cur[0] == '\\' && (Cur[1] == '\n' || Cur[1] == '\r')) {
112181ad6265SDimitry Andric       // A '\' followed by a newline always escapes the newline, regardless
112281ad6265SDimitry Andric       // of whether there is another '\' before it.
112381ad6265SDimitry Andric       // The source has a null byte at the end. So the end of the entire input
112481ad6265SDimitry Andric       // isn't reached yet. Also the lexer doesn't break apart an escaped
112581ad6265SDimitry Andric       // newline.
112681ad6265SDimitry Andric       assert(End - Cur >= 2);
112781ad6265SDimitry Andric       Cur += 2;
112881ad6265SDimitry Andric     } else if (Cur[0] == '?' && Cur[1] == '?' && Cur[2] == '/' &&
112981ad6265SDimitry Andric                (Cur[3] == '\n' || Cur[3] == '\r')) {
113081ad6265SDimitry Andric       // Newlines can also be escaped by a '?' '?' '/' trigraph. By the way, the
113181ad6265SDimitry Andric       // characters are quoted individually in this comment because if we write
113281ad6265SDimitry Andric       // them together some compilers warn that we have a trigraph in the code.
113381ad6265SDimitry Andric       assert(End - Cur >= 4);
113481ad6265SDimitry Andric       Cur += 4;
113581ad6265SDimitry Andric     } else {
113681ad6265SDimitry Andric       break;
113781ad6265SDimitry Andric     }
113881ad6265SDimitry Andric   }
113981ad6265SDimitry Andric   return Cur - Begin;
114081ad6265SDimitry Andric }
114181ad6265SDimitry Andric 
11420b57cec5SDimitry Andric FormatToken *FormatTokenLexer::getNextToken() {
11430b57cec5SDimitry Andric   if (StateStack.top() == LexerState::TOKEN_STASHED) {
11440b57cec5SDimitry Andric     StateStack.pop();
11450b57cec5SDimitry Andric     return getStashedToken();
11460b57cec5SDimitry Andric   }
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric   FormatTok = new (Allocator.Allocate()) FormatToken;
11490b57cec5SDimitry Andric   readRawToken(*FormatTok);
11500b57cec5SDimitry Andric   SourceLocation WhitespaceStart =
11510b57cec5SDimitry Andric       FormatTok->Tok.getLocation().getLocWithOffset(-TrailingWhitespace);
11520b57cec5SDimitry Andric   FormatTok->IsFirst = IsFirstToken;
11530b57cec5SDimitry Andric   IsFirstToken = false;
11540b57cec5SDimitry Andric 
11550b57cec5SDimitry Andric   // Consume and record whitespace until we find a significant token.
115681ad6265SDimitry Andric   // Some tok::unknown tokens are not just whitespace, e.g. whitespace
115781ad6265SDimitry Andric   // followed by a symbol such as backtick. Those symbols may be
115881ad6265SDimitry Andric   // significant in other languages.
11590b57cec5SDimitry Andric   unsigned WhitespaceLength = TrailingWhitespace;
116081ad6265SDimitry Andric   while (FormatTok->isNot(tok::eof)) {
116181ad6265SDimitry Andric     auto LeadingWhitespace = countLeadingWhitespace(FormatTok->TokenText);
116281ad6265SDimitry Andric     if (LeadingWhitespace == 0)
11630b57cec5SDimitry Andric       break;
116481ad6265SDimitry Andric     if (LeadingWhitespace < FormatTok->TokenText.size())
116581ad6265SDimitry Andric       truncateToken(LeadingWhitespace);
116681ad6265SDimitry Andric     StringRef Text = FormatTok->TokenText;
116781ad6265SDimitry Andric     bool InEscape = false;
11680b57cec5SDimitry Andric     for (int i = 0, e = Text.size(); i != e; ++i) {
11690b57cec5SDimitry Andric       switch (Text[i]) {
117081ad6265SDimitry Andric       case '\r':
117181ad6265SDimitry Andric         // If this is a CRLF sequence, break here and the LF will be handled on
117281ad6265SDimitry Andric         // the next loop iteration. Otherwise, this is a single Mac CR, treat it
117381ad6265SDimitry Andric         // the same as a single LF.
117481ad6265SDimitry Andric         if (i + 1 < e && Text[i + 1] == '\n')
117581ad6265SDimitry Andric           break;
1176bdd1243dSDimitry Andric         [[fallthrough]];
11770b57cec5SDimitry Andric       case '\n':
11780b57cec5SDimitry Andric         ++FormatTok->NewlinesBefore;
117981ad6265SDimitry Andric         if (!InEscape)
118081ad6265SDimitry Andric           FormatTok->HasUnescapedNewline = true;
118181ad6265SDimitry Andric         else
118281ad6265SDimitry Andric           InEscape = false;
11830b57cec5SDimitry Andric         FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
11840b57cec5SDimitry Andric         Column = 0;
11850b57cec5SDimitry Andric         break;
11860b57cec5SDimitry Andric       case '\f':
11870b57cec5SDimitry Andric       case '\v':
11880b57cec5SDimitry Andric         Column = 0;
11890b57cec5SDimitry Andric         break;
11900b57cec5SDimitry Andric       case ' ':
11910b57cec5SDimitry Andric         ++Column;
11920b57cec5SDimitry Andric         break;
11930b57cec5SDimitry Andric       case '\t':
1194a7dea167SDimitry Andric         Column +=
1195a7dea167SDimitry Andric             Style.TabWidth - (Style.TabWidth ? Column % Style.TabWidth : 0);
11960b57cec5SDimitry Andric         break;
11970b57cec5SDimitry Andric       case '\\':
119881ad6265SDimitry Andric       case '?':
119981ad6265SDimitry Andric       case '/':
120081ad6265SDimitry Andric         // The text was entirely whitespace when this loop was entered. Thus
120181ad6265SDimitry Andric         // this has to be an escape sequence.
120281ad6265SDimitry Andric         assert(Text.substr(i, 2) == "\\\r" || Text.substr(i, 2) == "\\\n" ||
120381ad6265SDimitry Andric                Text.substr(i, 4) == "\?\?/\r" ||
120481ad6265SDimitry Andric                Text.substr(i, 4) == "\?\?/\n" ||
120581ad6265SDimitry Andric                (i >= 1 && (Text.substr(i - 1, 4) == "\?\?/\r" ||
120681ad6265SDimitry Andric                            Text.substr(i - 1, 4) == "\?\?/\n")) ||
120781ad6265SDimitry Andric                (i >= 2 && (Text.substr(i - 2, 4) == "\?\?/\r" ||
120881ad6265SDimitry Andric                            Text.substr(i - 2, 4) == "\?\?/\n")));
120981ad6265SDimitry Andric         InEscape = true;
12100b57cec5SDimitry Andric         break;
12110b57cec5SDimitry Andric       default:
121281ad6265SDimitry Andric         // This shouldn't happen.
121381ad6265SDimitry Andric         assert(false);
12140b57cec5SDimitry Andric         break;
12150b57cec5SDimitry Andric       }
12160b57cec5SDimitry Andric     }
121781ad6265SDimitry Andric     WhitespaceLength += Text.size();
12180b57cec5SDimitry Andric     readRawToken(*FormatTok);
12190b57cec5SDimitry Andric   }
12200b57cec5SDimitry Andric 
122181ad6265SDimitry Andric   if (FormatTok->is(tok::unknown))
122281ad6265SDimitry Andric     FormatTok->setType(TT_ImplicitStringLiteral);
122381ad6265SDimitry Andric 
12240b57cec5SDimitry Andric   // JavaScript and Java do not allow to escape the end of the line with a
12250b57cec5SDimitry Andric   // backslash. Backslashes are syntax errors in plain source, but can occur in
12260b57cec5SDimitry Andric   // comments. When a single line comment ends with a \, it'll cause the next
12270b57cec5SDimitry Andric   // line of code to be lexed as a comment, breaking formatting. The code below
12280b57cec5SDimitry Andric   // finds comments that contain a backslash followed by a line break, truncates
12290b57cec5SDimitry Andric   // the comment token at the backslash, and resets the lexer to restart behind
12300b57cec5SDimitry Andric   // the backslash.
12310eae32dcSDimitry Andric   if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) &&
12325f757f3fSDimitry Andric       FormatTok->is(tok::comment) && FormatTok->TokenText.starts_with("//")) {
12330b57cec5SDimitry Andric     size_t BackslashPos = FormatTok->TokenText.find('\\');
12340b57cec5SDimitry Andric     while (BackslashPos != StringRef::npos) {
12350b57cec5SDimitry Andric       if (BackslashPos + 1 < FormatTok->TokenText.size() &&
12360b57cec5SDimitry Andric           FormatTok->TokenText[BackslashPos + 1] == '\n') {
123781ad6265SDimitry Andric         truncateToken(BackslashPos + 1);
12380b57cec5SDimitry Andric         break;
12390b57cec5SDimitry Andric       }
12400b57cec5SDimitry Andric       BackslashPos = FormatTok->TokenText.find('\\', BackslashPos + 1);
12410b57cec5SDimitry Andric     }
12420b57cec5SDimitry Andric   }
12430b57cec5SDimitry Andric 
124481ad6265SDimitry Andric   if (Style.isVerilog()) {
1245bdd1243dSDimitry Andric     static const llvm::Regex NumberBase("^s?[bdho]", llvm::Regex::IgnoreCase);
1246bdd1243dSDimitry Andric     SmallVector<StringRef, 1> Matches;
124781ad6265SDimitry Andric     // Verilog uses the backtick instead of the hash for preprocessor stuff.
124881ad6265SDimitry Andric     // And it uses the hash for delays and parameter lists. In order to continue
124981ad6265SDimitry Andric     // using `tok::hash` in other places, the backtick gets marked as the hash
125081ad6265SDimitry Andric     // here.  And in order to tell the backtick and hash apart for
125181ad6265SDimitry Andric     // Verilog-specific stuff, the hash becomes an identifier.
1252bdd1243dSDimitry Andric     if (FormatTok->is(tok::numeric_constant)) {
1253bdd1243dSDimitry Andric       // In Verilog the quote is not part of a number.
1254bdd1243dSDimitry Andric       auto Quote = FormatTok->TokenText.find('\'');
1255bdd1243dSDimitry Andric       if (Quote != StringRef::npos)
1256bdd1243dSDimitry Andric         truncateToken(Quote);
1257bdd1243dSDimitry Andric     } else if (FormatTok->isOneOf(tok::hash, tok::hashhash)) {
125881ad6265SDimitry Andric       FormatTok->Tok.setKind(tok::raw_identifier);
125981ad6265SDimitry Andric     } else if (FormatTok->is(tok::raw_identifier)) {
126081ad6265SDimitry Andric       if (FormatTok->TokenText == "`") {
126181ad6265SDimitry Andric         FormatTok->Tok.setIdentifierInfo(nullptr);
126281ad6265SDimitry Andric         FormatTok->Tok.setKind(tok::hash);
126381ad6265SDimitry Andric       } else if (FormatTok->TokenText == "``") {
126481ad6265SDimitry Andric         FormatTok->Tok.setIdentifierInfo(nullptr);
126581ad6265SDimitry Andric         FormatTok->Tok.setKind(tok::hashhash);
1266bdd1243dSDimitry Andric       } else if (Tokens.size() > 0 &&
1267bdd1243dSDimitry Andric                  Tokens.back()->is(Keywords.kw_apostrophe) &&
1268bdd1243dSDimitry Andric                  NumberBase.match(FormatTok->TokenText, &Matches)) {
1269bdd1243dSDimitry Andric         // In Verilog in a based number literal like `'b10`, there may be
1270bdd1243dSDimitry Andric         // whitespace between `'b` and `10`. Therefore we handle the base and
1271bdd1243dSDimitry Andric         // the rest of the number literal as two tokens. But if there is no
1272bdd1243dSDimitry Andric         // space in the input code, we need to manually separate the two parts.
1273bdd1243dSDimitry Andric         truncateToken(Matches[0].size());
1274bdd1243dSDimitry Andric         FormatTok->setFinalizedType(TT_VerilogNumberBase);
127581ad6265SDimitry Andric       }
127681ad6265SDimitry Andric     }
12770b57cec5SDimitry Andric   }
12780b57cec5SDimitry Andric 
12790b57cec5SDimitry Andric   FormatTok->WhitespaceRange = SourceRange(
12800b57cec5SDimitry Andric       WhitespaceStart, WhitespaceStart.getLocWithOffset(WhitespaceLength));
12810b57cec5SDimitry Andric 
12820b57cec5SDimitry Andric   FormatTok->OriginalColumn = Column;
12830b57cec5SDimitry Andric 
12840b57cec5SDimitry Andric   TrailingWhitespace = 0;
128581ad6265SDimitry Andric   if (FormatTok->is(tok::comment)) {
12860b57cec5SDimitry Andric     // FIXME: Add the trimmed whitespace to Column.
12870b57cec5SDimitry Andric     StringRef UntrimmedText = FormatTok->TokenText;
12880b57cec5SDimitry Andric     FormatTok->TokenText = FormatTok->TokenText.rtrim(" \t\v\f");
12890b57cec5SDimitry Andric     TrailingWhitespace = UntrimmedText.size() - FormatTok->TokenText.size();
129081ad6265SDimitry Andric   } else if (FormatTok->is(tok::raw_identifier)) {
12910b57cec5SDimitry Andric     IdentifierInfo &Info = IdentTable.get(FormatTok->TokenText);
12920b57cec5SDimitry Andric     FormatTok->Tok.setIdentifierInfo(&Info);
12930b57cec5SDimitry Andric     FormatTok->Tok.setKind(Info.getTokenID());
12940b57cec5SDimitry Andric     if (Style.Language == FormatStyle::LK_Java &&
12950b57cec5SDimitry Andric         FormatTok->isOneOf(tok::kw_struct, tok::kw_union, tok::kw_delete,
12960b57cec5SDimitry Andric                            tok::kw_operator)) {
12970b57cec5SDimitry Andric       FormatTok->Tok.setKind(tok::identifier);
12980b57cec5SDimitry Andric       FormatTok->Tok.setIdentifierInfo(nullptr);
12990eae32dcSDimitry Andric     } else if (Style.isJavaScript() &&
13000b57cec5SDimitry Andric                FormatTok->isOneOf(tok::kw_struct, tok::kw_union,
13010b57cec5SDimitry Andric                                   tok::kw_operator)) {
13020b57cec5SDimitry Andric       FormatTok->Tok.setKind(tok::identifier);
13030b57cec5SDimitry Andric       FormatTok->Tok.setIdentifierInfo(nullptr);
13047a6dacacSDimitry Andric     } else if (Style.isTableGen() && !Keywords.isTableGenKeyword(*FormatTok)) {
13057a6dacacSDimitry Andric       FormatTok->Tok.setKind(tok::identifier);
13067a6dacacSDimitry Andric       FormatTok->Tok.setIdentifierInfo(nullptr);
13070b57cec5SDimitry Andric     }
130881ad6265SDimitry Andric   } else if (FormatTok->is(tok::greatergreater)) {
13090b57cec5SDimitry Andric     FormatTok->Tok.setKind(tok::greater);
13100b57cec5SDimitry Andric     FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
13110b57cec5SDimitry Andric     ++Column;
13120b57cec5SDimitry Andric     StateStack.push(LexerState::TOKEN_STASHED);
131381ad6265SDimitry Andric   } else if (FormatTok->is(tok::lessless)) {
13140b57cec5SDimitry Andric     FormatTok->Tok.setKind(tok::less);
13150b57cec5SDimitry Andric     FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
13160b57cec5SDimitry Andric     ++Column;
13170b57cec5SDimitry Andric     StateStack.push(LexerState::TOKEN_STASHED);
13180b57cec5SDimitry Andric   }
13190b57cec5SDimitry Andric 
1320bdd1243dSDimitry Andric   if (Style.isVerilog() && Tokens.size() > 0 &&
1321bdd1243dSDimitry Andric       Tokens.back()->is(TT_VerilogNumberBase) &&
1322bdd1243dSDimitry Andric       FormatTok->Tok.isOneOf(tok::identifier, tok::question)) {
1323bdd1243dSDimitry Andric     // Mark the number following a base like `'h?a0` as a number.
1324bdd1243dSDimitry Andric     FormatTok->Tok.setKind(tok::numeric_constant);
1325bdd1243dSDimitry Andric   }
1326bdd1243dSDimitry Andric 
13270b57cec5SDimitry Andric   // Now FormatTok is the next non-whitespace token.
13280b57cec5SDimitry Andric 
13290b57cec5SDimitry Andric   StringRef Text = FormatTok->TokenText;
13300b57cec5SDimitry Andric   size_t FirstNewlinePos = Text.find('\n');
13310b57cec5SDimitry Andric   if (FirstNewlinePos == StringRef::npos) {
13320b57cec5SDimitry Andric     // FIXME: ColumnWidth actually depends on the start column, we need to
13330b57cec5SDimitry Andric     // take this into account when the token is moved.
13340b57cec5SDimitry Andric     FormatTok->ColumnWidth =
13350b57cec5SDimitry Andric         encoding::columnWidthWithTabs(Text, Column, Style.TabWidth, Encoding);
13360b57cec5SDimitry Andric     Column += FormatTok->ColumnWidth;
13370b57cec5SDimitry Andric   } else {
13380b57cec5SDimitry Andric     FormatTok->IsMultiline = true;
13390b57cec5SDimitry Andric     // FIXME: ColumnWidth actually depends on the start column, we need to
13400b57cec5SDimitry Andric     // take this into account when the token is moved.
13410b57cec5SDimitry Andric     FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
13420b57cec5SDimitry Andric         Text.substr(0, FirstNewlinePos), Column, Style.TabWidth, Encoding);
13430b57cec5SDimitry Andric 
13440b57cec5SDimitry Andric     // The last line of the token always starts in column 0.
13450b57cec5SDimitry Andric     // Thus, the length can be precomputed even in the presence of tabs.
13460b57cec5SDimitry Andric     FormatTok->LastLineColumnWidth = encoding::columnWidthWithTabs(
13470b57cec5SDimitry Andric         Text.substr(Text.find_last_of('\n') + 1), 0, Style.TabWidth, Encoding);
13480b57cec5SDimitry Andric     Column = FormatTok->LastLineColumnWidth;
13490b57cec5SDimitry Andric   }
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric   if (Style.isCpp()) {
135206c3fb27SDimitry Andric     auto *Identifier = FormatTok->Tok.getIdentifierInfo();
135306c3fb27SDimitry Andric     auto it = Macros.find(Identifier);
13540b57cec5SDimitry Andric     if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
13550b57cec5SDimitry Andric           Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
13560b57cec5SDimitry Andric               tok::pp_define) &&
13570b57cec5SDimitry Andric         it != Macros.end()) {
13585ffd83dbSDimitry Andric       FormatTok->setType(it->second);
1359fe6060f1SDimitry Andric       if (it->second == TT_IfMacro) {
1360fe6060f1SDimitry Andric         // The lexer token currently has type tok::kw_unknown. However, for this
1361fe6060f1SDimitry Andric         // substitution to be treated correctly in the TokenAnnotator, faking
1362fe6060f1SDimitry Andric         // the tok value seems to be needed. Not sure if there's a more elegant
1363fe6060f1SDimitry Andric         // way.
1364fe6060f1SDimitry Andric         FormatTok->Tok.setKind(tok::kw_if);
1365fe6060f1SDimitry Andric       }
13660b57cec5SDimitry Andric     } else if (FormatTok->is(tok::identifier)) {
136781ad6265SDimitry Andric       if (MacroBlockBeginRegex.match(Text))
13685ffd83dbSDimitry Andric         FormatTok->setType(TT_MacroBlockBegin);
136981ad6265SDimitry Andric       else if (MacroBlockEndRegex.match(Text))
13705ffd83dbSDimitry Andric         FormatTok->setType(TT_MacroBlockEnd);
137106c3fb27SDimitry Andric       else if (TypeNames.contains(Identifier))
137206c3fb27SDimitry Andric         FormatTok->setFinalizedType(TT_TypeName);
13730b57cec5SDimitry Andric     }
13740b57cec5SDimitry Andric   }
13750b57cec5SDimitry Andric 
13760b57cec5SDimitry Andric   return FormatTok;
13770b57cec5SDimitry Andric }
13780b57cec5SDimitry Andric 
137981ad6265SDimitry Andric bool FormatTokenLexer::readRawTokenVerilogSpecific(Token &Tok) {
138081ad6265SDimitry Andric   // In Verilog the quote is not a character literal.
138181ad6265SDimitry Andric   //
138281ad6265SDimitry Andric   // Make the backtick and double backtick identifiers to match against them
138381ad6265SDimitry Andric   // more easily.
138481ad6265SDimitry Andric   //
138581ad6265SDimitry Andric   // In Verilog an escaped identifier starts with backslash and ends with
138681ad6265SDimitry Andric   // whitespace. Unless that whitespace is an escaped newline. A backslash can
138781ad6265SDimitry Andric   // also begin an escaped newline outside of an escaped identifier. We check
138881ad6265SDimitry Andric   // for that outside of the Regex since we can't use negative lookhead
138981ad6265SDimitry Andric   // assertions. Simply changing the '*' to '+' breaks stuff as the escaped
139081ad6265SDimitry Andric   // identifier may have a length of 0 according to Section A.9.3.
139181ad6265SDimitry Andric   // FIXME: If there is an escaped newline in the middle of an escaped
139281ad6265SDimitry Andric   // identifier, allow for pasting the two lines together, But escaped
139381ad6265SDimitry Andric   // identifiers usually occur only in generated code anyway.
139481ad6265SDimitry Andric   static const llvm::Regex VerilogToken(R"re(^('|``?|\\(\\)re"
139581ad6265SDimitry Andric                                         "(\r?\n|\r)|[^[:space:]])*)");
139681ad6265SDimitry Andric 
139781ad6265SDimitry Andric   SmallVector<StringRef, 4> Matches;
139881ad6265SDimitry Andric   const char *Start = Lex->getBufferLocation();
139981ad6265SDimitry Andric   if (!VerilogToken.match(StringRef(Start, Lex->getBuffer().end() - Start),
140081ad6265SDimitry Andric                           &Matches)) {
140181ad6265SDimitry Andric     return false;
140281ad6265SDimitry Andric   }
140381ad6265SDimitry Andric   // There is a null byte at the end of the buffer, so we don't have to check
140481ad6265SDimitry Andric   // Start[1] is within the buffer.
140581ad6265SDimitry Andric   if (Start[0] == '\\' && (Start[1] == '\r' || Start[1] == '\n'))
140681ad6265SDimitry Andric     return false;
140781ad6265SDimitry Andric   size_t Len = Matches[0].size();
140881ad6265SDimitry Andric 
140981ad6265SDimitry Andric   // The kind has to be an identifier so we can match it against those defined
141081ad6265SDimitry Andric   // in Keywords. The kind has to be set before the length because the setLength
141181ad6265SDimitry Andric   // function checks that the kind is not an annotation.
141281ad6265SDimitry Andric   Tok.setKind(tok::raw_identifier);
141381ad6265SDimitry Andric   Tok.setLength(Len);
141481ad6265SDimitry Andric   Tok.setLocation(Lex->getSourceLocation(Start, Len));
141581ad6265SDimitry Andric   Tok.setRawIdentifierData(Start);
141681ad6265SDimitry Andric   Lex->seek(Lex->getCurrentBufferOffset() + Len, /*IsAtStartofline=*/false);
141781ad6265SDimitry Andric   return true;
141881ad6265SDimitry Andric }
141981ad6265SDimitry Andric 
14200b57cec5SDimitry Andric void FormatTokenLexer::readRawToken(FormatToken &Tok) {
142181ad6265SDimitry Andric   // For Verilog, first see if there is a special token, and fall back to the
142281ad6265SDimitry Andric   // normal lexer if there isn't one.
142381ad6265SDimitry Andric   if (!Style.isVerilog() || !readRawTokenVerilogSpecific(Tok.Tok))
14240b57cec5SDimitry Andric     Lex->LexFromRawLexer(Tok.Tok);
14250b57cec5SDimitry Andric   Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
14260b57cec5SDimitry Andric                             Tok.Tok.getLength());
14270b57cec5SDimitry Andric   // For formatting, treat unterminated string literals like normal string
14280b57cec5SDimitry Andric   // literals.
14290b57cec5SDimitry Andric   if (Tok.is(tok::unknown)) {
14300fca6ea1SDimitry Andric     if (Tok.TokenText.starts_with("\"")) {
14310b57cec5SDimitry Andric       Tok.Tok.setKind(tok::string_literal);
14320b57cec5SDimitry Andric       Tok.IsUnterminatedLiteral = true;
14330eae32dcSDimitry Andric     } else if (Style.isJavaScript() && Tok.TokenText == "''") {
14340b57cec5SDimitry Andric       Tok.Tok.setKind(tok::string_literal);
14350b57cec5SDimitry Andric     }
14360b57cec5SDimitry Andric   }
14370b57cec5SDimitry Andric 
14385f757f3fSDimitry Andric   if ((Style.isJavaScript() || Style.isProto()) && Tok.is(tok::char_constant))
14390b57cec5SDimitry Andric     Tok.Tok.setKind(tok::string_literal);
14400b57cec5SDimitry Andric 
144106c3fb27SDimitry Andric   if (Tok.is(tok::comment) && isClangFormatOn(Tok.TokenText))
14420b57cec5SDimitry Andric     FormattingDisabled = false;
14430b57cec5SDimitry Andric 
14440b57cec5SDimitry Andric   Tok.Finalized = FormattingDisabled;
14450b57cec5SDimitry Andric 
144606c3fb27SDimitry Andric   if (Tok.is(tok::comment) && isClangFormatOff(Tok.TokenText))
14470b57cec5SDimitry Andric     FormattingDisabled = true;
14480b57cec5SDimitry Andric }
14490b57cec5SDimitry Andric 
14500b57cec5SDimitry Andric void FormatTokenLexer::resetLexer(unsigned Offset) {
14510b57cec5SDimitry Andric   StringRef Buffer = SourceMgr.getBufferData(ID);
145281ad6265SDimitry Andric   Lex.reset(new Lexer(SourceMgr.getLocForStartOfFile(ID), LangOpts,
145381ad6265SDimitry Andric                       Buffer.begin(), Buffer.begin() + Offset, Buffer.end()));
14540b57cec5SDimitry Andric   Lex->SetKeepWhitespaceMode(true);
14550b57cec5SDimitry Andric   TrailingWhitespace = 0;
14560b57cec5SDimitry Andric }
14570b57cec5SDimitry Andric 
14580b57cec5SDimitry Andric } // namespace format
14590b57cec5SDimitry Andric } // namespace clang
1460