Rewriting modified named declarations

Hi cfe-dev!

I’m definitely a noob to clang development but I’m enjoying getting to know the various APIs and trying to transition from playing around to doing some useful work.

I’m doing my best to self-serve wherever possible, but there are a couple of things I’ve run into where I could really use some guidance from people who are more experienced here. The first of these is in the broad category of “re-serializing” (possibly modified) code from AST nodes without strictly relying on the original source code text (as in the case of the rewriter classes as I understand them).

As a concrete but probably contrived example, let’s say you’ve used your favorite AST visitor class to visit a named declaration that is a two dimensional array of function pointers. In code it looks something like this:

void (*twoDimCallbacks[3][3])(void);

The AST node you’ll get from this is a NamedDecl type, where you can ask for its string name (which will yield “twoDimCallbacks” as a string), and its original qualified type, on which you can then call getAsString(), which will give you “void (*[3][3])(void)”.

Now let’s say you want to modify and rewrite this declaration into some totally unrelated stream. Maybe you’re trying to create some support functions that aren’t strict re-writes of the original code. Essentially what you want is a function in your tool that looks like this:

void serializeNewNamedDecl(std::ostream &stream, std::string &name, QualType declType);

If you didn’t have to support arrays or function pointers, implementing this function would actually be somewhat trivial, since all of the type specifiers would just be on the left side. You could do something like:

stream << declType.getAsString() << " " << name;

To do this with arrays and function pointers though, you have to write code with some semantic understanding of the type declaration and figure out exactly where the name should go. It seems to me like this must already exist somewhere in the various clang libraries.

And so after much typing, I arrive at my question: what is the “clangiest” way to do this? Is the answer really just to write a custom serializer? Is it to do a search and replace on the original source code line where the original NamedDecl was found? What if we want to actually modify the type in some way? The common search and replace technique breaks down here. Is there a class that can generate a new NamedDecl and pretty print it?

Apologies if this has already been covered somewhere in the history of this forum. Appreciate whatever response anyone is willing to formulate.

Thanks in advance!
-Jon Reeves

Just to follow up on this for posterity, I realized some time later that this can easily be done using the QualType “print” method (as opposed to the usual getAsString). This method has an argument called “PlaceHolder” which can be used to serialize a concrete type declaration with an identifier instead of just getting the usual abstract declaration. I wasn’t able to find any documentation on this, but it’s relatively clear from reading the code in TypePrinter.

So I guess I still have a lingering question about whether this is the “best” way to do this, but it’s extremely simple and would probably be pretty hard to improve upon. If anyone has further input on this of course it’s more than appreciated, but I would otherwise consider it cased closed.

Thanks again!