RecursiveASTVisitor class from clangAST library
1. What's RecursiveASTVisitor?
RecursiveASTVisitor class is defined at the file ${LLVM_PROJECT_PATH}/clang/include/clang/AST/RecursiveASTVisitor.h.
2. Macros in RecursiveASTVisitor
There are many macros in the RecursiveASTVisitor.h file:
2.1 TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE)
If this class(RecursiveASTVisitor) and Derived class have the same "Traverse##NAME" function, then
convert '*this' into Derived type and call "Traverse##NAME" function with 'VAR' and 'QUEUE'.
If not, convert '*this' into Derived type and call "Traverse##NAME" function with 'VAR'.
1 // Traverse the given statement. If the most-derived traverse function takes a 2 // data recursion queue, pass it on; otherwise, discard it. Note that the 3 // first branch of this conditional must compile whether or not the derived 4 // class can take a queue, so if we're taking the second arm, make the first 5 // arm call our function rather than the derived class version. 6 #define TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE) 7 (::clang::detail::has_same_member_pointer_type< 8 decltype(&RecursiveASTVisitor::Traverse##NAME), 9 decltype(&Derived::Traverse##NAME)>::value 10 ? static_cast<std::conditional_t< 11 ::clang::detail::has_same_member_pointer_type< 12 decltype(&RecursiveASTVisitor::Traverse##NAME), 13 decltype(&Derived::Traverse##NAME)>::value, 14 Derived &, RecursiveASTVisitor &>>(*this) 15 .Traverse##NAME(static_cast<CLASS *>(VAR), QUEUE) 16 : getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)))
2.2 STMT(CLASS, PARENT) and StmtNodes.inc
Using the StmtNodes.inc file and STMT() macro define the Traverse##CLASS() function.
2.2.1 CLASS
The 'CLASS' would be any statement: BreakStmt, CXXCatchStmt, CXXForRangeStmt, CXXTryStmt,
CapturedStmt, CompoundStmt, ContinueStmt, CoroutineBodyStmt, DeclStmt, DoStmt, ForStmt,
GotoStmt, IfStmt, IndirectGotoStmt, MSDependentExistsStmt, NullStmt, ObjCAtCatchStmt, ObjCAtFinallyStmt,
ObjCAtSynchronizedStmt, ObjCAtThrowStmt, ObjCAtTryStmt, ObjCAutoreleasePoolStmt,
ObjCForCollectionStmt, ReturnStmt, CaseStmt, DefaultStmt, AttributedStmt, LabelStmt, WhileStmt, ... ...
1 // Declare Traverse*() for all concrete Stmt classes. 2 #define ABSTRACT_STMT(STMT) 3 #define STMT(CLASS, PARENT) 4 bool Traverse##CLASS(CLASS *S, DataRecursionQueue *Queue = nullptr); 5 #include "clang/AST/StmtNodes.inc"
2.3 Define the WalkUpFrom##Class() and Visit##CLASS() functions
By defining the WalkUpFrom##CLASS() and Visit##CLASS() functions to provide the defualt implementations for
RecursiveASTVisitor class. The values of 'CLASS' are the same as "2.2.1 CLASS".
1 // Define WalkUpFrom*() and empty Visit*() for all Stmt classes. 2 bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); } 3 bool VisitStmt(Stmt *S) { return true; } 4 #define STMT(CLASS, PARENT) 5 bool WalkUpFrom##CLASS(CLASS *S) { 6 TRY_TO(WalkUpFrom##PARENT(S)); 7 TRY_TO(Visit##CLASS(S)); 8 return true; 9 } 10 bool Visit##CLASS(CLASS *S) { return true; } 11 #include "clang/AST/StmtNodes.inc"
3. Traversal
3.1 Type Traversal
3.2 TypeLoc Traversal
3.3 Decl Traversal
3.4 Stmt Traversal
4. Preprocessing this file
The file contains a lot of macros, we will preprocess this file to get the preprocessed file.
// LLVM_PROJECT_PATH is the root path of llvm project.
//
// Using `export LLVM_PROJECT_PATH = ` to declare this env.
clang --trace-includes -D__cplusplus=201402L
-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/
-I${LLVM_PROJECT_PATH}/clang/include/
-I${LLVM_PROJECT_PATH}/.build_RelWithDebInfo/tools/clang/include/
-I${LLVM_PROJECT_PATH}/.build_RelWithDebInfo/include/
-I${LLVM_PROJECT_PATH}/llvm/include/
-E RecursiveASTVisitor.h -o tmp.ii
4.1 Delete the Blank Line
- Open your code in Visual Studio Code.
- From Edit Menu, select Replace or use a short cut key ( command + Option + F on Mac or Ctrl + H on Windows)
- In the find box type ^(s)*$n.
- Leave the replace box empty.
- Make sure the 'Use Regular Expression' is selected.
- Select the 'Replace All' button.
4.2 Delete the Linemarker
The linemarker line is like the following:
# 163 "/LLVM/llvm-project/.build_RelWithDebInfo/tools/clang/include/clang/AST/DeclNodes.inc"
To delete the linemarker, as the "4.1 Delete the Blank Line" section, we replace the regex in step 3 with "^#(.)+$n".
4.3 Delete the header files
Delete the codes from including header files.
The result of preprocessing RecursiveASTVisitor.h using clang -E is at https://gist.github.com/vitonzhangtt/8a1434c22d956bad8cd52259fc7044b0.
Reference
1. clang::RecursiveASTVisitor< Derived > Class Template Reference
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each node.
https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html