Author: Marek Kurdej Date: 2021-04-29T08:58:50+02:00 New Revision: 9363aa90bfe6f73df105799abc55bb74d4f186bf
URL: https://github.com/llvm/llvm-project/commit/9363aa90bfe6f73df105799abc55bb74d4f186bf DIFF: https://github.com/llvm/llvm-project/commit/9363aa90bfe6f73df105799abc55bb74d4f186bf.diff LOG: [clang-format] Add `SpacesInAngles: Leave` option to keep spacing inside angle brackets as is. A need for such an option came up in a few libc++ reviews. That's because libc++ has both code in C++03 and newer standards. Currently, it uses `Standard: C++03` setting for clang-format, but this breaks e.g. u8"string" literals. Also, angle brackets are the only place where C++03-specific formatting needs to be applied. Reviewed By: MyDeveloperDay, HazardyKnusperkeks Differential Revision: https://reviews.llvm.org/D101344 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Format/Format.h clang/lib/Format/Format.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTest.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a11d60cadb04..d178097ac8e6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -236,6 +236,9 @@ clang-format on the formatted new lines and not on the new lines in the file. (Fixes https://llvm.org/PR41870.) +- Option ``SpacesInAngles`` has been improved, it now accepts ``Leave`` value + that allows to keep spaces where they are already present. + libclang -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 98d2f16e2eef..6c49497a5699 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2994,14 +2994,27 @@ struct FormatStyle { /// \endcode unsigned SpacesBeforeTrailingComments; - /// If ``true``, spaces will be inserted after ``<`` and before ``>`` - /// in template argument lists. - /// \code - /// true: false: - /// static_cast< int >(arg); vs. static_cast<int>(arg); - /// std::function< void(int) > fct; std::function<void(int)> fct; - /// \endcode - bool SpacesInAngles; + /// Styles for adding spacing after ``<`` and before ``>` + /// in template argument lists. + enum SpacesInAnglesStyle : unsigned char { + /// Remove spaces after ``<`` and before ``>``. + /// \code + /// static_cast<int>(arg); + /// std::function<void(int)> fct; + /// \endcode + SIAS_Never, + /// Add spaces after ``<`` and before ``>``. + /// \code + /// static_cast< int >(arg); + /// std::function< void(int) > fct; + /// \endcode + SIAS_Always, + /// Keep a single space after ``<`` and before ``>`` if any spaces were + /// present. Option ``Standard: Cpp03`` takes precedence. + SIAS_Leave + }; + /// The SpacesInAnglesStyle to use for template argument lists. + SpacesInAnglesStyle SpacesInAngles; /// If ``true``, spaces will be inserted around if/for/switch/while /// conditions. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b6aa445bb9f4..7a80af24ab48 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -446,6 +446,18 @@ struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> { + static void enumeration(IO &IO, FormatStyle::SpacesInAnglesStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SIAS_Never); + IO.enumCase(Value, "Always", FormatStyle::SIAS_Always); + IO.enumCase(Value, "Leave", FormatStyle::SIAS_Leave); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::SIAS_Never); + IO.enumCase(Value, "true", FormatStyle::SIAS_Always); + } +}; + template <> struct MappingTraits<FormatStyle> { static void mapping(IO &IO, FormatStyle &Style) { // When reading, read the language first, we need it for getPredefinedStyle. @@ -1046,7 +1058,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeCpp11BracedList = false; LLVMStyle.SpaceBeforeSquareBrackets = false; LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; - LLVMStyle.SpacesInAngles = false; + LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never; LLVMStyle.SpacesInConditionalStatement = false; LLVMStyle.PenaltyBreakAssignment = prec::Assignment; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index fd0116714d9f..f20640a1343d 100755 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3094,6 +3094,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; + auto HasExistingWhitespace = [&Whitespace = Right.WhitespaceRange]() { + return Whitespace.getBegin() != Whitespace.getEnd(); + }; if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. if (Style.isCpp()) { @@ -3126,7 +3129,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // Preserve the existence of a space before a percent for cases like 0x%04x // and "%d %d" if (Left.is(tok::numeric_constant) && Right.is(tok::percent)) - return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin(); + return HasExistingWhitespace(); } else if (Style.isCSharp()) { // Require spaces around '{' and before '}' unless they appear in // interpolated strings. Interpolated strings are merged into a single token @@ -3319,7 +3322,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } if (Left.is(TT_ImplicitStringLiteral)) - return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); + return HasExistingWhitespace(); if (Line.Type == LT_ObjCMethodDecl) { if (Left.is(TT_ObjCMethodSpecifier)) return true; @@ -3406,12 +3409,22 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return Style.SpaceAfterCStyleCast || Right.isOneOf(TT_BinaryOperator, TT_SelectorName); + auto ShouldAddSpacesInAngles = [&Style = this->Style, + &HasExistingWhitespace]() { + if (Style.SpacesInAngles == FormatStyle::SIAS_Always) + return true; + if (Style.SpacesInAngles == FormatStyle::SIAS_Leave) + return HasExistingWhitespace(); + return false; + }; + if (Left.is(tok::greater) && Right.is(tok::greater)) { if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral))) return !Style.Cpp11BracedListStyle; return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && - (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles); + ((Style.Standard < FormatStyle::LS_Cpp11) || + ShouldAddSpacesInAngles()); } if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) || Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || @@ -3427,18 +3440,19 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // Generally don't remove existing spaces between an identifier and "::". // The identifier might actually be a macro name such as ALWAYS_INLINE. If // this turns out to be too lenient, add analysis of the identifier itself. - return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); + return HasExistingWhitespace(); if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren)) // Put a space between < and :: in vector< ::std::string > return (Left.is(TT_TemplateOpener) && - (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles)) || + ((Style.Standard < FormatStyle::LS_Cpp11) || + ShouldAddSpacesInAngles())) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, tok::kw___super, TT_TemplateOpener, TT_TemplateCloser)) || (Left.is(tok::l_paren) && Style.SpacesInParentheses); if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser))) - return Style.SpacesInAngles; + return ShouldAddSpacesInAngles(); // Space before TT_StructuredBindingLSquare. if (Right.is(TT_StructuredBindingLSquare)) return !Left.isOneOf(tok::amp, tok::ampamp) || diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 8b626f43e0e8..03364ff9dd98 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -10286,7 +10286,7 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) { verifyFormat("f({}, {{}, {}}, MyMap[{k, v}]);", SpaceBeforeBrace); FormatStyle SpaceBetweenBraces = getLLVMStyle(); - SpaceBetweenBraces.SpacesInAngles = true; + SpaceBetweenBraces.SpacesInAngles = FormatStyle::SIAS_Always; SpaceBetweenBraces.SpacesInParentheses = true; SpaceBetweenBraces.SpacesInSquareBrackets = true; verifyFormat("vector< int > x{ 1, 2, 3, 4 };", SpaceBetweenBraces); @@ -16308,7 +16308,6 @@ TEST_F(FormatTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(SortUsingDeclarations); CHECK_PARSE_BOOL(SpacesInParentheses); CHECK_PARSE_BOOL(SpacesInSquareBrackets); - CHECK_PARSE_BOOL(SpacesInAngles); CHECK_PARSE_BOOL(SpacesInConditionalStatement); CHECK_PARSE_BOOL(SpaceInEmptyBlock); CHECK_PARSE_BOOL(SpaceInEmptyParentheses); @@ -16865,6 +16864,15 @@ TEST_F(FormatTest, ParsesConfiguration) { " Maximum: 1", SpacesInLineCommentPrefix.Maximum, 1u); EXPECT_EQ(Style.SpacesInLineCommentPrefix.Minimum, 1u); + + Style.SpacesInAngles = FormatStyle::SIAS_Always; + CHECK_PARSE("SpacesInAngles: Never", SpacesInAngles, FormatStyle::SIAS_Never); + CHECK_PARSE("SpacesInAngles: Always", SpacesInAngles, + FormatStyle::SIAS_Always); + CHECK_PARSE("SpacesInAngles: Leave", SpacesInAngles, FormatStyle::SIAS_Leave); + // For backward compatibility: + CHECK_PARSE("SpacesInAngles: false", SpacesInAngles, FormatStyle::SIAS_Never); + CHECK_PARSE("SpacesInAngles: true", SpacesInAngles, FormatStyle::SIAS_Always); } TEST_F(FormatTest, ParsesConfigurationWithLanguages) { @@ -18442,7 +18450,7 @@ TEST_F(FormatTest, WrappedClosingParenthesisIndent) { TEST_F(FormatTest, SpacesInAngles) { FormatStyle Spaces = getLLVMStyle(); - Spaces.SpacesInAngles = true; + Spaces.SpacesInAngles = FormatStyle::SIAS_Always; verifyFormat("vector< ::std::string > x1;", Spaces); verifyFormat("Foo< int, Bar > x2;", Spaces); @@ -18458,23 +18466,48 @@ TEST_F(FormatTest, SpacesInAngles) { Spaces); Spaces.Standard = FormatStyle::LS_Cpp03; - Spaces.SpacesInAngles = true; + Spaces.SpacesInAngles = FormatStyle::SIAS_Always; verifyFormat("A< A< int > >();", Spaces); - Spaces.SpacesInAngles = false; + Spaces.SpacesInAngles = FormatStyle::SIAS_Never; + verifyFormat("A<A<int> >();", Spaces); + + Spaces.SpacesInAngles = FormatStyle::SIAS_Leave; + verifyFormat("vector< ::std::string> x4;", "vector<::std::string> x4;", + Spaces); + verifyFormat("vector< ::std::string > x4;", "vector<::std::string > x4;", + Spaces); + verifyFormat("A<A<int> >();", Spaces); + verifyFormat("A<A<int> >();", "A<A<int>>();", Spaces); + verifyFormat("A< A< int > >();", Spaces); Spaces.Standard = FormatStyle::LS_Cpp11; - Spaces.SpacesInAngles = true; + Spaces.SpacesInAngles = FormatStyle::SIAS_Always; verifyFormat("A< A< int > >();", Spaces); - Spaces.SpacesInAngles = false; + Spaces.SpacesInAngles = FormatStyle::SIAS_Never; verifyFormat("vector<::std::string> x4;", Spaces); verifyFormat("vector<int> x5;", Spaces); verifyFormat("Foo<int, Bar> x6;", Spaces); verifyFormat("Foo<::int, ::Bar> x7;", Spaces); verifyFormat("A<A<int>>();", Spaces); + + Spaces.SpacesInAngles = FormatStyle::SIAS_Leave; + verifyFormat("vector<::std::string> x4;", Spaces); + verifyFormat("vector< ::std::string > x4;", Spaces); + verifyFormat("vector<int> x5;", Spaces); + verifyFormat("vector< int > x5;", Spaces); + verifyFormat("Foo<int, Bar> x6;", Spaces); + verifyFormat("Foo< int, Bar > x6;", Spaces); + verifyFormat("Foo<::int, ::Bar> x7;", Spaces); + verifyFormat("Foo< ::int, ::Bar > x7;", Spaces); + + verifyFormat("A<A<int>>();", Spaces); + verifyFormat("A< A< int > >();", Spaces); + verifyFormat("A<A<int > >();", Spaces); + verifyFormat("A< A< int>>();", Spaces); } TEST_F(FormatTest, SpaceAfterTemplateKeyword) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits