Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -855,6 +855,7 @@ moveStatePastFakeLParens(State, Newline); moveStatePastScopeCloser(State); + if (Current.is(TT_TemplateString) && Current.opensScope()) State.Stack.back().LastSpace = (Current.IsMultiline ? Current.LastLineColumnWidth @@ -865,6 +866,20 @@ moveStatePastScopeOpener(State, Newline); moveStatePastFakeRParens(State); + if (Style.Language == FormatStyle::LK_JavaScript && + Current.is(tok::l_paren) && Current.MatchingParen && + Current.MatchingParen->Previous && + Current.MatchingParen->Previous->is(tok::comma)) { + // JavaScript param lists allow trailing commas, which trigger wrapping + // parameters one-per-line. + // TODO(martinprobst): this only causes one-per-line formatting only if + // lines overflow. + State.Stack.back().AvoidBinPacking = true; + State.Stack.back().BreakBeforeParameter = true; + // TODO(martinprobst): the line below triggers "Could not find a solution". + // Current.MatchingParen->MustBreakBefore = true; + } + if (Current.is(TT_ObjCStringLiteral) && State.StartOfStringLiteral == 0) State.StartOfStringLiteral = State.Column + 1; else if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) Index: unittests/Format/FormatTestJS.cpp =================================================================== --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -521,6 +521,18 @@ "}\n"); } +TEST_F(FormatTestJS, FunctionParametersTrailingComma) { + verifyFormat("function trailingComma(\n" + " parameter1,\n" + " parameter2,\n" + " ) {\n" + " a(); //\n" + "}\n", + "function trailingComma(parameter1, parameter2,) {\n" + " a(); //\n" + "}\n"); +} + TEST_F(FormatTestJS, ArrayLiterals) { verifyFormat("var aaaaa: List =\n" " [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];");