diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -26,6 +26,10 @@ namespace { +static bool startsWithLoopWithInitializer(const AnnotatedLine &Line) { + return Line.startsWith(tok::kw_for) || Line.startsWith(tok::kw_while); +} + /// Returns \c true if the token can be used as an identifier in /// an Objective-C \c \@selector, \c false otherwise. /// @@ -1135,7 +1139,7 @@ else if (Contexts.back().InInheritanceList) Tok->setType(TT_InheritanceComma); else if (Contexts.back().FirstStartOfName && - (Contexts.size() == 1 || Line.startsWith(tok::kw_for))) { + (Contexts.size() == 1 || startsWithLoopWithInitializer(Line))) { Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true; Line.IsMultiVariableDeclStmt = true; } @@ -3085,12 +3089,13 @@ Right.Next->Next->is(TT_RangeBasedForLoopColon)) return getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left; - return ( - (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && - (getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left || - (Line.IsMultiVariableDeclStmt && - (Left.NestingLevel == 0 || - (Left.NestingLevel == 1 && Line.First->is(tok::kw_for))))))); + return !Left.isOneOf(TT_PointerOrReference, tok::l_paren) && + (getTokenPointerOrReferenceAlignment(Right) != + FormatStyle::PAS_Left || + (Line.IsMultiVariableDeclStmt && + (Left.NestingLevel == 0 || + (Left.NestingLevel == 1 && + startsWithLoopWithInitializer(Line))))); } if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) && (!Left.is(TT_PointerOrReference) || @@ -3127,7 +3132,15 @@ return false; if (getTokenPointerOrReferenceAlignment(Left) == FormatStyle::PAS_Right) return false; - if (Line.IsMultiVariableDeclStmt) + // FIXME: Setting IsMultiVariableDeclStmt for the whole line is error-prone, + // because it does not take into account nested scopes like lambdas. + // In multi-variable declaration statements, attach */& to the variable + // independently of the style. However, avoid doing it if we are in a nested + // scope, e.g. lambda. We still need to special-case loops with + // initializers. + if (Line.IsMultiVariableDeclStmt && + (Left.NestingLevel == Line.First->NestingLevel || + startsWithLoopWithInitializer(Line))) return false; return Left.Previous && !Left.Previous->isOneOf( tok::l_paren, tok::coloncolon, tok::l_square); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -2001,6 +2001,10 @@ verifyFormat("for (int x = 0; int &c : {1, 2, 3})", Style); verifyFormat("for (f(); auto &c : {1, 2, 3})", Style); verifyFormat("for (f(); int &c : {1, 2, 3})", Style); + verifyFormat( + "function res1 = [](int &a) { return 0000000000000; },\n" + " res2 = [](int &a) { return 0000000000000; };", + Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int *c;\n" @@ -2038,6 +2042,10 @@ verifyFormat("for (int x = 0; int& c : {1, 2, 3})", Style); verifyFormat("for (f(); auto& c : {1, 2, 3})", Style); verifyFormat("for (f(); int& c : {1, 2, 3})", Style); + verifyFormat( + "function res1 = [](int& a) { return 0000000000000; },\n" + " res2 = [](int& a) { return 0000000000000; };", + Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int* c;\n" @@ -2091,6 +2099,10 @@ verifyFormat("for (int x = 0; int & c : {1, 2, 3})", Style); verifyFormat("for (f(); auto & c : {1, 2, 3})", Style); verifyFormat("for (f(); int & c : {1, 2, 3})", Style); + verifyFormat( + "function res1 = [](int & a) { return 0000000000000; },\n" + " res2 = [](int & a) { return 0000000000000; };", + Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int* c;\n" @@ -8366,6 +8378,7 @@ Style); verifyFormat("vector a, b;", Style); verifyFormat("for (int *p, *q; p != q; p = p->next) {\n}", Style); + verifyFormat("while (int *p, *q; p != q) {\n p = p->next;\n}", Style); } TEST_F(FormatTest, ConditionalExpressionsInBrackets) {