We are developing a tool for performing some source-to-source transformations. I have some technical questions regarding the approach we are following for this purpose:
As far as I understand, Clang AST is meant to be immutable, therefore once created (for instance with the ASTFrontendAction), I guess no Node (Stmt, Decl, whatever) must be modified.
Thus, our approach is basically to parse the source file and generate its AST, feed our algorithms for generating code using some information of the AST (patterns found with MatcherFinder, variable names, etc.), and then generating code (basically strings) using Replacements and Rewriter.
My main concerns are:
- I have not delved deep in all the FrontendAction subclasses in Clang. For our purpose, is ASTFrontendAction suitable? Are there any other better choices?
- Is it fine to not modify the original AST when performing source-to-source transformations? My first idea was to modify it until I read the “immutability philosophy”. On the other hand, I only care about the AST for parsing, not for the output (I am already performing the modifications with Rewriter, right?).
I am asking this just to be sure that I understand how Clang Tools work or if I am misunderstanding something.
Thank you so much.
I have not delved deep in all the FrontendAction subclasses in Clang. For our purpose, is ASTFrontendAction suitable? Are there any other better choices?
Not an expert, but I think deriving from ASTFontendAction is exactly
intended for such as use case.
Is it fine to not modify the original AST when performing source-to-source transformations? My first idea was to modify it until I read the "immutability philosophy". On the other hand, I only care about the AST for parsing, not for the output (I am already performing the modifications with Rewriter, right?).
It is always fine to **not** do something. Indeed, after parsing, the
AST is not supposed to be modified and you would get unexpected
results if you try (some analysis is baked in at this stage, e.g. name
lookup, overload resolution, implicit casts, etc). You can, however,
create a new but modified AST from the parsed one. Template
instantiation uses this via the TreeTransform helper. I still suggest
to avoid this if you don't need to. Instead as you mentioned you can
use clang::Rewriter to directly modify the input source characters
that can be found using SourceLocation. Note there is also
clang::tooling::Transformer to help with this task.
+1 to taking a look at clang::tooling::Transformer, which is the adaptor that ties the libraries in clang::transformer to actual tools. I’m happy to answer questions.
You should also consider whether your tool can be written as a clang tidy check rather than using ASTFrontendAction, since that saves you from needing to write your own tool around the transformation. However, it also means you’re confined to clang-tidy’s interface. So, it has pluses and minuses.
If you decide to go with clang-tidy, you can use the adaptor https://github.com/llvm/llvm-project/blob/master/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h to tie to clang::transformer.