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

    <tr>
        <th>Summary</th>
        <td>
            Odd (or perhaps inconsistent) behavior around `IgnoreUnlessSpelledInSource`
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:tooling
      </td>
    </tr>

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

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

<pre>
    I'm noticing some odd behavior around the `IgnoreUnlessSpelledInSource` traversal mode, in particular when that mode changes.

---

Suppose we have the following source:

```c++
struct A {
    ~A();
};

struct B {
    explicit B(A);
};

void f() { B(A{}); }
```

For the sake of discussion, assume that the AST of the function `f` is as follows:

```
α FunctionDecl <line:9:1, col:20> col:6 f 'void ()'
β `-CompoundStmt <col:10, col:20>
γ   `-ExprWithCleanups <col:12, col:17> 'B'
δ     `-CXXFunctionalCastExpr <col:12, col:17> 'B' functional cast to B <ConstructorConversion>
ε       `-CXXConstructExpr <col:12, col:17> 'B' 'void (A)'
ζ         `-CXXFunctionalCastExpr <col:14, col:16> 'A' functional cast to A <NoOp>
η           `-CXXBindTemporaryExpr <col:15, col:16> 'A' (CXXTemporary 0xc230d88)
θ             `-InitListExpr <col:15, col:16> 'A'
```

The AST nodes `ε`, `ζ`, and `θ` are "spelled in source" by the definition of `expr->IgnoreUnlessSpelledInSource() == expr`.

We look at some matchers and what nodes they match.

---
```
cxxConstructExpr()
```
We match the `CXXConstructExpr`. Nothing surprising.

---
```
traverse(TK_IgnoreUnlessSpelledInSource, cxxConstructExpr())
```
We match the `CXXConstructExpr`. Again, nothing surprising.

---
```
expr(traverse(TK_IgnoreUnlessSpelledInSource, cxxConstructExpr()))
```
We match the `CXXConstructExpr`. From my perspective, this is matching `expr` in the `AsIs` traversal mode, switching to `IgnoreUnlessSpelledInSource`, and then refining the match to `CXXConstructExpr`s that are spelled in source. Given that understanding, the result makes sense.

---
```
expr(anyOf(expr(traverse(clang::TK_IgnoreUnlessSpelledInSource,
                         cxxConstructExpr())),
           unless(anything())))
```
Notes regarding the matcher:
  * `anyOf` doesn't allow me to only provide a single argument, so I'm using `unless(anything())` to match nothing.
  * The outermost `expr` is to resolve an ambiguous call to `MatchFinder::addMatcher`.

We match the `CXXConstructExpr`... *three* times. For each of `γ`, `δ`, and `ε`, the `traverse` matcher ignores the nodes not spelled in source and ends up passing the `CXXConstructExpr` to its inner matchers.

>From my perspective, this matcher is no different than the previous matcher, where without any traversal matchers (referencing the categorization in the [AST Matcher Reference](https://clang.llvm.org/docs/LibASTMatchersReference.html), not the `traverse` matcher), the node matchers are refining the current node.

---

Perhaps this not a good idea to do. However, when writing generic utilities that allow arbitrary matchers to be composed, it's a question that needs to be answered. In particular, the path that led me to this rabbit trail was `clang::tooling::Transformer` and its `RewriteRule`s.

https://github.com/llvm/llvm-project/blob/0c032fd5425d853dfc577e607b9c179d811cec19/clang/lib/Tooling/Transformer/RewriteRule.cpp#L425-L438

When a `RewriteRule` composes its matchers, it does so with a variadic `AnyOf` matcher. A user writing something like

```
makeRule(traverse(clang::TK_IgnoreUnlessSpelledInSource,
                  cxxConstructExpr().bind("ctor")),
         insertBefore(node("ctor"), cat("/*hi*/")))
