Skip to content

[clang-tidy] fix false positives for bugprone-macro-parentheses in C++ templates#174329

Merged
zeyi2 merged 4 commits intollvm:mainfrom
zeyi2:91155
Jan 7, 2026
Merged

[clang-tidy] fix false positives for bugprone-macro-parentheses in C++ templates#174329
zeyi2 merged 4 commits intollvm:mainfrom
zeyi2:91155

Conversation

@zeyi2
Copy link
Member

@zeyi2 zeyi2 commented Jan 4, 2026

Closes #91155

@llvmbot
Copy link
Member

llvmbot commented Jan 4, 2026

@llvm/pr-subscribers-clang-tidy

Author: mitchell (zeyi2)

Changes

Closes #91155


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

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp (+13-4)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+9-5)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp (+17)
diff --git a/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
index 6467fb58de925..dc677ba7dc58d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
@@ -52,7 +52,8 @@ static bool isSurroundedRight(const Token &T) {
 /// Is given TokenKind a keyword?
 static bool isKeyword(const Token &T) {
   // FIXME: better matching of keywords to avoid false positives.
-  return T.isOneOf(tok::kw_if, tok::kw_case, tok::kw_const, tok::kw_struct);
+  return T.isOneOf(tok::kw_if, tok::kw_case, tok::kw_const, tok::kw_volatile,
+                   tok::kw_struct);
 }
 
 /// Warning is written when one of these operators are not within parentheses.
@@ -235,9 +236,17 @@ void MacroParenthesesPPCallbacks::argument(const Token &MacroNameTok,
       continue;
 
     // C++ template parameters.
-    if (PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less) &&
-        Next.isOneOf(tok::comma, tok::greater))
-      continue;
+    if (PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less)) {
+      auto NextIt = TI + 1;
+      while (NextIt != MI->tokens_end() &&
+             NextIt->isOneOf(tok::star, tok::amp, tok::ampamp, tok::kw_const,
+                             tok::kw_volatile))
+        ++NextIt;
+
+      if (NextIt != MI->tokens_end() &&
+          NextIt->isOneOf(tok::comma, tok::greater))
+        continue;
+    }
 
     // Namespaces.
     if (Prev.is(tok::kw_namespace))
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 7d878f7d28386..b1b30baf26285 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -111,10 +111,10 @@ Hover
 Code completion
 ^^^^^^^^^^^^^^^
 
-- Added a new ``MacroFilter`` configuration option to ``Completion`` to 
-  allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting 
-  macros. ``ExactPrefix`` is the default, which retains previous 
-  behavior of suggesting macros which match the prefix exactly.  
+- Added a new ``MacroFilter`` configuration option to ``Completion`` to
+  allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting
+  macros. ``ExactPrefix`` is the default, which retains previous
+  behavior of suggesting macros which match the prefix exactly.
 
 Code actions
 ^^^^^^^^^^^^
@@ -205,7 +205,7 @@ Improvements to clang-tidy
 
 - Improved :program:`clang-tidy` by adding the `--removed-arg` option to remove
   arguments sent to the compiler when invoking Clang-Tidy. This option was also
-  added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and 
+  added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and
   can be configured in the config file through the `RemovedArgs` option.
 
 - Deprecated the :program:`clang-tidy` ``zircon`` module. All checks have been
