[clang-tools-extra] d563c2d - [clang-tidy] Support parenthesized literals in modernize-macro-to-enum

via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 11 13:08:46 PDT 2022


Author: Richard
Date: 2022-04-11T14:06:48-06:00
New Revision: d563c2d0e52a738ab2038db02a76dc4c27ec7124

URL: https://github.com/llvm/llvm-project/commit/d563c2d0e52a738ab2038db02a76dc4c27ec7124
DIFF: https://github.com/llvm/llvm-project/commit/d563c2d0e52a738ab2038db02a76dc4c27ec7124.diff

LOG: [clang-tidy] Support parenthesized literals in modernize-macro-to-enum

When scanning a macro expansion to examine it as a candidate enum,
first strip off arbitrary matching parentheses from the outside in,
then examine what remains to see if it is Lit, +Lit, -Lit or ~Lit.
If not, reject it as a possible enum candidate.

Differential Revision: https://reviews.llvm.org/D123479

Fixes #54843

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
    clang-tools-extra/docs/clang-tidy/checks/modernize-macro-to-enum.rst
    clang-tools-extra/test/clang-tidy/checkers/modernize-macro-to-enum.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
index b2d59adc9a556..318b86be982b9 100644
--- a/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MacroToEnumCheck.cpp
@@ -324,18 +324,51 @@ void MacroToEnumCallbacks::MacroDefined(const Token &MacroNameTok,
     return;
 
   const MacroInfo *Info = MD->getMacroInfo();
-  if (Info->isFunctionLike() || Info->isBuiltinMacro() ||
-      Info->tokens().empty() || Info->tokens().size() > 2)
+  ArrayRef<Token> MacroTokens = Info->tokens();
+  if (Info->isFunctionLike() || Info->isBuiltinMacro() || MacroTokens.empty())
     return;
 
-  // It can be +Lit, -Lit or just Lit.
-  Token Tok = Info->tokens().front();
-  if (Info->tokens().size() == 2) {
-    if (!Tok.isOneOf(tok::TokenKind::minus, tok::TokenKind::plus,
-                     tok::TokenKind::tilde))
+  // Return Lit when +Lit, -Lit or ~Lit; otherwise return Unknown.
+  Token Unknown;
+  Unknown.setKind(tok::TokenKind::unknown);
+  auto GetUnopArg = [Unknown](Token First, Token Second) {
+    return First.isOneOf(tok::TokenKind::minus, tok::TokenKind::plus,
+                         tok::TokenKind::tilde)
+               ? Second
+               : Unknown;
+  };
+
+  // It could just be a single token.
+  Token Tok = MacroTokens.front();
+
+  // It can be any arbitrary nesting of matched parentheses around
+  // +Lit, -Lit, ~Lit or Lit.
+  if (MacroTokens.size() > 2) {
+    // Strip off matching '(', ..., ')' token pairs.
+    size_t Begin = 0;
+    size_t End = MacroTokens.size() - 1;
+    assert(End >= 2U);
+    for (; Begin < MacroTokens.size() / 2; ++Begin, --End) {
+      if (!MacroTokens[Begin].is(tok::TokenKind::l_paren) ||
+          !MacroTokens[End].is(tok::TokenKind::r_paren))
+        break;
+    }
+    size_t Size = End >= Begin ? (End - Begin + 1U) : 0U;
+
+    // It was a single token inside matching parens.
+    if (Size == 1)
+      Tok = MacroTokens[Begin];
+    else if (Size == 2)
+      // It can be +Lit, -Lit or ~Lit.
+      Tok = GetUnopArg(MacroTokens[Begin], MacroTokens[End]);
+    else
+      // Zero or too many tokens after we stripped matching parens.
       return;
-    Tok = Info->tokens().back();
+  } else if (MacroTokens.size() == 2) {
+    // It can be +Lit, -Lit, or ~Lit.
+    Tok = GetUnopArg(MacroTokens.front(), MacroTokens.back());
   }
+
   if (!Tok.isLiteral() || isStringLiteral(Tok.getKind()) ||
       !isIntegralConstant(Tok))
     return;

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/modernize-macro-to-enum.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize-macro-to-enum.rst
index 6be406544ba87..d7784419faa1f 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize-macro-to-enum.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize-macro-to-enum.rst
@@ -14,10 +14,12 @@ within the constraints outlined below.
 
 Potential macros for replacement must meet the following constraints:
 
-- Macros must expand only to integral literal tokens.  The unary operators
-  plus, minus and tilde are recognized to allow for positive, negative
-  and bitwise negated integers.  More complicated integral constant
-  expressions are not currently recognized by this check.
+- Macros must expand only to integral literal tokens or simple expressions
+  of literal tokens.  The unary operators plus, minus and tilde are
+  recognized to allow for positive, negative and bitwise negated integers.
+  The above expressions may also be surrounded by matching pairs of
+  parentheses.  More complicated integral constant expressions are not
+  recognized by this check.
 - Macros must be defined on sequential source file lines, or with
   only comment lines in between macro definitions.
 - Macros must all be defined in the same source file.
@@ -43,6 +45,7 @@ Examples:
   #define GREEN 0x00FF00
   #define BLUE  0x0000FF
 
+  #define TM_NONE (-1) // No method selected.
   #define TM_ONE 1    // Use tailored method one.
   #define TM_TWO 2    // Use tailored method two.  Method two
                       // is preferable to method one.
@@ -59,6 +62,7 @@ becomes
   };
 
   enum {
+  TM_NONE = (-1), // No method selected.
   TM_ONE = 1,    // Use tailored method one.
   TM_TWO = 2,    // Use tailored method two.  Method two
                       // is preferable to method one.

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-macro-to-enum.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-macro-to-enum.cpp
index 37122cfc61b9e..7727ce0e3a604 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize-macro-to-enum.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-macro-to-enum.cpp
@@ -137,6 +137,41 @@
 // CHECK-FIXES-NEXT: SUFFIX5 = +1ULL
 // CHECK-FIXES-NEXT: };
 
+// A limited form of constant expression is recognized: a parenthesized
+// literal or a parenthesized literal with the unary operators +, - or ~.
+#define PAREN1 (-1)
+#define PAREN2 (1)
+#define PAREN3 (+1)
+#define PAREN4 (~1)
+// CHECK-MESSAGES: :[[@LINE-4]]:1: warning: replace macro with enum
+// CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN1' defines an integral constant; prefer an enum instead
+// CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN2' defines an integral constant; prefer an enum instead
+// CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN3' defines an integral constant; prefer an enum instead
+// CHECK-MESSAGES: :[[@LINE-5]]:9: warning: macro 'PAREN4' defines an integral constant; prefer an enum instead
+// CHECK-FIXES: enum {
+// CHECK-FIXES-NEXT: PAREN1 = (-1),
+// CHECK-FIXES-NEXT: PAREN2 = (1),
+// CHECK-FIXES-NEXT: PAREN3 = (+1),
+// CHECK-FIXES-NEXT: PAREN4 = (~1)
+// CHECK-FIXES-NEXT: };
+
+// More complicated parenthesized expressions are excluded.
+// Expansions that are not surrounded by parentheses are excluded.
+// Nested matching parentheses are stripped.
+#define COMPLEX_PAREN1 (x+1)
+#define COMPLEX_PAREN2 (x+1
+#define COMPLEX_PAREN3 (())
+#define COMPLEX_PAREN4 ()
+#define COMPLEX_PAREN5 (+1)
+#define COMPLEX_PAREN6 ((+1))
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
+// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'COMPLEX_PAREN5' defines an integral constant; prefer an enum instead
+// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'COMPLEX_PAREN6' defines an integral constant; prefer an enum instead
+// CHECK-FIXES: enum {
+// CHECK-FIXES-NEXT: COMPLEX_PAREN5 = (+1),
+// CHECK-FIXES-NEXT: COMPLEX_PAREN6 = ((+1))
+// CHECK-FIXES-NEXT: };
+
 // Macros appearing in conditional expressions can't be replaced
 // by enums.
 #define USE_FOO 1


        


More information about the cfe-commits mailing list