[clang] 9363aa9 - [clang-format] Add `SpacesInAngles: Leave` option to keep spacing inside angle brackets as is.
Marek Kurdej via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 28 23:58:55 PDT 2021
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) {
More information about the cfe-commits
mailing list