@@ -392,6 +392,10 @@ Changes in existing checks
   <clang-tidy/checks/bugprone/invalid-enum-default-initialization>` with new
   `IgnoredEnums` option to ignore specified enums during analysis.
 
+- Improved :doc:`bugprone-macro-parentheses
+  <clang-tidy/checks/bugprone/macro-parentheses>` check by fixing false
+  positives when using C++ template parameters.
+
 - Improved :doc:`bugprone-narrowing-conversions
   <clang-tidy/checks/bugprone/narrowing-conversions>` check by fixing
   false positive from analysis of a conditional expression in C.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
index 6c2f42dd2dcd6..5897de03d8cec 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
@@ -54,3 +54,20 @@
 // These are allowed for now..
 #define MAYBE1            *12.34
 #define MAYBE2            <<3
+#define MAYBE3            a < b * c
+
+#define CAST1(type, p)    (reinterpret_cast<type*>(p))
+#define CAST2(type, p)    (static_cast<type*>(p))
+#define CAST3(type, p)    (const_cast<type*>(p))
+#define CAST4(type, p)    (dynamic_cast<type*>(p))
+#define CAST5(type, p)    (static_cast<type&>(p))
+#define CAST6(type, p)    (static_cast<type&&>(p))
+#define CAST7(type, p)    (static_cast<const type*>(p))
+#define CAST8(type, p)    (static_cast<volatile type*>(p))
+#define CAST9(type, p)    (static_cast<type const*>(p))
+#define CAST10(type, p)   (reinterpret_cast<type * const &>(p))
+
+#define TEMPLATE1(T)      (std::vector<T*>)
+#define TEMPLATE2(T)      (std::vector<T&>)
+#define TEMPLATE3(T)      (std::vector<const T*>)
+#define TEMPLATE4(T)      (std::map<T*, T*>)

@llvmbot
Copy link
Member

llvmbot commented Jan 4, 2026

@llvm/pr-subscribers-clang-tools-extra

Author: mitchell (zeyi2)

Changes

Closes #91155


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

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp (+13-4)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+9-5)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp (+17)
diff --git a/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
index 6467fb58de925..dc677ba7dc58d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
@@ -52,7 +52,8 @@ static bool isSurroundedRight(const Token &T) {
 /// Is given TokenKind a keyword?
 static bool isKeyword(const Token &T) {
   // FIXME: better matching of keywords to avoid false positives.
-  return T.isOneOf(tok::kw_if, tok::kw_case, tok::kw_const, tok::kw_struct);
+  return T.isOneOf(tok::kw_if, tok::kw_case, tok::kw_const, tok::kw_volatile,
+                   tok::kw_struct);
 }
 
 /// Warning is written when one of these operators are not within parentheses.
@@ -235,9 +236,17 @@ void MacroParenthesesPPCallbacks::argument(const Token &MacroNameTok,
       continue;
 
     // C++ template parameters.
-    if (PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less) &&
-        Next.isOneOf(tok::comma, tok::greater))
-      continue;
+    if (PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less)) {
+      auto NextIt = TI + 1;
+      while (NextIt != MI->tokens_end() &&
+             NextIt->isOneOf(tok::star, tok::amp, tok::ampamp, tok::kw_const,
+                             tok::kw_volatile))
+        ++NextIt;
+
+      if (NextIt != MI->tokens_end() &&
+          NextIt->isOneOf(tok::comma, tok::greater))
+        continue;
+    }
 
     // Namespaces.
     if (Prev.is(tok::kw_namespace))
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 7d878f7d28386..b1b30baf26285 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -111,10 +111,10 @@ Hover
 Code completion
 ^^^^^^^^^^^^^^^
 
-- Added a new ``MacroFilter`` configuration option to ``Completion`` to 
-  allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting 
-  macros. ``ExactPrefix`` is the default, which retains previous 
-  behavior of suggesting macros which match the prefix exactly.  
+- Added a new ``MacroFilter`` configuration option to ``Completion`` to
+  allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting
+  macros. ``ExactPrefix`` is the default, which retains previous
+  behavior of suggesting macros which match the prefix exactly.
 
 Code actions
 ^^^^^^^^^^^^
@@ -205,7 +205,7 @@ Improvements to clang-tidy
 
 - Improved :program:`clang-tidy` by adding the `--removed-arg` option to remove
   arguments sent to the compiler when invoking Clang-Tidy. This option was also
-  added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and 
+  added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and
   can be configured in the config file through the `RemovedArgs` option.
 
 - Deprecated the :program:`clang-tidy` ``zircon`` module. All checks have been
@@ -392,6 +392,10 @@ Changes in existing checks
   <clang-tidy/checks/bugprone/invalid-enum-default-initialization>` with new
   `IgnoredEnums` option to ignore specified enums during analysis.
 
+- Improved :doc:`bugprone-macro-parentheses
+  <clang-tidy/checks/bugprone/macro-parentheses>` check by fixing false
+  positives when using C++ template parameters.
+
 - Improved :doc:`bugprone-narrowing-conversions
   <clang-tidy/checks/bugprone/narrowing-conversions>` check by fixing
   false positive from analysis of a conditional expression in C.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
index 6c2f42dd2dcd6..5897de03d8cec 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/macro-parentheses.cpp
@@ -54,3 +54,20 @@
 // These are allowed for now..
 #define MAYBE1            *12.34
 #define MAYBE2            <<3
+#define MAYBE3            a < b * c
+
+#define CAST1(type, p)    (reinterpret_cast<type*>(p))
+#define CAST2(type, p)    (static_cast<type*>(p))
+#define CAST3(type, p)    (const_cast<type*>(p))
+#define CAST4(type, p)    (dynamic_cast<type*>(p))
+#define CAST5(type, p)    (static_cast<type&>(p))
+#define CAST6(type, p)    (static_cast<type&&>(p))
+#define CAST7(type, p)    (static_cast<const type*>(p))
+#define CAST8(type, p)    (static_cast<volatile type*>(p))
+#define CAST9(type, p)    (static_cast<type const*>(p))
+#define CAST10(type, p)   (reinterpret_cast<type * const &>(p))
+
+#define TEMPLATE1(T)      (std::vector<T*>)
+#define TEMPLATE2(T)      (std::vector<T&>)
+#define TEMPLATE3(T)      (std::vector<const T*>)
+#define TEMPLATE4(T)      (std::map<T*, T*>)

@github-actions
Copy link

github-actions bot commented Jan 4, 2026

✅ With the latest revision this PR passed the C/C++ code linter.

// These are allowed for now..
#define MAYBE1 *12.34
#define MAYBE2 <<3
#define MAYBE3 a < b * c
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may be an existing FN: https://clang-tidy.godbolt.org/z/GfcxqEvcb

@zeyi2 zeyi2 requested a review from vbvictor January 4, 2026 19:46
@zeyi2 zeyi2 requested a review from localspook January 6, 2026 05:15
@github-actions
Copy link

github-actions bot commented Jan 6, 2026

🪟 Windows x64 Test Results

  • 3015 tests passed
  • 29 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

🐧 Linux x64 Test Results

  • 3076 tests passed
  • 7 tests skipped

✅ The build succeeded and all tests passed.

@zeyi2 zeyi2 merged commit e8bf7e8 into llvm:main Jan 7, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wrong fix of clang-tidy bugprone-macro-parentheses

4 participants