Skip to content

Commit cab1eb2

Browse files
committed
[clang-format] Allow custom pointer/ref alignment for C-style casts
I would like to adopt clang-format in systemd (https://github.com/systemd/systemd). One major blocker is that systemd right-aligns pointers by default, except in function return types and c-style casts, where they are left-aligned. Let's introduce a CStyleCast customization for PointerAlignment and ReferenceAlignment that allows overriding the alignment used for C-style casts. systemd style guide: https://github.com/systemd/systemd/blob/main/docs/CODING_STYLE.md
1 parent a4ca42e commit cab1eb2

File tree

6 files changed

+290
-27
lines changed

6 files changed

+290
-27
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5748,6 +5748,29 @@ the configuration (without a prefix: ``Auto``).
57485748
int * a(void);
57495749

57505750

5751+
* ``CastAlignmentStyle CStyleCast``
5752+
The alignment for pointers in C-style casts.
5753+
5754+
Possible values:
5755+
5756+
* ``CAS_Default`` (in configuration: ``Default``)
5757+
Use default alignment.
5758+
5759+
* ``CAS_Left`` (in configuration: ``Left``)
5760+
Align pointer/reference to the left.
5761+
5762+
.. code-block:: c++
5763+
5764+
(char*)s;
5765+
5766+
* ``CAS_Right`` (in configuration: ``Right``)
5767+
Align pointer/reference to the right.
5768+
5769+
.. code-block:: c++
5770+
5771+
(char *)s;
5772+
5773+
57515774

57525775
.. _QualifierAlignment:
57535776

@@ -5961,6 +5984,29 @@ the configuration (without a prefix: ``Auto``).
59615984
int * a(void);
59625985

59635986

5987+
* ``CastAlignmentStyle CStyleCast``
5988+
The alignment for references in C-style casts.
5989+
5990+
Possible values:
5991+
5992+
* ``CAS_Default`` (in configuration: ``Default``)
5993+
Use default alignment.
5994+
5995+
* ``CAS_Left`` (in configuration: ``Left``)
5996+
Align pointer/reference to the left.
5997+
5998+
.. code-block:: c++
5999+
6000+
(char*)s;
6001+
6002+
* ``CAS_Right`` (in configuration: ``Right``)
6003+
Align pointer/reference to the right.
6004+
6005+
.. code-block:: c++
6006+
6007+
(char *)s;
6008+
6009+
59646010

59656011
.. _ReflowComments:
59666012

clang/include/clang/Format/Format.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4057,14 +4057,33 @@ struct FormatStyle {
40574057
RTAS_Middle
40584058
};
40594059

4060+
/// \brief The pointer/reference alignment style for C-style casts.
4061+
enum CastAlignmentStyle : int8_t {
4062+
/// Use default alignment.
4063+
CAS_Default,
4064+
/// Align pointer/reference to the left.
4065+
/// \code
4066+
/// (char*)s;
4067+
/// \endcode
4068+
CAS_Left,
4069+
/// Align pointer/reference to the right.
4070+
/// \code
4071+
/// (char *)s;
4072+
/// \endcode
4073+
CAS_Right,
4074+
};
4075+
40604076
/// Pointer and reference alignment options.
40614077
struct PointerAlignmentOptions {
40624078
/// The default alignment for pointers and references.
40634079
PointerAlignmentStyle Default;
40644080
/// The alignment for pointers in function return types.
40654081
ReturnTypeAlignmentStyle ReturnType;
4082+
/// The alignment for pointers in C-style casts.
4083+
CastAlignmentStyle CStyleCast;
40664084
bool operator==(const PointerAlignmentOptions &R) const {
4067-
return Default == R.Default && ReturnType == R.ReturnType;
4085+
return Default == R.Default && ReturnType == R.ReturnType &&
4086+
CStyleCast == R.CStyleCast;
40684087
}
40694088
bool operator!=(const PointerAlignmentOptions &R) const {
40704089
return !(*this == R);
@@ -4264,8 +4283,11 @@ struct FormatStyle {
42644283
ReferenceAlignmentStyle Default;
42654284
/// The alignment for references in function return types.
42664285
ReturnTypeAlignmentStyle ReturnType;
4286+
/// The alignment for references in C-style casts.
4287+
CastAlignmentStyle CStyleCast;
42674288
bool operator==(const ReferenceAlignmentOptions &R) const {
4268-
return Default == R.Default && ReturnType == R.ReturnType;
4289+
return Default == R.Default && ReturnType == R.ReturnType &&
4290+
CStyleCast == R.CStyleCast;
42694291
}
42704292
bool operator!=(const ReferenceAlignmentOptions &R) const {
42714293
return !(*this == R);

clang/lib/Format/Format.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -555,35 +555,49 @@ struct ScalarEnumerationTraits<FormatStyle::ReturnTypeAlignmentStyle> {
555555
}
556556
};
557557

558+
template <> struct ScalarEnumerationTraits<FormatStyle::CastAlignmentStyle> {
559+
static void enumeration(IO &IO, FormatStyle::CastAlignmentStyle &Value) {
560+
IO.enumCase(Value, "Default", FormatStyle::CAS_Default);
561+
IO.enumCase(Value, "Left", FormatStyle::CAS_Left);
562+
IO.enumCase(Value, "Right", FormatStyle::CAS_Right);
563+
}
564+
};
565+
558566
template <> struct MappingTraits<FormatStyle::PointerAlignmentOptions> {
559567
static void enumInput(IO &IO, FormatStyle::PointerAlignmentOptions &Value) {
560568
IO.enumCase(Value, "Middle",
561569
FormatStyle::PointerAlignmentOptions(
562570
{/*Default=*/FormatStyle::PAS_Middle,
563-
/*ReturnType=*/FormatStyle::RTAS_Default}));
571+
/*ReturnType=*/FormatStyle::RTAS_Default,
572+
/*CStyleCast=*/FormatStyle::CAS_Default}));
564573
IO.enumCase(Value, "Left",
565574
FormatStyle::PointerAlignmentOptions(
566575
{/*Default=*/FormatStyle::PAS_Left,
567-
/*ReturnType=*/FormatStyle::RTAS_Default}));
576+
/*ReturnType=*/FormatStyle::RTAS_Default,
577+
/*CStyleCast=*/FormatStyle::CAS_Default}));
568578
IO.enumCase(Value, "Right",
569579
FormatStyle::PointerAlignmentOptions(
570580
{/*Default=*/FormatStyle::PAS_Right,
571-
/*ReturnType=*/FormatStyle::RTAS_Default}));
581+
/*ReturnType=*/FormatStyle::RTAS_Default,
582+
/*CStyleCast=*/FormatStyle::CAS_Default}));
572583

