diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/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 && diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp --- a/clang/lib/Format/FormatToken.cpp +++ b/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) {} 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 @@ -3021,8 +3021,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 && @@ -3041,18 +3047,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 && 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 @@ -1924,6 +1924,22 @@ 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); + verifyFormat("for (int a = 0, b = 0; const auto &c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b = 0; const int &c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b = 0; const Foo &c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const auto &c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const int &c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo &c : {1, 2, 3})", Style); + verifyFormat("for (auto x = 0; auto &c : {1, 2, 3})", Style); + verifyFormat("for (auto x = 0; int &c : {1, 2, 3})", Style); + verifyFormat("for (int x = 0; auto &c : {1, 2, 3})", Style); + 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); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int *c;\n" @@ -1943,6 +1959,24 @@ 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); + verifyFormat("for (int a = 0, b = 0; const auto& c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b = 0; const int& c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b = 0; const Foo& c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b = 0; const Foo* c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const auto& c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const int& c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo& c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo* c : {1, 2, 3})", Style); + verifyFormat("for (auto x = 0; auto& c : {1, 2, 3})", Style); + verifyFormat("for (auto x = 0; int& c : {1, 2, 3})", Style); + verifyFormat("for (int x = 0; auto& c : {1, 2, 3})", Style); + 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); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int* c;\n" @@ -1961,6 +1995,9 @@ 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); + verifyFormat("for (int a = 0, b = 0; const Foo *c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo *c : {1, 2, 3})", Style); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int *c;\n" @@ -1979,6 +2016,20 @@ 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); + verifyFormat("for (int a = 0, b++; const auto & c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const int & c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo & c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo* c : {1, 2, 3})", Style); + verifyFormat("for (auto x = 0; auto & c : {1, 2, 3})", Style); + verifyFormat("for (auto x = 0; int & c : {1, 2, 3})", Style); + verifyFormat("for (int x = 0; auto & c : {1, 2, 3})", Style); + 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); Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive; verifyFormat("Const unsigned int* c;\n" @@ -1997,6 +2048,9 @@ 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); + verifyFormat("for (int a = 0, b = 0; const Foo * c : {1, 2, 3})", Style); + verifyFormat("for (int a = 0, b++; const Foo * c : {1, 2, 3})", Style); // FIXME: we don't handle this yet, so output may be arbitrary until it's // specifically handled