Index: lib/Format/UnwrappedLineParser.h =================================================================== --- lib/Format/UnwrappedLineParser.h +++ lib/Format/UnwrappedLineParser.h @@ -125,6 +125,7 @@ void nextToken(); const FormatToken *getPreviousToken(); void readToken(); + bool isIIFE() const; // Decides which comment tokens should be added to the current line and which // should be added as comments before the next token. Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -493,15 +493,16 @@ FormatTok->BlockKind = BK_Block; nextToken(); { - bool GoogScope = - Style.Language == FormatStyle::LK_JavaScript && isGoogScope(*Line); + bool SkipIndent = + Style.Language == FormatStyle::LK_JavaScript && + (isGoogScope(*Line) || isIIFE()); ScopedLineState LineState(*this); ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, /*MustBeDeclaration=*/false); - Line->Level += GoogScope ? 0 : 1; + Line->Level += SkipIndent ? 0 : 1; parseLevel(/*HasOpeningBrace=*/true); flushComments(isOnNewLine(*FormatTok)); - Line->Level -= GoogScope ? 0 : 1; + Line->Level -= SkipIndent ? 0 : 1; } nextToken(); } @@ -2342,5 +2343,30 @@ } } +bool UnwrappedLineParser::isIIFE() const { + // Look for the start of an immediately invoked anonymous function. + // https://en.wikipedia.org/wiki/Immediately-invoked_function_expression + // This is commonly done in JavaScript to create a new, anonymous scope. + // Example: (function() { ... })() + // FIXME: check for the end invocation or alternate ways to start function + // expressions? + if (Line->Tokens.size() < 5) + return false; + auto I = Line->Tokens.begin(); + if (I->Tok->isNot(tok::l_paren)) + return false; + ++I; + if (I->Tok->isNot(Keywords.kw_function)) + return false; + ++I; + if (I->Tok->isNot(tok::l_paren)) + return false; + ++I; + if (I->Tok->isNot(tok::r_paren)) + return false; + ++I; + return I->Tok->is(tok::l_brace); +} + } // end namespace format } // end namespace clang Index: unittests/Format/FormatTestJS.cpp =================================================================== --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -367,6 +367,21 @@ "});"); } +TEST_F(FormatTestJS, IIFE) { + verifyFormat("(function() {\n" + "var a = 1;\n" + "}())"); + verifyFormat("(function() {\n" + "var b = 2;\n" + "})()"); + verifyFormat("(function() {\n" + "var c = 3;\n" + "})();"); + verifyFormat("(function() {\n" + "var d = 4;\n" + "}());"); +} + TEST_F(FormatTestJS, GoogModules) { verifyFormat("goog.module('this.is.really.absurdly.long');", getGoogleJSStyleWithColumns(40));