573584
// For backward compatibility.
574585
IO.enumCase(Value, "true",
575586
FormatStyle::PointerAlignmentOptions(
576587
{/*Default=*/FormatStyle::PAS_Left,
577-
/*ReturnType=*/FormatStyle::RTAS_Default}));
588+
/*ReturnType=*/FormatStyle::RTAS_Default,
589+
/*CStyleCast=*/FormatStyle::CAS_Default}));
578590
IO.enumCase(Value, "false",
579591
FormatStyle::PointerAlignmentOptions(
580592
{/*Default=*/FormatStyle::PAS_Right,
581-
/*ReturnType=*/FormatStyle::RTAS_Default}));
593+
/*ReturnType=*/FormatStyle::RTAS_Default,
594+
/*CStyleCast=*/FormatStyle::CAS_Default}));
582595
}
583596

584597
static void mapping(IO &IO, FormatStyle::PointerAlignmentOptions &Value) {
585598
IO.mapOptional("Default", Value.Default);
586599
IO.mapOptional("ReturnType", Value.ReturnType);
600+
IO.mapOptional("CStyleCast", Value.CStyleCast);
587601
}
588602
};
589603

@@ -633,24 +647,29 @@ template <> struct MappingTraits<FormatStyle::ReferenceAlignmentOptions> {
633647
IO.enumCase(Value, "Pointer",
634648
FormatStyle::ReferenceAlignmentOptions(
635649
{/*Default=*/FormatStyle::RAS_Pointer,
636-
/*ReturnType=*/FormatStyle::RTAS_Default}));
650+
/*ReturnType=*/FormatStyle::RTAS_Default,
651+
/*CStyleCast=*/FormatStyle::CAS_Default}));
637652
IO.enumCase(Value, "Middle",
638653
FormatStyle::ReferenceAlignmentOptions(
639654
{/*Default=*/FormatStyle::RAS_Middle,
640-
/*ReturnType=*/FormatStyle::RTAS_Default}));
655+
/*ReturnType=*/FormatStyle::RTAS_Default,
656+
/*CStyleCast=*/FormatStyle::CAS_Default}));
641657
IO.enumCase(Value, "Left",
642658
FormatStyle::ReferenceAlignmentOptions(
643659
{/*Default=*/FormatStyle::RAS_Left,
644-
/*ReturnType=*/FormatStyle::RTAS_Default}));
660+
/*ReturnType=*/FormatStyle::RTAS_Default,
661+
/*CStyleCast=*/FormatStyle::CAS_Default}));
645662
IO.enumCase(Value, "Right",
646663
FormatStyle::ReferenceAlignmentOptions(
647664
{/*Default=*/FormatStyle::RAS_Right,
648-
/*ReturnType=*/FormatStyle::RTAS_Default}));
665+
/*ReturnType=*/FormatStyle::RTAS_Default,
666+
/*CStyleCast=*/FormatStyle::CAS_Default}));
649667
}
650668

