Clang 의 AST 를 사용해서 code 등을 analyze 할 때 AST 의 특정부분을 찾는 것은 ASTMatcher 를 이용한다. "AST 에서 이러이러한 특징을 갖는 녀석을 찾고, 그것에 대해 무슨 일을 하고 싶다." 라면 이 ASTMatcher 를 사용하면 된다.
실제 Clang tool 을 작성하는 것에 대해서는 "Visual Studio 에서 Clang tool 빌드 하기" 를 참고하자.
AST Matcher
Clang 은 ASTMatcher library 를 제공하는데, 이녀석으로 Clang AST 를 좀 더 쉽게 이용할 수 있다.아래문장에 ASTMatcher library 를 이용한 경우인데,
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl( )))))
- for 문인데 : forStmt
- loop 에 대한 init 을 가졌고 : hasLoopInit
- 선언하는 문장이 있고(declare) : declStmt
- 그 선언은 한개이고, : hasSingleDecl
- 그 선언은 변수 : varDecl
위의 ASTMatcher 는 아래 for 문에 match 된다. (노란색)
for(int i = 0 ; i<10; i++){}
만약 loop 가 아래처럼 2개를 initialize 한다면 위의 조건에 맞지 않아서 match 되지 않는다.
for(int i = 0, j=0 ; i<10; i++){}
여기에 추가로 " '0'으로 초기화되는 녀석들만 가져오게 하고 싶다 "면,
hasInitializer(integerLiteral(equals(0)))만 추가하면 된다.
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl( hasInitializer(integerLiteral(equals(0))) )))))
실제로 선언을 할 때는 아래처럼 하게 된다. 아래에서 .bind 는 저 Matcher 에 ID 를 주는 것이다. 이 ID 를 이용해서 나중에 저걸 가지고 무엇인가를 작업할 때에 필요하다.
StatementMatcher LoopMatcher = forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl( hasInitializer(integerLiteral(equals(0)))))))).bind("forLoop");
이러면 아래같은 for 문이 있으면 match 된다.
for(int i = 0 ; i<10; i++){}
Callback 함수
이렇게 특정 녀석이 matching 됐을 때 callback 함수를 부를 수 있게 설정할 수 있다. 소스는 ref. 1 에서 가져왔다.StatementMatcher LoopMatcher = forStmt( hasLoopInit(declStmt( hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) .bind("initVarName")))), hasIncrement(unaryOperator( hasOperatorName("++"), hasUnaryOperand(declRefExpr( to(varDecl(hasType(isInteger())).bind("incVarName")))))), hasCondition(binaryOperator( hasOperatorName("<"), hasLHS(ignoringParenImpCasts(declRefExpr( to(varDecl(hasType(isInteger())).bind("condVarName"))))), hasRHS(expr(hasType(isInteger())))))).bind("forLoop"); class LoopPrinter : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result) { if (const ForStmt *FS = Result.Nodes.getNodeAs<clang::ForStmt>("forLoop")){ FS->dump(); llvm::outs() << "Potential array-based loop discovered.\n"; } } }; int main(int argc, const char **argv) { CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); LoopPrinter Printer; // callback MatchFinder Finder; Finder.addMatcher(LoopMatcher, &Printer); return Tool.run(newFrontendActionFactory(&Finder).get()); // old code // return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>().get()); }
See Also
- Matching the Clang AST — Clang 5 documentation : Matcher 를 어떻게 사용하는지 알려준다.
- AST Matcher Reference : ASTMatcher library references
댓글 없음:
댓글 쓰기