```

inadvertently trips over this, matching multiple times where it seems like it should only match once.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysWFtz27oR_jXQy441FKjrgx4kOWrd5iSd2J3krQMCKxENCLAAKNl96G_vLEjKki9KzjnJeBSS4t6__XYhEYLeW8Qlm6zZ5HYgmlg6v4x_Q4t-UDj1tLxjfFaBdVFLbfcQXIXglIICS3HQzoPwrrEKYonAptnd3jqP_7QGQ7iv0RhUd_beNV4im2YQvTigD8JA5RQyvgFtoRY-atkY4eFYooVYipi-B1kKu8cwZNkty1bt583NzfntfVPXLiAcEUpxwOTHzhnjjq27yXK-Ohdh06z9k4yv6S89DdE3MsIK2Kx7AgDwvxXjc8YXLO8estnt8_W54PpSEB9ro6WOsGZ8vrqu4eC0gl1riLR0MrM1vZokga4unT9XsHU-BR7EdwS3A6WDbELQzlKKRQhNhW1a6a3V_QO9lDLVWBm1s1S6HRVIBxChS2B4L2_d7eYDW49g26m4RWmA5RujLSV8wfLViKxLZ1i-4hnLP3TXU9gB47MUdZddPjvTycmbm42rakLWfawi6W1lR9kLnWdyOUCS_PBY-686lhuDwjZ1OJPmz9KjGXnE-Gx9aX1M1Ws9-PatD06YjQiRFP-EslNWhQEpQoToCB35ZuNsCxbnN85SI1CFLmKYAJzbP0n8rOmzvK5eJXYKcKn-anjjMxvTzsbqnfBWJPfJfa4vo5kBvDS51lY9YFU7L_zTC4uT9ywyPt98-3YSg-xR8jxT84SdZ3NzgBcG76yOH_Wr0N4zdKXFHrrGsU5hIN1tueiCb0730-5eWHV6Nqe-Eh6BcR5aSiTW66iJcyieUi8q3GmrUze6HUnjY-1vWP7hGqd2nJHfsvyWOMezaXZBl18RjHPfQcSWuysRZYk-JBePRAltRLHEp_bLd9j2Miny8fECm10fv_Xq185oPyJewpo8hk8ulomwG197HbTd_5Qb3TyhPDz8_V9XE7WBd3z-M26v9kInjrV_zH9s3fhFYfyZSLbeVVA9QY0-1CijPiRjsdSBhkJSQAF2uEyzwvYaV-EuvD3ew1F3gtH9eD_oWyfSGuBTP5BkeQrAveN_aKcbddmrFhvCX_ShXysaq9CHKKzSdt8GiOAxNCZCJb5jgIA24O8pnrBPn2l4v66lNMLuaYjmqx-W9XlzePPf1aK_Id0kM613CZmXAm8D5ZOLGMDjXnh1kXj0p1UAgPEVVaENe5qBchgs47MIgrYGoFXDgbPmCWrvDlohCKCOMAjC75sKbUzQcNAul03ogHXFaQKX61DQ9drw3CGiZ9dE9JUL8QKkgQQ9BmcOCMKCqAq9b1wTQApjOkj9Roq3msDR1kso9VsX-WtC_WE3DYfkVCw9IjkXdYVhCLSloZBlR-_tzvJigIzfGCD9kOkMngA2zfrqgE7YSize8bl18XUrJLVoVYCmhpq2_67Kb8dBydExgLYW_WlyXGTjGm2cnCNvQOndDj1a2kFFyxy1x4OmSvQg4xs6AXiEo46layII-3ROKv3sYnzuMWmTfQRSRNw7r_8r0gTtuWmypqHdlRK-dELIJreMz8sY67Tk8i3j29StQ2MO1dD5PeNb5WRgfPtRF6v7h05FOKkYlrEybfelZL9fne6lvjZnI9jjJcvJxqcM0WvXDj3_QF-KOrRpJuMC9s4p0AoFFU25IfzVHfFwyqmFo9eR7OzpbKclNFEbHTX21Jl6V_hCx7RinZyMDgoESdt4QJWObJHxWQAB_2kwpGwnDRZR9a8LG47oUQ3h7vx816ehFrFshQieLWGkWLwoCh2p5NrAUaRF64xFo3NGnyjVCxt2zlepRxO0Caxsmn1BCha_NIbKcAnYy5rvdSybYihdxfiWSt_9d1N792-UkfFtYVzB-DaTWc53ajLmEzWf5GonJ7MZTrNZsZCj2ULNRyOJcrTogUSKNAk-dD7z7bnDfHvm5FDWNeP5xzGf3Hwc5_MLuqHaiddR9RUJKei-Wm15EiUTv1IbgYCD8FooLdOo7mm7ExnCCpqA_oQP2hLbXcbo73jl_EfjMjnzy2fe28NuWGir0iWnExTj_L3xp21AH9e4c55csmkXeSm3IcpoHycsrErNeAsLfn1Mtp_aCnVAH9FGQySl6wDugD4BmdSfVqaqMVHXBts50DGcjhAQq5CynO5K1xjVzs12wDhimYFa5mqRL8QAl6PZKF9k-WSaDcpltijy0a4Yi_lozjGbToSQUo53nC92ucjzgV7yjI-zMc95NlrwbLibzVSRZxOVF7s5judsnGEltDlx3kCH0OByvpjz0cCIAk1Ivwxx3le1b0DO2eR24JepV4pmH9g4MzrE8Kwr6mhw-Vmls6jzNCESZ2krnQ06xLQGLF79kPTDJXHQeLP83W2cQiM6T9H9PwAA__9IWMzz">