651669
static void mapping(IO &IO, FormatStyle::ReferenceAlignmentOptions &Value) {
652670
IO.mapOptional("Default", Value.Default);
653671
IO.mapOptional("ReturnType", Value.ReturnType);
672+
IO.mapOptional("CStyleCast", Value.CStyleCast);
654673
}
655674
};
656675

@@ -1851,11 +1870,13 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
18511870
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
18521871
LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
18531872
LLVMStyle.PointerAlignment = {/*Default=*/FormatStyle::PAS_Right,
1854-
/*ReturnType=*/FormatStyle::RTAS_Default};
1873+
/*ReturnType=*/FormatStyle::RTAS_Default,
1874+
/*CStyleCast=*/FormatStyle::CAS_Default};
18551875
LLVMStyle.PPIndentWidth = -1;
18561876
LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
18571877
LLVMStyle.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Pointer,
1858-
/*ReturnType=*/FormatStyle::RTAS_Default};
1878+
/*ReturnType=*/FormatStyle::RTAS_Default,
1879+
/*CStyleCast=*/FormatStyle::CAS_Default};
18591880
LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
18601881
LLVMStyle.RemoveBracesLLVM = false;
18611882
LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false;

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6586,6 +6586,29 @@ static bool isReturnType(const FormatToken &Tok, const LangOptions &LangOpts) {
65866586
return false;
65876587
}
65886588

