ClangでなにかやろうとしたときにはRecursiveASTVisitorを使うことが多いと思う。簡単な使い方の説明を書く。
RecursiveASTVisitorにはVisitFooとTraverseFooが定義されている。他にWalkUpFromFooもあるけど、前二つに比べると利用頻度は下がるだろう。
サンプルプログラム。意味はない。
@interface Hello : NSObject
@end
@implementation Hello
- (NSString *)hello:(NSString *x) {
if (x) {
return x;
} else {
return @"";
}
}
@end
僕はClang初心者なので、Clangの流儀としてこれで合っているのか良くわかりません。とりあえず意図通りに動いてはいる。
プログラム中のすべての要素を処理したい場合
これは簡単で、単純にVisitFooを実装すれば良い。
VisitExprを定義しておけば、ifの条件のxとreturnのxと@""に対する処理が実装できる。
特定の要素に含まれる要素を処理したい場合
メソッド定義の中の式だけ処理したい場合がある。しかもその処理には式を含むメソッド名が必要だったりする。
この場合は、
- メソッド定義だけ取り出すVisitor
- 式を処理するVisitor
に分ける。1.のためにVisitを使うと、全部の部分式を処理してしまうので、ここでTraverseを使う。
class MethodBodyProcessor : public RecursiveASTVisitor<MethodBodyProcessor> {
...
};
class ProgramProcessor : public RecursiveASTVisitor<ProgramProcessor> {
public:
bool TraverseObjCMethodDecl(ObjCMethodDecl *decl) {
std::string name = decl->getNameAsString();
MethodBodyProcessor bodyProcessor(name);
return bodyProcessor.TraverseStmt(decl->getBody());
}
};
RecursiveASTVisitorのTraverseFooには、再帰的にvisitする処理が含まれているので、TraverseFooを自分で実装してしまうことで、部分式を処理しないようにすることができる。この場合、式の処理が必要なら、別のVisitorを作って委譲する。
式のクラスによって場合分けしつつ、結果をreturnしたい場合
多分RecursiveASTVisitorではなく、ExprVisitorとかを使って、手でrecursionするしか無いと思う。悲しい。