444 lines
15 KiB
C++
444 lines
15 KiB
C++
// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-macro-to-enum %t -- -- -I%S/Inputs/macro-to-enum -fno-delayed-template-parsing
|
|
// C++14 or later required for binary literals.
|
|
|
|
#if 1
|
|
#include "modernize-macro-to-enum.h"
|
|
|
|
// These macros are skipped due to being inside a conditional compilation block.
|
|
#define GOO_RED 1
|
|
#define GOO_GREEN 2
|
|
#define GOO_BLUE 3
|
|
|
|
#endif
|
|
|
|
// Macros expanding to expressions involving only literals are converted.
|
|
#define EXPR1 1 - 1
|
|
#define EXPR2 1 + 1
|
|
#define EXPR3 1 * 1
|
|
#define EXPR4 1 / 1
|
|
#define EXPR5 1 | 1
|
|
#define EXPR6 1 & 1
|
|
#define EXPR7 1 << 1
|
|
#define EXPR8 1 >> 1
|
|
#define EXPR9 1 % 2
|
|
#define EXPR10 1 ^ 1
|
|
#define EXPR11 (1 + (2))
|
|
#define EXPR12 ((1) + (2 + 0) + (1 * 1) + (1 / 1) + (1 | 1 ) + (1 & 1) + (1 << 1) + (1 >> 1) + (1 % 2) + (1 ^ 1))
|
|
// CHECK-MESSAGES: :[[@LINE-12]]:1: warning: replace macro with enum [modernize-macro-to-enum]
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR1' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR2' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR3' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR4' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR5' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR6' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR7' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR8' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR9' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR10' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR11' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-13]]:9: warning: macro 'EXPR12' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: EXPR1 = 1 - 1,
|
|
// CHECK-FIXES-NEXT: EXPR2 = 1 + 1,
|
|
// CHECK-FIXES-NEXT: EXPR3 = 1 * 1,
|
|
// CHECK-FIXES-NEXT: EXPR4 = 1 / 1,
|
|
// CHECK-FIXES-NEXT: EXPR5 = 1 | 1,
|
|
// CHECK-FIXES-NEXT: EXPR6 = 1 & 1,
|
|
// CHECK-FIXES-NEXT: EXPR7 = 1 << 1,
|
|
// CHECK-FIXES-NEXT: EXPR8 = 1 >> 1,
|
|
// CHECK-FIXES-NEXT: EXPR9 = 1 % 2,
|
|
// CHECK-FIXES-NEXT: EXPR10 = 1 ^ 1,
|
|
// CHECK-FIXES-NEXT: EXPR11 = (1 + (2)),
|
|
// CHECK-FIXES-NEXT: EXPR12 = ((1) + (2 + 0) + (1 * 1) + (1 / 1) + (1 | 1 ) + (1 & 1) + (1 << 1) + (1 >> 1) + (1 % 2) + (1 ^ 1))
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
#define RED 0xFF0000
|
|
#define GREEN 0x00FF00
|
|
#define BLUE 0x0000FF
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:1: warning: replace macro with enum [modernize-macro-to-enum]
|
|
// CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'RED' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'GREEN' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'BLUE' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: RED = 0xFF0000,
|
|
// CHECK-FIXES-NEXT: GREEN = 0x00FF00,
|
|
// CHECK-FIXES-NEXT: BLUE = 0x0000FF
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
// Verify that comments are preserved.
|
|
#define CoordModeOrigin 0 /* relative to the origin */
|
|
#define CoordModePrevious 1 /* relative to previous point */
|
|
// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'CoordModeOrigin' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'CoordModePrevious' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: CoordModeOrigin = 0, /* relative to the origin */
|
|
// CHECK-FIXES-NEXT: CoordModePrevious = 1 /* relative to previous point */
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
// Verify that multiline comments are preserved.
|
|
#define BadDrawable 9 /* parameter not a Pixmap or Window */
|
|
#define BadAccess 10 /* depending on context:
|
|
- key/button already grabbed
|
|
- attempt to free an illegal
|
|
cmap entry
|
|
- attempt to store into a read-only
|
|
color map entry. */
|
|
// - attempt to modify the access control
|
|
// list from other than the local host.
|
|
//
|
|
#define BadAlloc 11 /* insufficient resources */
|
|
// CHECK-MESSAGES: :[[@LINE-11]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-12]]:9: warning: macro 'BadDrawable' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-12]]:9: warning: macro 'BadAccess' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-4]]:9: warning: macro 'BadAlloc' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: BadDrawable = 9, /* parameter not a Pixmap or Window */
|
|
// CHECK-FIXES-NEXT: BadAccess = 10, /* depending on context:
|
|
// CHECK-FIXES-NEXT: - key/button already grabbed
|
|
// CHECK-FIXES-NEXT: - attempt to free an illegal
|
|
// CHECK-FIXES-NEXT: cmap entry
|
|
// CHECK-FIXES-NEXT: - attempt to store into a read-only
|
|
// CHECK-FIXES-NEXT: color map entry. */
|
|
// CHECK-FIXES-NEXT: // - attempt to modify the access control
|
|
// CHECK-FIXES-NEXT: // list from other than the local host.
|
|
// CHECK-FIXES-NEXT: //
|
|
// CHECK-FIXES-NEXT: BadAlloc = 11 /* insufficient resources */
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
// Undefining a macro invalidates adjacent macros
|
|
// from being considered as an enum.
|
|
#define REMOVED1 1
|
|
#define REMOVED2 2
|
|
#define REMOVED3 3
|
|
#undef REMOVED2
|
|
#define VALID1 1
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: macro 'VALID1' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: VALID1 = 1
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
#define UNDEF1 1
|
|
#define UNDEF2 2
|
|
#define UNDEF3 3
|
|
|
|
// Undefining a macro later invalidates the set of possible adjacent macros
|
|
// from being considered as an enum.
|
|
#undef UNDEF2
|
|
|
|
// Integral constants can have an optional sign
|
|
#define SIGNED1 +1
|
|
#define SIGNED2 -1
|
|
// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'SIGNED1' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'SIGNED2' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: SIGNED1 = +1,
|
|
// CHECK-FIXES-NEXT: SIGNED2 = -1
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
// Integral constants with bitwise negated values
|
|
#define UNOP1 ~0U
|
|
#define UNOP2 ~1U
|
|
// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'UNOP1' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-3]]:9: warning: macro 'UNOP2' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: UNOP1 = ~0U,
|
|
// CHECK-FIXES-NEXT: UNOP2 = ~1U
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
// Integral constants in other bases and with suffixes are OK
|
|
#define BASE1 0777 // octal
|
|
#define BASE2 0xDEAD // hexadecimal
|
|
#define BASE3 0b0011 // binary
|
|
#define SUFFIX1 +1U
|
|
#define SUFFIX2 -1L
|
|
#define SUFFIX3 +1UL
|
|
#define SUFFIX4 -1LL
|
|
#define SUFFIX5 +1ULL
|
|
// CHECK-MESSAGES: :[[@LINE-8]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'BASE1' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'BASE2' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'BASE3' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX1' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX2' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX3' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX4' defines an integral constant; prefer an enum instead
|
|
// CHECK-MESSAGES: :[[@LINE-9]]:9: warning: macro 'SUFFIX5' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: BASE1 = 0777, // octal
|
|
// CHECK-FIXES-NEXT: BASE2 = 0xDEAD, // hexadecimal
|
|
// CHECK-FIXES-NEXT: BASE3 = 0b0011, // binary
|
|
// CHECK-FIXES-NEXT: SUFFIX1 = +1U,
|
|
// CHECK-FIXES-NEXT: SUFFIX2 = -1L,
|
|
// CHECK-FIXES-NEXT: SUFFIX3 = +1UL,
|
|
// CHECK-FIXES-NEXT: SUFFIX4 = -1LL,
|
|
// 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: };
|
|
|
|
#define GOOD_COMMA (1, 2)
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: replace macro with enum
|
|
// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: macro 'GOOD_COMMA' defines an integral constant; prefer an enum instead
|
|
// CHECK-FIXES: enum {
|
|
// CHECK-FIXES-NEXT: GOOD_COMMA = (1, 2)
|
|
// CHECK-FIXES-NEXT: };
|
|
|
|
// Macros appearing in conditional expressions can't be replaced
|
|
// by enums.
|
|
#define USE_FOO 1
|
|
#define USE_BAR 0
|
|
#define USE_IF 1
|
|
#define USE_ELIF 1
|
|
#define USE_IFDEF 1
|
|
#define USE_IFNDEF 1
|
|
|
|
// Undef'ing first and then defining later should still exclude this macro
|
|
#undef USE_UINT64
|
|
#define USE_UINT64 0
|
|
#undef USE_INT64
|
|
#define USE_INT64 0
|
|
|
|
#if defined(USE_FOO) && USE_FOO
|
|
extern void foo();
|
|
#else
|
|
inline void foo() {}
|
|
#endif
|
|
|
|
#if USE_BAR
|
|
extern void bar();
|
|
#else
|
|
inline void bar() {}
|
|
#endif
|
|
|
|
#if USE_IF
|
|
inline void used_if() {}
|
|
#endif
|
|
|
|
#if 0
|
|
#elif USE_ELIF
|
|
inline void used_elif() {}
|
|
#endif
|
|
|
|
#ifdef USE_IFDEF
|
|
inline void used_ifdef() {}
|
|
#endif
|
|
|
|
#ifndef USE_IFNDEF
|
|
#else
|
|
inline void used_ifndef() {}
|
|
#endif
|
|
|
|
// Regular conditional compilation blocks should leave previous
|
|
// macro enums alone.
|
|
#if 0
|
|
#include <non-existent.h>
|
|
#endif
|
|
|
|
// Conditional compilation blocks invalidate adjacent macros
|
|
// from being considered as an enum. Conditionally compiled
|
|
// blocks could contain macros that should rightly be included
|
|
// in the enum, but we can't explore multiple branches of a
|
|
// conditionally compiled section in clang-tidy, only the active
|
|
// branch based on compilation options.
|
|
#define CONDITION1 1
|
|
#define CONDITION2 2
|
|
#if 0
|
|
#define CONDITION3 3
|
|
#else
|
|
#define CONDITION3 -3
|
|
#endif
|
|
|
|
#define IFDEF1 1
|
|
#define IFDEF2 2
|
|
#ifdef FROB
|
|
#define IFDEF3 3
|
|
#endif
|
|
|
|
#define IFNDEF1 1
|
|
#define IFNDEF2 2
|
|
#ifndef GOINK
|
|
#define IFNDEF3 3
|
|
#endif
|
|
|
|
// Macros used in conditions are invalidated, even if they look
|
|
// like enums after they are used in conditions.
|
|
#if DEFINED_LATER1
|
|
#endif
|
|
#ifdef DEFINED_LATER2
|
|
#endif
|
|
#ifndef DEFINED_LATER3
|
|
#endif
|
|
#undef DEFINED_LATER4
|
|
#if ((defined(DEFINED_LATER5) || DEFINED_LATER6) && DEFINED_LATER7) || (DEFINED_LATER8 > 10)
|
|
#endif
|
|
|
|
#define DEFINED_LATER1 1
|
|
#define DEFINED_LATER2 2
|
|
#define DEFINED_LATER3 3
|
|
#define DEFINED_LATER4 4
|
|
#define DEFINED_LATER5 5
|
|
#define DEFINED_LATER6 6
|
|
#define DEFINED_LATER7 7
|
|
#define DEFINED_LATER8 8
|
|
|
|
// Sometimes an argument to ifdef can be classified as a keyword token.
|
|
#ifdef __restrict
|
|
#endif
|
|
|
|
// These macros do not expand to integral constants.
|
|
#define HELLO "Hello, "
|
|
#define WORLD "World"
|
|
#define EPS1 1.0F
|
|
#define EPS2 1e5
|
|
#define EPS3 1.
|
|
|
|
// Ignore macros invoking comma operator unless they are inside parens.
|
|
#define BAD_COMMA 1, 2
|
|
|
|
extern void draw(unsigned int Color);
|
|
|
|
void f()
|
|
{
|
|
// Usage of macros converted to enums should still compile.
|
|
draw(RED);
|
|
draw(GREEN | RED);
|
|
draw(BLUE + RED);
|
|
}
|
|
|
|
// Ignore macros defined inside a top-level function definition.
|
|
void g(int x)
|
|
{
|
|
if (x != 0) {
|
|
#define INSIDE1 1
|
|
#define INSIDE2 2
|
|
if (INSIDE1 > 1) {
|
|
f();
|
|
}
|
|
} else {
|
|
if (INSIDE2 == 1) {
|
|
f();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ignore macros defined inside a top-level function declaration.
|
|
extern void g2(
|
|
#define INSIDE3 3
|
|
#define INSIDE4 4
|
|
);
|
|
|
|
// Ignore macros defined inside a record (structure) declaration.
|
|
struct S {
|
|
#define INSIDE5 5
|
|
#define INSIDE6 6
|
|
char storage[INSIDE5];
|
|
};
|
|
class C {
|
|
#define INSIDE7 7
|
|
#define INSIDE8 8
|
|
};
|
|
|
|
// Ignore macros defined inside a template function definition.
|
|
template <int N>
|
|
#define INSIDE9 9
|
|
bool fn()
|
|
{
|
|
#define INSIDE10 10
|
|
return INSIDE9 > 1 || INSIDE10 < N;
|
|
}
|
|
|
|
// Ignore macros defined inside a variable declaration.
|
|
extern int
|
|
#define INSIDE11 11
|
|
v;
|
|
|
|
// Ignore macros defined inside a template class definition.
|
|
template <int N>
|
|
class C2 {
|
|
public:
|
|
#define INSIDE12 12
|
|
char storage[N];
|
|
bool f() {
|
|
return N > INSIDE12;
|
|
}
|
|
bool g();
|
|
};
|
|
|
|
// Ignore macros defined inside a template member function definition.
|
|
template <int N>
|
|
#define INSIDE13 13
|
|
bool C2<N>::g() {
|
|
#define INSIDE14 14
|
|
return N < INSIDE12 || N > INSIDE13 || INSIDE14 > N;
|
|
};
|
|
|
|
// Ignore macros defined inside a template type alias.
|
|
template <typename T>
|
|
class C3 {
|
|
T data;
|
|
};
|
|
template <typename T>
|
|
#define INSIDE15 15
|
|
using Data = C3<T[INSIDE15]>;
|
|
|
|
// Ignore macros defined inside a type alias.
|
|
using Data2 =
|
|
#define INSIDE16 16
|
|
char[INSIDE16];
|
|
|
|
// Ignore macros defined inside a (constexpr) variable definition.
|
|
constexpr int
|
|
#define INSIDE17 17
|
|
value = INSIDE17;
|
|
|
|
// Ignore macros used in the expansion of other macros
|
|
#define INSIDE18 18
|
|
#define INSIDE19 19
|
|
|
|
#define CONCAT(n_, s_) n_##s_
|
|
#define FN_NAME(n_, s_) CONCAT(n_, s_)
|
|
|
|
extern void FN_NAME(g, INSIDE18)();
|
|
|
|
void gg()
|
|
{
|
|
g18();
|
|
}
|