Index: clang/lib/Format/FormatToken.h =================================================================== --- clang/lib/Format/FormatToken.h +++ clang/lib/Format/FormatToken.h @@ -521,7 +521,9 @@ } /// Determine whether the token is a simple-type-specifier. - bool isSimpleTypeSpecifier() const; + LLVM_NODISCARD bool isSimpleTypeSpecifier() const; + + LLVM_NODISCARD bool isTypeOrIdentifier() const; bool isObjCAccessSpecifier() const { return is(tok::at) && Next && Index: clang/lib/Format/FormatToken.cpp =================================================================== --- clang/lib/Format/FormatToken.cpp +++ clang/lib/Format/FormatToken.cpp @@ -70,6 +70,10 @@ } } +bool FormatToken::isTypeOrIdentifier() const { + return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier); +} + TokenRole::~TokenRole() {} void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {} Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3024,8 +3024,14 @@ Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) && (Left.is(TT_AttributeParen) || Left.canBePointerOrReferenceQualifier())) return true; + if (Left.Tok.isLiteral()) + return true; + // for (auto a = 0, b = 0; const auto & c : {1, 2, 3}) + if (Left.isTypeOrIdentifier() && Right.Next && Right.Next->Next && + Right.Next->Next->is(TT_RangeBasedForLoopColon)) + return getTokenPointerOrReferenceAlignment(Right) != + FormatStyle::PAS_Left; return ( - Left.Tok.isLiteral() || (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && (getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left || (Line.IsMultiVariableDeclStmt && @@ -3044,18 +3050,32 @@ Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) && Right.canBePointerOrReferenceQualifier()) return true; - return Right.Tok.isLiteral() || Right.is(TT_BlockComment) || - (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) && - !Right.is(TT_StartOfName)) || - (Right.is(tok::l_brace) && Right.is(BK_Block)) || - (!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare, - tok::l_paren) && - (getTokenPointerOrReferenceAlignment(Left) != - FormatStyle::PAS_Right && - !Line.IsMultiVariableDeclStmt) && - Left.Previous && - !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, - tok::l_square)); + // & 1 + if (Right.Tok.isLiteral()) + return true; + // & /* comment + if (Right.is(TT_BlockComment)) + return true; + // foo() -> const Bar * override/final + if (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) && + !Right.is(TT_StartOfName)) + return true; + // & { + if (Right.is(tok::l_brace) && Right.is(BK_Block)) + return true; + // for (auto a = 0, b = 0; const auto& c : {1, 2, 3}) + if (Left.Previous && Left.Previous->isTypeOrIdentifier() && Right.Next && + Right.Next->is(TT_RangeBasedForLoopColon)) + return getTokenPointerOrReferenceAlignment(Left) != + FormatStyle::PAS_Right; + return !Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare, + tok::l_paren) && + (getTokenPointerOrReferenceAlignment(Left) != + FormatStyle::PAS_Right && + !Line.IsMultiVariableDeclStmt) && + Left.Previous && + !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, + tok::l_square); } // Ensure right pointer alignment with ellipsis e.g. int *...P if (Left.is(tok::ellipsis) && Left.Previous && Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -1924,6 +1924,10 @@ verifyFormat("int *a = f1();", Style); verifyFormat("int &b = f2();", Style); verifyFormat("int &&c = f3();", Style); + verifyFormat("for (auto a = 0, b = 0; const auto &c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const int &c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo &c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo *c : {1, 2, 3})", Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int *c;\n" @@ -1943,6 +1947,10 @@ verifyFormat("int* a = f1();", Style); verifyFormat("int& b = f2();", Style); verifyFormat("int&& c = f3();", Style); + verifyFormat("for (auto a = 0, b = 0; const auto& c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const int& c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo& c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo* c : {1, 2, 3})", Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int* c;\n" @@ -1961,6 +1969,7 @@ verifyFormat("int *a = f1();", Style); verifyFormat("int& b = f2();", Style); verifyFormat("int&& c = f3();", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo *c : {1, 2, 3})", Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int *c;\n" @@ -1979,6 +1988,10 @@ verifyFormat("int* a = f1();", Style); verifyFormat("int & b = f2();", Style); verifyFormat("int && c = f3();", Style); + verifyFormat("for (auto a = 0, b = 0; const auto & c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const int & c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo & c : {1, 2, 3})", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo* c : {1, 2, 3})", Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int* c;\n" @@ -1997,6 +2010,7 @@ verifyFormat("int * a = f1();", Style); verifyFormat("int &b = f2();", Style); verifyFormat("int &&c = f3();", Style); + verifyFormat("for (auto a = 0, b = 0; const Foo * c : {1, 2, 3})", Style); // FIXME: we don't handle this yet, so output may be arbitrary until it's // specifically handled