Index: clang/lib/Format/UnwrappedLineParser.h =================================================================== --- clang/lib/Format/UnwrappedLineParser.h +++ clang/lib/Format/UnwrappedLineParser.h @@ -185,6 +185,10 @@ bool isOnNewLine(const FormatToken &FormatTok); + // Peek to the next token without impacting on the current token + // position. Returns null if no more tokens. + FormatToken *peekNextToken() const; + // Compute hash of the current preprocessor branch. // This is used to identify the different branches, and thus track if block // open and close in the same branch. Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -994,6 +994,12 @@ Keywords.kw_import, tok::kw_export); } +FormatToken *UnwrappedLineParser::peekNextToken() const { + unsigned TokenPosition = Tokens->getPosition(); + return (++TokenPosition < AllTokens.size()) ? AllTokens[TokenPosition] + : nullptr; +} + // readTokenWithJavaScriptASI reads the next token and terminates the current // line if JavaScript Automatic Semicolon Insertion must // happen between the current token and the next token. @@ -1006,6 +1012,20 @@ readToken(); FormatToken *Next = FormatTok; + if (Previous->isOneOf(tok::kw_return, tok::kw_break, tok::kw_continue, + Keywords.kw_yield)) { + if (Next->isOneOf(Keywords.kw_let, tok::kw_const, Keywords.kw_var)) { + return addUnwrappedLine(); + } + // Look for return xxx = val; but not return xxx(); + if (Next->is(tok::identifier)) { + FormatToken *PeekNext = peekNextToken(); + if (PeekNext && PeekNext->is(tok::equal)) { + return addUnwrappedLine(); + } + } + } + bool IsOnSameLine = CommentsBeforeNextToken.empty() ? Next->NewlinesBefore == 0 Index: clang/unittests/Format/FormatTestJS.cpp =================================================================== --- clang/unittests/Format/FormatTestJS.cpp +++ clang/unittests/Format/FormatTestJS.cpp @@ -2604,5 +2604,58 @@ "}\n"); } +TEST_F(FormatTestJS, ASIAfterReturn) { + verifyFormat("if (true) return\n" + "const v = 42"); + verifyFormat("if (true) return\n" + "let v = 42"); + verifyFormat("if (true) return\n" + "var v = 42"); + verifyFormat("if (true) break\n" + "let v = 42"); + verifyFormat("if (true) break\n" + "const v = 42"); + verifyFormat("if (true) break\n" + "v = 42"); + verifyFormat("if (true) continue\n" + "let v = 42"); + verifyFormat("if (true) continue\n" + "var v = 42"); + verifyFormat("if (true) continue\n" + "const v = 42"); + verifyFormat("if (true) yield\n" + "let v = 42"); + verifyFormat("if (true) yield\n" + "var v = 42"); + verifyFormat("if (true) yield\n" + "const v = 42"); + + verifyFormat("if (true) break\n" + "var v = 42"); + verifyFormat("if (true) return\n" + "v = 42"); + verifyFormat("if (true) continue\n" + "v = 42"); + verifyFormat("if (true) yield\n" + "v = 42"); + + verifyFormat("void foo() {\n" + " if (true) return\n" + " v = 42\n" + "}"); + verifyFormat("void foo() {\n" + " if (true) return\n" + " const v = 42\n" + "}"); + verifyFormat("void foo() {\n" + " if (true) return\n" + " let v = 42\n" + "}"); + verifyFormat("void foo() {\n" + " if (true) return\n" + " var v = 42\n" + "}"); +} + } // namespace format } // end namespace clang