[clang] a08fa8a - [Clang-Format] Add ReferenceAlignment directive
Björn Schäpers via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 24 13:27:57 PDT 2021
Author: Seraphime Kirkovski
Date: 2021-06-24T22:27:45+02:00
New Revision: a08fa8a508199c6463f5ee5d617e2f360f718067
URL: https://github.com/llvm/llvm-project/commit/a08fa8a508199c6463f5ee5d617e2f360f718067
DIFF: https://github.com/llvm/llvm-project/commit/a08fa8a508199c6463f5ee5d617e2f360f718067.diff
LOG: [Clang-Format] Add ReferenceAlignment directive
This introduces ReferenceAlignment style option modeled around
PointerAlignment.
Style implementors can specify Left, Right, Middle or Pointer to
follow whatever the PointerAlignment option specifies.
Differential Revision: https://reviews.llvm.org/D104096
Added:
Modified:
clang/docs/ClangFormatStyleOptions.rst
clang/include/clang/Format/Format.h
clang/lib/Format/Format.cpp
clang/lib/Format/TokenAnnotator.cpp
clang/lib/Format/TokenAnnotator.h
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 21028b1f607ad..fd19cdfc3e600 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3236,6 +3236,38 @@ the configuration (without a prefix: ``Auto``).
BasedOnStyle: llvm
CanonicalDelimiter: 'cc'
+**ReferenceAlignment** (``ReferenceAlignmentStyle``)
+ Reference alignment style (overrides ``PointerAlignment`` for
+ references).
+
+ Possible values:
+
+ * ``RAS_Pointer`` (in configuration: ``Pointer``)
+ Align reference like ``PointerAlignment``.
+
+ * ``RAS_Left`` (in configuration: ``Left``)
+ Align reference to the left.
+
+ .. code-block:: c++
+
+ int& a;
+
+ * ``RAS_Right`` (in configuration: ``Right``)
+ Align reference to the right.
+
+ .. code-block:: c++
+
+ int &a;
+
+ * ``RAS_Middle`` (in configuration: ``Middle``)
+ Align reference in the middle.
+
+ .. code-block:: c++
+
+ int & a;
+
+
+
**ReflowComments** (``bool``)
If ``true``, clang-format will attempt to re-flow comments.
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 06aeacc9785cc..515ac42d42f5a 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2725,7 +2725,7 @@ struct FormatStyle {
/// (counted relative to leading non-whitespace column).
unsigned PenaltyIndentedWhitespace;
- /// The ``&`` and ``*`` alignment style.
+ /// The ``&``, ``&&`` and ``*`` alignment style.
enum PointerAlignmentStyle : unsigned char {
/// Align pointer to the left.
/// \code
@@ -2820,6 +2820,31 @@ struct FormatStyle {
/// \endcode
std::vector<RawStringFormat> RawStringFormats;
+ /// \brief The ``&`` and ``&&`` alignment style.
+ enum ReferenceAlignmentStyle {
+ /// Align reference like ``PointerAlignment``.
+ RAS_Pointer,
+ /// Align reference to the left.
+ /// \code
+ /// int& a;
+ /// \endcode
+ RAS_Left,
+ /// Align reference to the right.
+ /// \code
+ /// int &a;
+ /// \endcode
+ RAS_Right,
+ /// Align reference in the middle.
+ /// \code
+ /// int & a;
+ /// \endcode
+ RAS_Middle
+ };
+
+ /// \brief Reference alignment style (overrides ``PointerAlignment`` for
+ /// references).
+ ReferenceAlignmentStyle ReferenceAlignment;
+
// clang-format off
/// If ``true``, clang-format will attempt to re-flow comments.
/// \code
@@ -3455,6 +3480,7 @@ struct FormatStyle {
R.PenaltyBreakTemplateDeclaration &&
PointerAlignment == R.PointerAlignment &&
RawStringFormats == R.RawStringFormats &&
+ ReferenceAlignment == R.ReferenceAlignment &&
ShortNamespaceLines == R.ShortNamespaceLines &&
SortIncludes == R.SortIncludes &&
SortJavaStaticImport == R.SortJavaStaticImport &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index bfd4d8b5af503..71b7820c2b1c6 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -417,6 +417,16 @@ struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) {
+ IO.enumCase(Value, "Pointer", FormatStyle::RAS_Pointer);
+ IO.enumCase(Value, "Middle", FormatStyle::RAS_Middle);
+ IO.enumCase(Value, "Left", FormatStyle::RAS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::RAS_Right);
+ }
+};
+
template <>
struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
static void enumeration(IO &IO,
@@ -692,6 +702,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("PointerAlignment", Style.PointerAlignment);
IO.mapOptional("PPIndentWidth", Style.PPIndentWidth);
IO.mapOptional("RawStringFormats", Style.RawStringFormats);
+ IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment);
IO.mapOptional("ReflowComments", Style.ReflowComments);
IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines);
IO.mapOptional("SortIncludes", Style.SortIncludes);
@@ -1065,6 +1076,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ObjCSpaceAfterProperty = false;
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
+ LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
LLVMStyle.ShortNamespaceLines = 1;
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Latest;
@@ -1755,10 +1767,12 @@ class Formatter : public TokenAnalyzer {
Tok = Tok->Next;
}
}
- if (Style.DerivePointerAlignment)
+ if (Style.DerivePointerAlignment) {
Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
? FormatStyle::PAS_Left
: FormatStyle::PAS_Right;
+ Style.ReferenceAlignment = FormatStyle::RAS_Pointer;
+ }
if (Style.Standard == FormatStyle::LS_Auto)
Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
? FormatStyle::LS_Latest
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 92fb1b14056ab..bfa49de7d74f7 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2988,16 +2988,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) &&
(Left.is(TT_AttributeParen) || Left.canBePointerOrReferenceQualifier()))
return true;
- return (Left.Tok.isLiteral() ||
- (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
- (Style.PointerAlignment != FormatStyle::PAS_Left ||
- (Line.IsMultiVariableDeclStmt &&
- (Left.NestingLevel == 0 ||
- (Left.NestingLevel == 1 && Line.First->is(tok::kw_for)))))));
+ return (
+ Left.Tok.isLiteral() ||
+ (!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)))))));
}
if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
(!Left.is(TT_PointerOrReference) ||
- (Style.PointerAlignment != FormatStyle::PAS_Right &&
+ (getTokenPointerOrReferenceAlignment(Left) != FormatStyle::PAS_Right &&
!Line.IsMultiVariableDeclStmt)))
return true;
if (Left.is(TT_PointerOrReference)) {
@@ -3013,7 +3014,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Right.is(tok::l_brace) && Right.is(BK_Block)) ||
(!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare,
tok::l_paren) &&
- (Style.PointerAlignment != FormatStyle::PAS_Right &&
+ (getTokenPointerOrReferenceAlignment(Left) !=
+ FormatStyle::PAS_Right &&
!Line.IsMultiVariableDeclStmt) &&
Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon,
@@ -3182,7 +3184,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
// Match const and volatile ref-qualifiers without any additional
// qualifiers such as
// void Fn() const &;
- return Style.PointerAlignment != FormatStyle::PAS_Left;
+ return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left;
return true;
}
@@ -3534,11 +3536,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// Space before TT_StructuredBindingLSquare.
if (Right.is(TT_StructuredBindingLSquare))
return !Left.isOneOf(tok::amp, tok::ampamp) ||
- Style.PointerAlignment != FormatStyle::PAS_Right;
+ getTokenReferenceAlignment(Left) != FormatStyle::PAS_Right;
// Space before & or && following a TT_StructuredBindingLSquare.
if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) &&
Right.isOneOf(tok::amp, tok::ampamp))
- return Style.PointerAlignment != FormatStyle::PAS_Left;
+ return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left;
if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
(Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
!Right.is(tok::r_paren)))
@@ -4034,7 +4036,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return !Right.is(tok::l_paren);
if (Right.is(TT_PointerOrReference))
return Line.IsMultiVariableDeclStmt ||
- (Style.PointerAlignment == FormatStyle::PAS_Right &&
+ (getTokenPointerOrReferenceAlignment(Right) ==
+ FormatStyle::PAS_Right &&
(!Right.Next || Right.Next->isNot(TT_FunctionDeclarationName)));
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
Right.is(tok::kw_operator))
@@ -4249,5 +4252,41 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
llvm::errs() << "----\n";
}
+FormatStyle::PointerAlignmentStyle
+TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) {
+ assert(Reference.isOneOf(tok::amp, tok::ampamp));
+ switch (Style.ReferenceAlignment) {
+ case FormatStyle::RAS_Pointer:
+ return Style.PointerAlignment;
+ case FormatStyle::RAS_Left:
+ return FormatStyle::PAS_Left;
+ case FormatStyle::RAS_Right:
+ return FormatStyle::PAS_Right;
+ case FormatStyle::RAS_Middle:
+ return FormatStyle::PAS_Middle;
+ }
+ assert(0); //"Unhandled value of ReferenceAlignment"
+ return Style.PointerAlignment;
+}
+
+FormatStyle::PointerAlignmentStyle
+TokenAnnotator::getTokenPointerOrReferenceAlignment(
+ const FormatToken &PointerOrReference) {
+ if (PointerOrReference.isOneOf(tok::amp, tok::ampamp)) {
+ switch (Style.ReferenceAlignment) {
+ case FormatStyle::RAS_Pointer:
+ return Style.PointerAlignment;
+ case FormatStyle::RAS_Left:
+ return FormatStyle::PAS_Left;
+ case FormatStyle::RAS_Right:
+ return FormatStyle::PAS_Right;
+ case FormatStyle::RAS_Middle:
+ return FormatStyle::PAS_Middle;
+ }
+ }
+ assert(PointerOrReference.is(tok::star));
+ return Style.PointerAlignment;
+}
+
} // namespace format
} // namespace clang
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index 7f2dff561e7b4..0f9c02dbeb34b 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -195,6 +195,11 @@ class TokenAnnotator {
FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,
FormatToken *CurrentToken,
unsigned Depth);
+ FormatStyle::PointerAlignmentStyle
+ getTokenReferenceAlignment(const FormatToken &PointerOrReference);
+
+ FormatStyle::PointerAlignmentStyle
+ getTokenPointerOrReferenceAlignment(const FormatToken &PointerOrReference);
const FormatStyle &Style;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index cc702e81c2c37..df795e3c89320 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -1789,6 +1789,98 @@ TEST_F(FormatTest, ElseIf) {
getLLVMStyleWithColumns(62));
}
+TEST_F(FormatTest, SeparatePointerReferenceAlignment) {
+ FormatStyle Style = getLLVMStyle();
+ // Check first the default LLVM style
+ // Style.PointerAlignment = FormatStyle::PAS_Right;
+ // Style.ReferenceAlignment = FormatStyle::RAS_Pointer;
+ verifyFormat("int *f1(int *a, int &b, int &&c);", Style);
+ verifyFormat("int &f2(int &&c, int *a, int &b);", Style);
+ verifyFormat("int &&f3(int &b, int &&c, int *a);", Style);
+ verifyFormat("int *f1(int &a) const &;", Style);
+ verifyFormat("int *f1(int &a) const & = 0;", Style);
+ verifyFormat("int *a = f1();", Style);
+ verifyFormat("int &b = f2();", Style);
+ verifyFormat("int &&c = f3();", Style);
+
+ Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive;
+ verifyFormat("Const unsigned int *c;\n"
+ "const unsigned int *d;\n"
+ "Const unsigned int &e;\n"
+ "const unsigned int &f;\n"
+ "const unsigned &&g;\n"
+ "Const unsigned h;",
+ Style);
+
+ Style.PointerAlignment = FormatStyle::PAS_Left;
+ Style.ReferenceAlignment = FormatStyle::RAS_Pointer;
+ verifyFormat("int* f1(int* a, int& b, int&& c);", Style);
+ verifyFormat("int& f2(int&& c, int* a, int& b);", Style);
+ verifyFormat("int&& f3(int& b, int&& c, int* a);", Style);
+ verifyFormat("int* f1(int& a) const& = 0;", Style);
+ verifyFormat("int* a = f1();", Style);
+ verifyFormat("int& b = f2();", Style);
+ verifyFormat("int&& c = f3();", Style);
+
+ Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive;
+ verifyFormat("Const unsigned int* c;\n"
+ "const unsigned int* d;\n"
+ "Const unsigned int& e;\n"
+ "const unsigned int& f;\n"
+ "const unsigned&& g;\n"
+ "Const unsigned h;",
+ Style);
+
+ Style.PointerAlignment = FormatStyle::PAS_Right;
+ Style.ReferenceAlignment = FormatStyle::RAS_Left;
+ verifyFormat("int *f1(int *a, int& b, int&& c);", Style);
+ verifyFormat("int& f2(int&& c, int *a, int& b);", Style);
+ verifyFormat("int&& f3(int& b, int&& c, int *a);", Style);
+ verifyFormat("int *a = f1();", Style);
+ verifyFormat("int& b = f2();", Style);
+ verifyFormat("int&& c = f3();", Style);
+
+ Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive;
+ verifyFormat("Const unsigned int *c;\n"
+ "const unsigned int *d;\n"
+ "Const unsigned int& e;\n"
+ "const unsigned int& f;\n"
+ "const unsigned g;\n"
+ "Const unsigned h;",
+ Style);
+
+ Style.PointerAlignment = FormatStyle::PAS_Left;
+ Style.ReferenceAlignment = FormatStyle::RAS_Middle;
+ verifyFormat("int* f1(int* a, int & b, int && c);", Style);
+ verifyFormat("int & f2(int && c, int* a, int & b);", Style);
+ verifyFormat("int && f3(int & b, int && c, int* a);", Style);
+ verifyFormat("int* a = f1();", Style);
+ verifyFormat("int & b = f2();", Style);
+ verifyFormat("int && c = f3();", Style);
+
+ Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive;
+ verifyFormat("Const unsigned int* c;\n"
+ "const unsigned int* d;\n"
+ "Const unsigned int & e;\n"
+ "const unsigned int & f;\n"
+ "const unsigned && g;\n"
+ "Const unsigned h;",
+ Style);
+
+ Style.PointerAlignment = FormatStyle::PAS_Middle;
+ Style.ReferenceAlignment = FormatStyle::RAS_Right;
+ verifyFormat("int * f1(int * a, int &b, int &&c);", Style);
+ verifyFormat("int &f2(int &&c, int * a, int &b);", Style);
+ verifyFormat("int &&f3(int &b, int &&c, int * a);", Style);
+ verifyFormat("int * a = f1();", Style);
+ verifyFormat("int &b = f2();", Style);
+ verifyFormat("int &&c = f3();", Style);
+
+ // FIXME: we don't handle this yet, so output may be arbitrary until it's
+ // specifically handled
+ // verifyFormat("int Add2(BTree * &Root, char * szToAdd)", Style);
+}
+
TEST_F(FormatTest, FormatsForLoop) {
verifyFormat(
"for (int VeryVeryLongLoopVariable = 0; VeryVeryLongLoopVariable < 10;\n"
@@ -18013,6 +18105,15 @@ TEST_F(FormatTest, ParsesConfiguration) {
FormatStyle::PAS_Right);
CHECK_PARSE("PointerAlignment: Middle", PointerAlignment,
FormatStyle::PAS_Middle);
+ Style.ReferenceAlignment = FormatStyle::RAS_Middle;
+ CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment,
+ FormatStyle::RAS_Pointer);
+ CHECK_PARSE("ReferenceAlignment: Left", ReferenceAlignment,
+ FormatStyle::RAS_Left);
+ CHECK_PARSE("ReferenceAlignment: Right", ReferenceAlignment,
+ FormatStyle::RAS_Right);
+ CHECK_PARSE("ReferenceAlignment: Middle", ReferenceAlignment,
+ FormatStyle::RAS_Middle);
// For backward compatibility:
CHECK_PARSE("PointerBindsToType: Left", PointerAlignment,
FormatStyle::PAS_Left);
More information about the cfe-commits
mailing list