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