Author: mprobst Date: Tue May 9 15:04:09 2017 New Revision: 302580 URL: http://llvm.org/viewvc/llvm-project?rev=302580&view=rev Log: clang-format: [JS] Don't indent JavaScript IIFEs.
Because IIFEs[1] are often used like an anonymous namespace around large sections of JavaScript code, it's useful not to indent to them (which effectively reduces the column limit by the indent amount needlessly). It's also common for developers to wrap these around entire files or libraries. When adopting clang-format, changing the indent entire file can reduce the usefulness of the blame annotations. Patch by danbeam, thanks! Differential Revision: https://reviews.llvm.org/D32989 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=302580&r1=302579&r2=302580&view=diff ============================================================================== --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Tue May 9 15:04:09 2017 @@ -476,6 +476,24 @@ static bool isGoogScope(const UnwrappedL return I->Tok->is(tok::l_paren); } +static bool isIIFE(const UnwrappedLine &Line, + const AdditionalKeywords &Keywords) { + // 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() { ... })() + if (Line.Tokens.size() < 3) + 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; + return I->Tok->is(tok::l_paren); +} + static bool ShouldBreakBeforeBrace(const FormatStyle &Style, const FormatToken &InitialToken) { if (InitialToken.is(tok::kw_namespace)) @@ -493,15 +511,16 @@ void UnwrappedLineParser::parseChildBloc FormatTok->BlockKind = BK_Block; nextToken(); { - bool GoogScope = - Style.Language == FormatStyle::LK_JavaScript && isGoogScope(*Line); + bool SkipIndent = + (Style.Language == FormatStyle::LK_JavaScript && + (isGoogScope(*Line) || isIIFE(*Line, Keywords))); 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(); } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=302580&r1=302579&r2=302580&view=diff ============================================================================== --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue May 9 15:04:09 2017 @@ -367,6 +367,25 @@ TEST_F(FormatTestJS, GoogScopes) { "});"); } +TEST_F(FormatTestJS, IIFEs) { + // Internal calling parens; no semi. + verifyFormat("(function() {\n" + "var a = 1;\n" + "}())"); + // External calling parens; no semi. + verifyFormat("(function() {\n" + "var b = 2;\n" + "})()"); + // Internal calling parens; with semi. + verifyFormat("(function() {\n" + "var c = 3;\n" + "}());"); + // External calling parens; with semi. + verifyFormat("(function() {\n" + "var d = 4;\n" + "})();"); +} + TEST_F(FormatTestJS, GoogModules) { verifyFormat("goog.module('this.is.really.absurdly.long');", getGoogleJSStyleWithColumns(40)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits