Getting multiple AST matches as a list

Hello,

I'm learning about how to use AST matchers, but one usecase is giving me headaches. I have a declaration like this:

const char *list = { "a", "b" };

and I would like to retrieve the array initializer as a list of strings in my matcher callback. I've managed to get a pointer to the InitListExpr which looks like this:

InitListExpr 0x46be670 'const char *[2]'
>-ImplicitCastExpr 0x46be6c0 'const char *' <ArrayToPointerDecay>
> `-StringLiteral 0x46be5b8 'const char [12]' lvalue "semihosting"
`-ImplicitCastExpr 0x46be6d8 'const char *' <ArrayToPointerDecay>
  `-StringLiteral 0x46be5f0 'const char [4]' lvalue "swo"

I've looked through the traversal matchers, but it seems like I can only get matchers which will generate a match for each element in the list. Is there any way to generate a single match with all elements wrapped up in a list?

/Jesper

Wouldn't binding the result of the initListExpr() give you access to the InitListExpr that you could get the items from? Or did you want something that was a little nicer?

Another option would be to bind to every child of the initListExpr() but then you don't get the matches all at once to your match callback. Rather the callback gets called once per child.

If you wanted every child at once, you'd need to bind a different name to each child. There's no way to do that currently. Or we'd need some mechanism to collect a bunch of matches under a single name.

Wouldn't binding the result of the initListExpr() give you access to the InitListExpr that you could get the items from? Or did you want something that was a little nicer?

How do I get out the value used in the initializer? I've tried finding a way to "evaluate" an "Expr *" and get out a value (if possible), but I cannot figure out what API to use to do that. I realize that it may not always be possible to find a value, but it's ok to bail out if the expression does not consist of (string) literals.

Ideally I'd like to be able to something like this:

    // Evaluate the initializer list

    std::vector<std::string> listOfInitializers = initListExpr->Evaluate(...);

Another option would be to bind to every child of the initListExpr() but then you don't get the matches all at once to your match callback. Rather the callback gets called once per child.

If you wanted every child at once, you'd need to bind a different name to each child. There's no way to do that currently. Or we'd need some mechanism to collect a bunch of matches under a single name.

I can't do that because I don't know how many children there are.

/Jesper

Hi,

The AST dump above clearly shows how the AST is structured, and that should be all the information you need.

Basically, you can see that the children of the InitListExpr are the nodes you’re interested in. So you bind the whole InitListExpr that you’re interested, and you iterate through its children. According to the AST dump, the actual StringLiteral nodes are wrapped by ImplicitCastExpr-s - a phenomenon that’s very common in Clang’s AST - so you need to throw these away: Expr-s have a lot of methods to do this, IgnoreImpCasts() and so on - see the documentation for the exact naming and descriptions.
After this, all you need to do is llvm::dyn_cast the Expr to StringLiteral, and the StringLiteral class has methods to get the actual string value.

AST matchers are usually used to give you a rough approximation of the information you need - you’ll find that usually you will need to perform some additional logic to get to the data you actually want. AST matchers give you a substitute to the complex state machines you’d have to implement in RecursiveASTVisitor, but they’re not meant to be a complete way of getting all the information from the AST.
Nonetheless, if you find that you still want to do this using AST matchers, feel free to implement them yourself using the macros and classes defined in ASTMatchersMacros.h. For examples, the best place to look at is ASTMatchers.h. However, you may find this confusing, and the compiler error messages are not that helpful, due to the fact that AST matchers rely heavily on C++ templates (and some macros).

Hope this helps!

Gabor

Thanks, this was very helpful.

/Jesper