6589+
static bool isCStyleCast(const FormatToken &Tok, const LangOptions &LangOpts) {
6590+
// Look forward to see if there's a TT_CastRParen.
6591+
for (const FormatToken *Next = Tok.Next; Next;
6592+
Next = Next->getNextNonComment()) {
6593+
if (Next->is(TT_CastRParen))
6594+
return true;
6595+
6596+
if (Next->is(TT_TemplateOpener) && Next->MatchingParen) {
6597+
Next = Next->MatchingParen;
6598+
continue;
6599+
}
6600+
6601+
if (Prev->isPointerOrReference() || Prev->isTypeName(LangOpts) ||
6602+
Prev->isOneOf(tok::identifier, tok::coloncolon) ||
6603+
Prev->canBePointerOrReferenceQualifier()) {
6604+
continue;
6605+
}
6606+
6607+
break;
6608+
}
6609+
return false;
6610+
}
6611+
65896612
static FormatStyle::PointerAlignmentStyle
65906613
mapReturnTypeAlignmentStyle(FormatStyle::ReturnTypeAlignmentStyle Style) {
65916614
switch (Style) {
@@ -6601,6 +6624,19 @@ mapReturnTypeAlignmentStyle(FormatStyle::ReturnTypeAlignmentStyle Style) {
66016624
llvm_unreachable("Unknown FormatStyle::ReturnTypeAlignmentStyle enum");
66026625
}
66036626

6627+
static FormatStyle::PointerAlignmentStyle
6628+
mapCastAlignmentStyle(FormatStyle::CastAlignmentStyle Style) {
6629+
switch (Style) {
6630+
case FormatStyle::CAS_Left:
6631+
return FormatStyle::PAS_Left;
6632+
case FormatStyle::CAS_Right:
6633+
return FormatStyle::PAS_Right;
6634+
case FormatStyle::CAS_Default:
6635+
assert(false);
6636+
}
6637+
llvm_unreachable("Unknown FormatStyle::CastAlignmentStyle enum");
6638+
}
6639+
66046640
FormatStyle::PointerAlignmentStyle
66056641
TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const {
66066642
assert(Reference.isOneOf(tok::amp, tok::ampamp));
@@ -6610,6 +6646,11 @@ TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) const {
66106646
return mapReturnTypeAlignmentStyle(Style.ReferenceAlignment.ReturnType);
66116647
}
66126648

6649+
if (Style.ReferenceAlignment.CStyleCast != FormatStyle::CAS_Default &&
6650+
isCStyleCast(Reference, LangOpts)) {
6651+
return mapCastAlignmentStyle(Style.ReferenceAlignment.CStyleCast);
6652+
}
6653+
66136654
switch (Style.ReferenceAlignment.Default) {
66146655
case FormatStyle::RAS_Pointer:
66156656
return Style.PointerAlignment.Default;
@@ -6635,6 +6676,11 @@ TokenAnnotator::getTokenPointerOrReferenceAlignment(
66356676
return mapReturnTypeAlignmentStyle(Style.PointerAlignment.ReturnType);
66366677
}
66376678

6679+
if (Style.PointerAlignment.CStyleCast != FormatStyle::CAS_Default &&
6680+
isCStyleCast(PointerOrReference, LangOpts)) {
6681+
return mapCastAlignmentStyle(Style.PointerAlignment.CStyleCast);
6682+
}
6683+
66386684
return Style.PointerAlignment.Default;
66396685
}
66406686

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -392,66 +392,96 @@ TEST(ConfigParseTest, ParsesConfiguration) {
392392
#undef CHECK_ALIGN_CONSECUTIVE
393393

394394
Style.PointerAlignment = {/*Default=*/FormatStyle::PAS_Middle,
395-
/*ReturnType=*/FormatStyle::RTAS_Default};
395+
/*ReturnType=*/FormatStyle::RTAS_Default,
396+
/*CStyleCast=*/FormatStyle::CAS_Default};
396397
CHECK_PARSE("PointerAlignment: Left", PointerAlignment,
397398
FormatStyle::PointerAlignmentOptions(
398399
{/*Default=*/FormatStyle::PAS_Left,
399-
/*ReturnType=*/FormatStyle::RTAS_Default}));
400+
/*ReturnType=*/FormatStyle::RTAS_Default,
401+
/*CStyleCast=*/FormatStyle::CAS_Default}));
400402
CHECK_PARSE("PointerAlignment: Right", PointerAlignment,
401403
FormatStyle::PointerAlignmentOptions(
402404
{/*Default=*/FormatStyle::PAS_Right,
403-
/*ReturnType=*/FormatStyle::RTAS_Default}));
405+
/*ReturnType=*/FormatStyle::RTAS_Default,
406+
/*CStyleCast=*/FormatStyle::CAS_Default}));
404407
CHECK_PARSE("PointerAlignment: Middle", PointerAlignment,
405408
FormatStyle::PointerAlignmentOptions(
406409
{/*Default=*/FormatStyle::PAS_Middle,
407-
/*ReturnType=*/FormatStyle::RTAS_Default}));
410+
/*ReturnType=*/FormatStyle::RTAS_Default,
411+
/*CStyleCast=*/FormatStyle::CAS_Default}));
408412
CHECK_PARSE("PointerAlignment:\n"
409413
" Default: Right\n"
410414
" ReturnType: Left",
411415
PointerAlignment,
412416
FormatStyle::PointerAlignmentOptions(
413417
{/*Default=*/FormatStyle::PAS_Right,
414-
/*ReturnType=*/FormatStyle::RTAS_Left}));
418+
/*ReturnType=*/FormatStyle::RTAS_Left,
419+
/*CStyleCast=*/FormatStyle::CAS_Default}));
420+
CHECK_PARSE("PointerAlignment:\n"
421+
" Default: Right\n"
422+
" CStyleCast: Left",
423+
PointerAlignment,
424+
FormatStyle::PointerAlignmentOptions(
425+
{/*Default=*/FormatStyle::PAS_Right,
426+
/*ReturnType=*/FormatStyle::RTAS_Left,
427+
/*CStyleCast=*/FormatStyle::CAS_Left}));
415428

