<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/55049>55049</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [clang-tidy] modernize-macro-to-enum should insert enum declarations at appropriate scope
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            enhancement,
            clang-tidy
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
            LegalizeAdulthood
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          LegalizeAdulthood
      </td>
    </tr>
</table>

<pre>
    Suppose macros are defined within the body of a top-level declaration:

```
void f()
{
#define FOO1 1
#define FOO2 2
  // ... some code that may or may not use these macros
}

void g()
{
  if (FOO1 > 1) { /* ... */ }
}
```

Because macros don't respect any scope, switching `FOO1` and `FOO2` to an enum will cause function `g()` to fail to compile.

A good first pass is to simply ignore any macros that are defined within the source range of a top-level decl.  This implies that macros defined within the body of a class declaration won't be converted.  (See bug #54883)

A second pass is to examine the expansion locations of such macros and if they only occur within the top-level decl in which they are defined, then they are suitable for conversion to an enum.  However, you can't introduce enums just anywhere and have them visible to all the scopes in which the macros were expanded.  So after having determined that the expansion locations all reside within a suitable top-level decl, a suitable insertion point for the enum has to be determined such that all references to the enum are within scope of the declaration.

A tortured example will illustrate:

```
void g(int x)
{
    if (x > 1) {
#define FOO1 1
#define FOO2 2
    } else {
        h(FOO1);
        h(FOO2);
    }
}
```

If this were naively converted to an enum at the location of the macro definition, we would get:

```
void g(int x)
{
    if (x > 1) {
        enum {
            FOO1 = 1,
            FOO2 = 2
        };
    } else {
        h(FOO1);
        h(FOO2);
    }
}
```

and this code would fail to compile as [shown here on compiler explorer](https://godbolt.org/z/Ph6eeeccP).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy9VWFv4jgQ_TXhywhEHWjhAx_a7VZ70km7Uu8PmGRCvDJxZDtQ9tffGyeU0GVPq5PuEJDYY4_fvHkz3rrytHnt2tYFpr0uvAukPVPJlWm4pKOJtWko1kxbLCVXkabo2qnlA1ssK6z2OhrXZPljNn_O5uf_-_nwTcODMyVVmVplaj0seHgaXlTen0YvX7_e0d2NWUWqnyXK1Au-NJvNKLg9U-FKBjwdgR7wfHo0LlIXZJ7fwzqf-jxGmWDtbsIiMhVOWyVQWf4ZwNSaYO4hPCYIeAqai9f3l-vw-_8nLnR34bkEaeohkufQchFJNycKhWs5U58ogPkC1O8ITgQDHlhRDkMlw-gwQ9x0e-TJWuq9V11TSEJk5Tm0fnGljZVn4fatsTwbY3uknXNIkfEhUqtDIBNkbTD71p7I7BoHWQjEAX3i_BdSCa7zBZPXzY5vSWZG9FcN_-LbcDjnr2fln5QHtYUwVh0dBxK3IoXmwD5yOROZrF4ZOzvwp_LlYrXKLykeAg6MHeU4WH7Te5GcHMpvrW6CHGFdkc4KgiF0Rf1eKNgNkWA14DVgyRVF58fIr8MmzB5rAwdpy4g8yTjmmoshdCbqrUU6oek-sgTmknNE-cUd4dzL7pPrkP-eC9NE78oOGZB1gb53IanrWHPKYUm1PqQo93Qwwcgx4hcSStkTDYYrsOeIj-IgMVMmml-xq4rsxaFotWQM9il_Kae_IlKOguwNandgS18iviZNghsZTROQY_HWOsSZ6EmnSBXUOqVxy2MgKWO9WtOpFWJoCk4r33cK5QOSFL6kWowjqX0ol-h87Dz8i2hay30J4geysYF_ox9KdUoMb7e6z7n_vF01n3_TMkn6E7FFb7jyL5966HCCIL9tUx9tv9nt_hAGzaCZRhsk9HSp0XHzGoRylseZ-6S5vkJMumGghCN4dp0Fdxz_S4bPHCR8P83KZ7gXnmXjp5tmlczq2iacfSDz_0-NtICUm3R79oR-uBwIpZQtn0Ltjg2lvoHEDDYvNW1xH_hs-QwkdYxtkGyku3nnyq2zceY82H_5gd-3-p6Zi-Ib4M4m5SYv1_laT6KJljc4BCXW7KbRlCf4oz0w-cb84GkSwDS6acoCoAjOvgH0iRlVZxAV6bb1rvUG5deX8aTzdvMBHqq8284QCgbWHs6PKbZ-xzWMoQmh44CX5XK-WE_qDT_cz7c652W12M6LbZkXi1Wh7uZ3xfouX69WE6u3SKLEkinFTa3RYPbcwJkS1eIxihFzy-eJ2ai5UvOFUirP1SKfVRqDUi_WS17dL_MqW8x5j6TMBJ2wOfGbBBSXWoDRmhDDxYhbDJc08wDiT95pCxIfy87GGlf7cKzuMPKbn8yTFPQmRfw3gw8Ykg">