llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-format

Author: Lane0218

<details>
<summary>Changes</summary>

This narrows clang-format's spacing heuristic for `identifier ::`.

Previously, clang-format preserved existing whitespace before `::` after any
identifier, which caused inputs like:

```c++
template &lt;typename T&gt;
auto mem = &amp;T :: member;
```

to format as:

```c++
template &lt;typename T&gt;
auto mem = &amp;T ::member;
```

This patch preserves that whitespace only for identifiers that look like
object-like macros, such as the existing `ALWAYS_INLINE ::std::string` case.
Ordinary identifiers now format as expected:

```c++
&amp;T :: member
```

becomes

```c++
&amp;T::member
```

Test:
- `./build-cir/tools/clang/unittests/Format/FormatTests 
--gtest_filter=FormatTest.NestedNameSpecifiers`

Fixes #<!-- -->188754


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


2 Files Affected:

- (modified) clang/lib/Format/TokenAnnotator.cpp (+17-4) 
- (modified) clang/unittests/Format/FormatTest.cpp (+2) 


``````````diff
diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index d2cdc28a7da7b..6a229283681cb 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -59,6 +59,21 @@ static bool canBeObjCSelectorComponent(const FormatToken 
&Tok) {
   return Tok.Tok.getIdentifierInfo();
 }
 
+/// Returns \c true if the token likely names an object-like macro.
+static bool isPossibleMacro(const FormatToken &Tok) {
+  if (Tok.isNot(tok::identifier))
+    return false;
+
+  StringRef Text = Tok.TokenText;
+  assert(!Text.empty());
+
+  // T, K, U, V likely could be template arguments.
+  if (Text.size() == 1)
+    return false;
+
+  return Text == Text.upper();
+}
+
 /// With `Left` being '(', check if we're at either `[...](` or
 /// `[...]<...>(`, where the [ opens a lambda capture list.
 // FIXME: this doesn't cover attributes/constraints before the l_paren.
@@ -5646,10 +5661,8 @@ bool TokenAnnotator::spaceRequiredBefore(const 
AnnotatedLine &Line,
     return false;
   }
   if (Right.is(tok::coloncolon) && Left.is(tok::identifier)) {
-    // 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.hasWhitespaceBefore();
+    // Preserve the space in constructs such as ALWAYS_INLINE ::std::string.
+    return isPossibleMacro(Left) && Right.hasWhitespaceBefore();
   }
   if (Right.is(tok::coloncolon) &&
       Left.isNoneOf(tok::l_brace, tok::comment, tok::l_paren)) {
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 2701a7fca7346..6cb28f2c98c2a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -80,6 +80,8 @@ TEST_F(FormatTest, NestedNameSpecifiers) {
   verifyFormat("static constexpr bool Bar = _Atomic(bar())::value;");
   verifyFormat("bool a = 2 < ::SomeFunction();");
   verifyFormat("ALWAYS_INLINE ::std::string getName();");
+  verifyFormat("template <typename T> auto mem = &T::member;",
+               "template <typename T> auto mem = &T :: member;");
   verifyFormat("some::string getName();");
 }
 

``````````

</details>


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

Reply via email to