416429
Style.ReferenceAlignment = {/*Default=*/FormatStyle::RAS_Middle,
417-
/*ReturnType=*/FormatStyle::RTAS_Default};
430+
/*ReturnType=*/FormatStyle::RTAS_Default,
431+
/*CStyleCast=*/FormatStyle::CAS_Default};
418432
CHECK_PARSE("ReferenceAlignment: Pointer", ReferenceAlignment,
419433
FormatStyle::ReferenceAlignmentOptions(
420434
{/*Default=*/FormatStyle::RAS_Pointer,
421-
/*ReturnType=*/FormatStyle::RTAS_Default}));
435+
/*ReturnType=*/FormatStyle::RTAS_Default,
436+
/*CStyleCast=*/FormatStyle::CAS_Default}));
422437
CHECK_PARSE("ReferenceAlignment: Left", ReferenceAlignment,
423438
FormatStyle::ReferenceAlignmentOptions(
424439
{/*Default=*/FormatStyle::RAS_Left,
425-
/*ReturnType=*/FormatStyle::RTAS_Default}));
440+
/*ReturnType=*/FormatStyle::RTAS_Default,
441+
/*CStyleCast=*/FormatStyle::CAS_Default}));
426442
CHECK_PARSE("ReferenceAlignment: Right", ReferenceAlignment,
427443
FormatStyle::ReferenceAlignmentOptions(
428444
{/*Default=*/FormatStyle::RAS_Right,
429-
/*ReturnType=*/FormatStyle::RTAS_Default}));
445+
/*ReturnType=*/FormatStyle::RTAS_Default,
446+
/*CStyleCast=*/FormatStyle::CAS_Default}));
430447
CHECK_PARSE("ReferenceAlignment: Middle", ReferenceAlignment,
431448
FormatStyle::ReferenceAlignmentOptions(
432449
{/*Default=*/FormatStyle::RAS_Middle,
433-
/*ReturnType=*/FormatStyle::RTAS_Default}));
450+
/*ReturnType=*/FormatStyle::RTAS_Default,
451+
/*CStyleCast=*/FormatStyle::CAS_Default}));
434452
CHECK_PARSE("ReferenceAlignment:\n"
435453
" Default: Right\n"
436454
" ReturnType: Left",
437455
ReferenceAlignment,
438456
FormatStyle::ReferenceAlignmentOptions(
439457
{/*Default=*/FormatStyle::RAS_Right,
440-
/*ReturnType=*/FormatStyle::RTAS_Left}));
458+
/*ReturnType=*/FormatStyle::RTAS_Left,
459+
/*CStyleCast=*/FormatStyle::CAS_Default}));
460+
CHECK_PARSE("ReferenceAlignment:\n"
461+
" Default: Right\n"
462+
" CStyleCast: Left",
463+
ReferenceAlignment,
464+
FormatStyle::ReferenceAlignmentOptions(
465+
{/*Default=*/FormatStyle::RAS_Right,
466+
/*ReturnType=*/FormatStyle::RTAS_Left,
467+
/*CStyleCast=*/FormatStyle::CAS_Left}));
441468

442469
// For backward compatibility:
443470
CHECK_PARSE("PointerBindsToType: Left", PointerAlignment,
444471
FormatStyle::PointerAlignmentOptions(
445472
{/*Default=*/FormatStyle::PAS_Left,
446-
/*ReturnType=*/FormatStyle::RTAS_Default}));
473+
/*ReturnType=*/FormatStyle::RTAS_Default,
474+
/*CStyleCast=*/FormatStyle::CAS_Default}));
447475
CHECK_PARSE("PointerBindsToType: Right", PointerAlignment,
448476
FormatStyle::PointerAlignmentOptions(
449477
{/*Default=*/FormatStyle::PAS_Right,
450-
/*ReturnType=*/FormatStyle::RTAS_Default}));
478+
/*ReturnType=*/FormatStyle::RTAS_Default,
479+
/*CStyleCast=*/FormatStyle::CAS_Default}));
451480
CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment,
452481
FormatStyle::PointerAlignmentOptions(
453482
{/*Default=*/FormatStyle::PAS_Middle,
454-
/*ReturnType=*/FormatStyle::RTAS_Default}));
483+
/*ReturnType=*/FormatStyle::RTAS_Default,
484+
/*CStyleCast=*/FormatStyle::CAS_Default}));
455485

456486
Style.ReflowComments = FormatStyle::RCS_Always;
457487
CHECK_PARSE("ReflowComments: Never", ReflowComments, FormatStyle::RCS_Never);

0 commit comments

Comments
 (0)