Matching the Clang AST

This document explains how to use Clang's LibASTMatchers to match interesting nodes of the AST and execute code that uses the matched nodes. Combined with LibTooling, LibASTMatchers helps to write code-to-code transformation tools or query tools.

We assume basic knowledge about the Clang AST. See the Introduction to the Clang AST if you want to learn more about how the AST is structured.

Introduction

LibASTMatchers provides a domain specific language to create predicates on Clang's AST. This DSL is written in and can be used from C++, allowing users to write a single program to both match AST nodes and access the node's C++ interface to extract attributes, source locations, or any other information provided on the AST level.

AST matchers are predicates on nodes in the AST. Matchers are created by calling creator functions that allow building up a tree of matchers, where inner matchers are used to make the match more specific.

For example, to create a matcher that matches all class or union declarations in the AST of a translation unit, you can call recordDecl(). To narrow the match down, for example to find all class or union declarations with the name "Foo", insert a hasName matcher: the call recordDecl(hasName("Foo")) returns a matcher that matches classes or unions that are named "Foo", in any namespace. By default, matchers that accept multiple inner matchers use an implicit allOf(). This allows further narrowing down the match, for example to match all classes that are derived from "Bar": recordDecl(hasName("Foo"), isDerivedFrom("Bar")).

How to create a matcher

With more than a thousand classes in the Clang AST, one can quickly get lost when trying to figure out how to create a matcher for a specific pattern. This section will teach you how to use a rigorous step-by-step pattern to build the matcher you are interested in. Note that there will always be matchers missing for some part of the AST. See the section about how to write your own AST matchers later in this document.

The precondition to using the matchers is to understand how the AST for what you want to match looks like. The Introduction to the Clang AST teaches you how to dump a translation unit's AST into a human readable format.

In general, the strategy to create the right matchers is:

  1. Find the outermost class in Clang's AST you want to match.
  2. Look at the AST Matcher Reference for matchers that either match the node you're interested in or narrow down attributes on the node.
  3. Create your outer match expression. Verify that it works as expected.
  4. Examine the matchers for what the next inner node you want to match is.
  5. Repeat until the matcher is finished.

Binding nodes in match expressions

Matcher expressions allow you to specify which parts of the AST are interesting for a certain task. Often you will want to then do something with the nodes that were matched, like building source code transformations.

To that end, matchers that match specific AST nodes (so called node matchers) are bindable; for example, recordDecl(hasName("MyClass")).bind("id") will bind the matched recordDecl node to the string "id", to be later retrieved in the match callback.

Writing your own matchers

There are multiple different ways to define a matcher, depending on its type and flexibility.