xref: /llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize/macro-to-enum.rst (revision 6e566bc5523f743bc34a7e26f050f1f2b4d699a8)
1*6e566bc5SRichard.. title:: clang-tidy - modernize-macro-to-enum
2*6e566bc5SRichard
3*6e566bc5SRichardmodernize-macro-to-enum
4*6e566bc5SRichard=======================
5*6e566bc5SRichard
6*6e566bc5SRichardReplaces groups of adjacent macros with an unscoped anonymous enum.
7*6e566bc5SRichardUsing an unscoped anonymous enum ensures that everywhere the macro
8*6e566bc5SRichardtoken was used previously, the enumerator name may be safely used.
9*6e566bc5SRichard
10*6e566bc5SRichardThis check can be used to enforce the C++ core guideline `Enum.1:
11*6e566bc5SRichardPrefer enumerations over macros
12*6e566bc5SRichard<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#enum1-prefer-enumerations-over-macros>`_,
13*6e566bc5SRichardwithin the constraints outlined below.
14*6e566bc5SRichard
15*6e566bc5SRichardPotential macros for replacement must meet the following constraints:
16*6e566bc5SRichard
17*6e566bc5SRichard- Macros must expand only to integral literal tokens or expressions
18*6e566bc5SRichard  of literal tokens.  The expression may contain any of the unary
19*6e566bc5SRichard  operators ``-``, ``+``, ``~`` or ``!``, any of the binary operators
20*6e566bc5SRichard  ``,``, ``-``, ``+``, ``*``, ``/``, ``%``, ``&``, ``|``, ``^``, ``<``,
21*6e566bc5SRichard  ``>``, ``<=``, ``>=``, ``==``, ``!=``, ``||``, ``&&``, ``<<``, ``>>``
22*6e566bc5SRichard  or ``<=>``, the ternary operator ``?:`` and its
23*6e566bc5SRichard  `GNU extension <https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html>`_.
24*6e566bc5SRichard  Parenthesized expressions are also recognized.  This recognizes
25*6e566bc5SRichard  most valid expressions.  In particular, expressions with the
26*6e566bc5SRichard  ``sizeof`` operator are not recognized.
27*6e566bc5SRichard- Macros must be defined on sequential source file lines, or with
28*6e566bc5SRichard  only comment lines in between macro definitions.
29*6e566bc5SRichard- Macros must all be defined in the same source file.
30*6e566bc5SRichard- Macros must not be defined within a conditional compilation block.
31*6e566bc5SRichard  (Conditional include guards are exempt from this constraint.)
32*6e566bc5SRichard- Macros must not be defined adjacent to other preprocessor directives.
33*6e566bc5SRichard- Macros must not be used in any conditional preprocessing directive.
34*6e566bc5SRichard- Macros must not be used as arguments to other macros.
35*6e566bc5SRichard- Macros must not be undefined.
36*6e566bc5SRichard- Macros must be defined at the top-level, not inside any declaration or
37*6e566bc5SRichard  definition.
38*6e566bc5SRichard
39*6e566bc5SRichardEach cluster of macros meeting the above constraints is presumed to
40*6e566bc5SRichardbe a set of values suitable for replacement by an anonymous enum.
41*6e566bc5SRichardFrom there, a developer can give the anonymous enum a name and
42*6e566bc5SRichardcontinue refactoring to a scoped enum if desired.  Comments on the
43*6e566bc5SRichardsame line as a macro definition or between subsequent macro definitions
44*6e566bc5SRichardare preserved in the output.  No formatting is assumed in the provided
45*6e566bc5SRichardreplacements, although clang-tidy can optionally format all fixes.
46*6e566bc5SRichard
47*6e566bc5SRichard.. warning::
48*6e566bc5SRichard
49*6e566bc5SRichard  Initializing expressions are assumed to be valid initializers for
50*6e566bc5SRichard  an enum.  C requires that enum values fit into an ``int``, but
51*6e566bc5SRichard  this may not be the case for some accepted constant expressions.
52*6e566bc5SRichard  For instance ``1 << 40`` will not fit into an ``int`` when the size of
53*6e566bc5SRichard  an ``int`` is 32 bits.
54*6e566bc5SRichard
55*6e566bc5SRichardExamples:
56*6e566bc5SRichard
57*6e566bc5SRichard.. code-block:: c++
58*6e566bc5SRichard
59*6e566bc5SRichard  #define RED   0xFF0000
60*6e566bc5SRichard  #define GREEN 0x00FF00
61*6e566bc5SRichard  #define BLUE  0x0000FF
62*6e566bc5SRichard
63*6e566bc5SRichard  #define TM_NONE (-1) // No method selected.
64*6e566bc5SRichard  #define TM_ONE 1    // Use tailored method one.
65*6e566bc5SRichard  #define TM_TWO 2    // Use tailored method two.  Method two
66*6e566bc5SRichard                      // is preferable to method one.
67*6e566bc5SRichard  #define TM_THREE 3  // Use tailored method three.
68*6e566bc5SRichard
69*6e566bc5SRichardbecomes
70*6e566bc5SRichard
71*6e566bc5SRichard.. code-block:: c++
72*6e566bc5SRichard
73*6e566bc5SRichard  enum {
74*6e566bc5SRichard  RED = 0xFF0000,
75*6e566bc5SRichard  GREEN = 0x00FF00,
76*6e566bc5SRichard  BLUE = 0x0000FF
77*6e566bc5SRichard  };
78*6e566bc5SRichard
79*6e566bc5SRichard  enum {
80*6e566bc5SRichard  TM_NONE = (-1), // No method selected.
81*6e566bc5SRichard  TM_ONE = 1,    // Use tailored method one.
82*6e566bc5SRichard  TM_TWO = 2,    // Use tailored method two.  Method two
83*6e566bc5SRichard                      // is preferable to method one.
84*6e566bc5SRichard  TM_THREE = 3  // Use tailored method three.
85*6e566bc5SRichard  };
86