diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2571,6 +2571,15 @@ +**SpaceBeforePointerQualifiers** (``bool``) + If ``true``, spaces will be added before pointer qualifiers. This only + changes the format when pointers are aligned to the right. + + .. code-block:: c++ + + true: false: + void * const x = NULL; vs. void *const x = NULL; + **SpaceBeforeRangeBasedForLoopColon** (``bool``) If ``false``, spaces will be removed before range-based for loop colon. diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2172,6 +2172,14 @@ /// Defines in which cases to put a space before opening parentheses. SpaceBeforeParensOptions SpaceBeforeParens; + /// If ``true``, spaces will be added before pointer qualifiers. This only + /// changes the format when pointers are aligned to the right. + /// \code + /// true: false: + /// void * const x = NULL; vs. void *const x = NULL; + /// \endcode + bool SpaceBeforePointerQualifiers; + /// If ``false``, spaces will be removed before range-based for loop /// colon. /// \code @@ -2470,6 +2478,7 @@ R.SpaceBeforeCtorInitializerColon && SpaceBeforeInheritanceColon == R.SpaceBeforeInheritanceColon && SpaceBeforeParens == R.SpaceBeforeParens && + SpaceBeforePointerQualifiers == R.SpaceBeforePointerQualifiers && SpaceBeforeRangeBasedForLoopColon == R.SpaceBeforeRangeBasedForLoopColon && SpaceInEmptyBlock == R.SpaceInEmptyBlock && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -598,6 +598,8 @@ IO.mapOptional("SpaceBeforeInheritanceColon", Style.SpaceBeforeInheritanceColon); IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); + IO.mapOptional("SpaceBeforePointerQualifiers", + Style.SpaceBeforePointerQualifiers); IO.mapOptional("SpaceBeforeRangeBasedForLoopColon", Style.SpaceBeforeRangeBasedForLoopColon); IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock); @@ -938,6 +940,7 @@ LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; + LLVMStyle.SpaceBeforePointerQualifiers = false; LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true; LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; 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 @@ -2873,6 +2873,8 @@ return true; if (Left.is(TT_PointerOrReference)) return Right.Tok.isLiteral() || Right.is(TT_BlockComment) || + (Style.SpaceBeforePointerQualifiers && + Right.canBePointerOrReferenceQualifier()) || (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) && !Right.is(TT_StartOfName)) || (Right.is(tok::l_brace) && Right.is(BK_Block)) || 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 @@ -12104,6 +12104,47 @@ NoSpaceStyle); } +TEST_F(FormatTest, ConfigurableSpaceBeforePointerQualifiers) { + FormatStyle Spaces = getLLVMStyle(); + Spaces.AttributeMacros.push_back("qualified"); + verifyFormat("SomeType *const *a = NULL;", Spaces); + verifyFormat("SomeType *volatile *a = NULL;", Spaces); + verifyFormat("SomeType *__attribute__((attr)) *a = NULL;", Spaces); + verifyFormat("SomeType *qualified *a = NULL, *const *b;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + + Spaces.SpaceBeforePointerQualifiers = true; + verifyFormat("SomeType * const *a = NULL;", Spaces); + verifyFormat("SomeType * volatile *a = NULL;", Spaces); + verifyFormat("SomeType * __attribute__((attr)) *a = NULL;", Spaces); + verifyFormat("SomeType * qualified *a = NULL, * const *b;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + + // Check that setting SpaceBeforePointerQualifiers doesn't result in extra + // spaces for PAS_Left/PAS_Middle. + Spaces.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("SomeType* const* a = NULL;", Spaces); + verifyFormat("SomeType* volatile* a = NULL;", Spaces); + verifyFormat("SomeType* __attribute__((attr))* a = NULL;", Spaces); + verifyFormat("SomeType* qualified* a = NULL, * const* b;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + + Spaces.PointerAlignment = FormatStyle::PAS_Middle; + verifyFormat("SomeType * const * a = NULL;", Spaces); + verifyFormat("SomeType * volatile * a = NULL;", Spaces); + verifyFormat("SomeType * __attribute__((attr)) * a = NULL;", Spaces); + verifyFormat("SomeType * qualified * a = NULL, * const * b;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); + verifyFormat("std::vector x;", Spaces); +} + TEST_F(FormatTest, AlignConsecutiveMacros) { FormatStyle Style = getLLVMStyle(); Style.AlignConsecutiveAssignments = true; @@ -14003,6 +14044,7 @@ CHECK_PARSE_BOOL(SpaceBeforeCpp11BracedList); CHECK_PARSE_BOOL(SpaceBeforeCtorInitializerColon); CHECK_PARSE_BOOL(SpaceBeforeInheritanceColon); + CHECK_PARSE_BOOL(SpaceBeforePointerQualifiers); CHECK_PARSE_BOOL(SpaceBeforeRangeBasedForLoopColon); CHECK_PARSE_BOOL(SpaceBeforeSquareBrackets); CHECK_PARSE_BOOL(UseCRLF);