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するしか無いと思う。悲しい。