[컴][LLVM] ASTMatcher





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

  1. Matching the Clang AST — Clang 5 documentation : Matcher 를 어떻게 사용하는지 알려준다.
  2. AST Matcher Reference : ASTMatcher library references


References

  1. Tutorial for building tools using LibTooling and LibASTMatchers — Clang 5 documentation



댓글 없음:

댓글 쓰기