llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-format

Author: None (kgerlich)

<details>
<summary>Changes</summary>

… macro

This adds a new configuration option SpaceBeforeUnderscoreParens to control 
spacing between underscore and opening parenthesis. This is specifically 
designed for the gettext internationalization macro '_()' commonly used in GNU 
projects like GDB.

The option:
- Defaults to true for LLVM style (preserving existing behavior)
- Defaults to false for GNU style (removes space before '_(')
- Only affects single underscore tokens '_', not other identifiers
- Leaves all other spacing rules unchanged

Examples:
  GNU style with SpaceBeforeUnderscoreParens=false:
    printf(_("Hello"));     // No space before '_('
    my_func (arg);            // Space before other functions preserved

  LLVM style with SpaceBeforeUnderscoreParens=true:
    printf(_("Hello"));     // Standard spacing rules apply

This addresses the common pattern in GNU software where gettext messages use 
'_()' without spaces, improving consistency with GNU coding standards.

---
Full diff: https://github.com/llvm/llvm-project/pull/159925.diff


4 Files Affected:

- (modified) clang/include/clang/Format/Format.h (+10) 
- (modified) clang/lib/Format/Format.cpp (+4) 
- (modified) clang/lib/Format/TokenAnnotator.cpp (+6) 
- (modified) clang/unittests/Format/FormatTest.cpp (+36) 


``````````diff
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 342fefcfc408c..1643c575fcbba 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -4667,6 +4667,16 @@ struct FormatStyle {
   /// \version 7
   bool SpaceBeforeInheritanceColon;
 
+  /// If ``false``, spaces will be removed between underscore and an opening
+  /// parenthesis. This is specifically for the gettext macro ``_()`` commonly
+  /// used in GNU projects.
+  /// \code
+  ///    true:                                  false:
+  ///    _ (message);                   vs.     _(message);
+  /// \endcode
+  /// \version 19
+  bool SpaceBeforeUnderscoreParens;
+
   /// If ``true``, a space will be added before a JSON colon. For other
   /// languages, e.g. JavaScript, use ``SpacesInContainerLiterals`` instead.
   /// \code
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 24a36d97a6fa9..9181e9a9ecd26 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1219,6 +1219,8 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.SpaceBeforeCtorInitializerColon);
     IO.mapOptional("SpaceBeforeInheritanceColon",
                    Style.SpaceBeforeInheritanceColon);
+    IO.mapOptional("SpaceBeforeUnderscoreParens",
+                   Style.SpaceBeforeUnderscoreParens);
     IO.mapOptional("SpaceBeforeJsonColon", Style.SpaceBeforeJsonColon);
     IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
     IO.mapOptional("SpaceBeforeParensOptions", Style.SpaceBeforeParensOptions);
@@ -1713,6 +1715,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.SpaceBeforeCpp11BracedList = false;
   LLVMStyle.SpaceBeforeCtorInitializerColon = true;
   LLVMStyle.SpaceBeforeInheritanceColon = true;
+  LLVMStyle.SpaceBeforeUnderscoreParens = true;
   LLVMStyle.SpaceBeforeJsonColon = false;
   LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
   LLVMStyle.SpaceBeforeParensOptions = {};
@@ -2044,6 +2047,7 @@ FormatStyle getGNUStyle() {
   Style.FixNamespaceComments = false;
   Style.KeepFormFeed = true;
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+  Style.SpaceBeforeUnderscoreParens = false;
   return Style;
 }
 
diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index d97f56751ea69..9af90184d157e 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4901,6 +4901,12 @@ bool TokenAnnotator::spaceRequiredBetween(const 
AnnotatedLine &Line,
     // Handle builtins like identifiers.
     if (Line.Type != LT_PreprocessorDirective &&
         (Left.Tok.getIdentifierInfo() || Left.is(tok::r_paren))) {
+      // Check for special case: single underscore token (gettext macro)
+      if (Left.Tok.getIdentifierInfo() && !Style.SpaceBeforeUnderscoreParens) {
+        StringRef TokenText = Left.TokenText;
+        if (TokenText == "_")
+          return false;
+      }
       return spaceRequiredBeforeParens(Right);
     }
     return false;
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index d9db06667d802..4ca1f8fbfa363 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -17852,6 +17852,42 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
                Spaces);
 }
 
+TEST_F(FormatTest, SpaceBeforeUnderscoreParens) {
+  // Test with SpaceBeforeParens = Always to clearly show the difference
+  FormatStyle Style = getLLVMStyle();
+  Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+
+  // Default LLVM style should have SpaceBeforeUnderscoreParens = true
+  EXPECT_TRUE(Style.SpaceBeforeUnderscoreParens);
+  verifyFormat("func (arg);", Style);       // All functions should have space
+  verifyFormat("my_func (arg);", Style);    // All functions should have space 
 
+  verifyFormat("_ (message);", Style);      // Single underscore should have 
space when SpaceBeforeUnderscoreParens=true
+  verifyFormat("underscore_ (param);", Style); // Other underscores should 
have space
+
+  // Now test with SpaceBeforeUnderscoreParens = false but SpaceBeforeParens = 
Always
+  Style.SpaceBeforeUnderscoreParens = false;
+  verifyFormat("func (arg);", Style);       // Non-underscore functions should 
still have space
+  verifyFormat("my_func (arg);", Style);    // Functions with underscores 
should still have space
+  verifyFormat("_(message);", Style);       // Single underscore (gettext 
macro) should NOT have space
+  verifyFormat("underscore_ (param);", Style); // Other underscores should 
still have space
+  verifyFormat("_private_func (data);", Style); // Functions starting with 
underscore but not single _ should have space
+
+  // Test GNU style (should have SpaceBeforeUnderscoreParens = false by 
default)
+  FormatStyle GNUStyle = getGNUStyle();
+  EXPECT_FALSE(GNUStyle.SpaceBeforeUnderscoreParens);
+  EXPECT_EQ(GNUStyle.SpaceBeforeParens, FormatStyle::SBPO_Always); // GNU 
style should have SpaceBeforeParens = Always
+  verifyFormat("func (arg);", GNUStyle);    // GNU style has SpaceBeforeParens 
= Always
+  verifyFormat("my_func (arg);", GNUStyle); // Functions with underscores 
should have space
+  verifyFormat("_(message);", GNUStyle);    // Single underscore (gettext 
macro) should NOT have space
+  verifyFormat("_private_func (data);", GNUStyle); // Other functions should 
have space
+
+  // Test mixed scenarios with GNU style
+  verifyFormat("printf (_(\"Hello\"));\n"
+               "func (arg);\n"
+               "_(\"World\");",
+               GNUStyle);
+}
+
 TEST_F(FormatTest, ConfigurableSpacesInSquareBrackets) {
   verifyFormat("int a[5];");
   verifyFormat("a[3] += 42;");

``````````

</details>


https://github.com/llvm/llvm-project/pull/159925
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to