diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 58fe385a03c7..c0a60171f07d 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1029,7 +1029,7 @@ public: assert(Tokens.empty()); do { Tokens.push_back(getNextToken()); - maybeJoinPreviousTokens(); + tryMergePreviousTokens(); } while (Tokens.back()->Tok.isNot(tok::eof)); return Tokens; } @@ -1037,23 +1037,45 @@ public: IdentifierTable &getIdentTable() { return IdentTable; } private: - void maybeJoinPreviousTokens() { + void tryMergePreviousTokens() { + tryMerge_TMacro() || tryMergeJavaScriptIdentityOperators(); + } + + bool tryMergeJavaScriptIdentityOperators() { + if (Tokens.size() < 2) + return false; + FormatToken &First = *Tokens[Tokens.size() - 2]; + if (!First.isOneOf(tok::exclaimequal, tok::equalequal)) + return false; + FormatToken &Second = *Tokens.back(); + if (!Second.is(tok::equal)) + return false; + if (Second.WhitespaceRange.getBegin() != Second.WhitespaceRange.getEnd()) + return false; + First.TokenText = + StringRef(First.TokenText.data(), First.TokenText.size() + 1); + First.ColumnWidth += 1; + Tokens.pop_back(); + return true; + } + + bool tryMerge_TMacro() { if (Tokens.size() < 4) - return; + return false; FormatToken *Last = Tokens.back(); if (!Last->is(tok::r_paren)) - return; + return false; FormatToken *String = Tokens[Tokens.size() - 2]; if (!String->is(tok::string_literal) || String->IsMultiline) - return; + return false; if (!Tokens[Tokens.size() - 3]->is(tok::l_paren)) - return; + return false; FormatToken *Macro = Tokens[Tokens.size() - 4]; if (Macro->TokenText != "_T") - return; + return false; const char *Start = Macro->TokenText.data(); const char *End = Last->TokenText.data() + Last->TokenText.size(); @@ -1069,6 +1091,7 @@ private: Tokens.pop_back(); Tokens.pop_back(); Tokens.back() = String; + return true; } FormatToken *getNextToken() { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 7bba0362c4a0..7c3b8f69de94 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1364,10 +1364,6 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Tok.isOneOf(tok::arrowstar, tok::periodstar) || Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar)) return false; - // JavaScript identity operators ===, !==. - if (Tok.Previous->isOneOf(tok::equalequal, tok::exclaimequal) && - Tok.is(tok::equal)) - return false; if (!Style.SpaceBeforeAssignmentOperators && Tok.getPrecedence() == prec::Assignment) return false; @@ -1457,9 +1453,6 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl) return false; - // JavaScript identity operators ===, !==. - if (Left.isOneOf(tok::equalequal, tok::exclaimequal) && Right.is(tok::equal)) - return false; if (Left.Previous) { if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && Left.Previous->is(tok::kw___attribute)) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 90c74a473274..ab3303ea928b 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -7326,12 +7326,19 @@ TEST_F(FormatTest, SpacesInAngles) { verifyFormat("A>();", Spaces); } - TEST_F(FormatTest, UnderstandsJavaScript) { + verifyFormat("a == = b;"); + verifyFormat("a != = b;"); + verifyFormat("a === b;"); - verifyFormat("aaaaaaa === b;", getLLVMStyleWithColumns(10)); + verifyFormat("aaaaaaa ===\n b;", getLLVMStyleWithColumns(10)); verifyFormat("a !== b;"); - verifyFormat("aaaaaaa !== b;", getLLVMStyleWithColumns(10)); + verifyFormat("aaaaaaa !==\n b;", getLLVMStyleWithColumns(10)); + verifyFormat("if (a + b + c +\n" + " d !==\n" + " e + f + g)\n" + " q();", + getLLVMStyleWithColumns(20)); } } // end namespace tooling