Skip to content

Latest commit

 

History

History
72 lines (57 loc) · 2.3 KB

README.md

File metadata and controls

72 lines (57 loc) · 2.3 KB

Baby Steps With LibClang ("idiomatic" rust version)

CI codecov

Inspired by Bastian Rieck's wonderful blogs, Baby Steps With LibClang: Walking an Abstract Syntax Tree and Baby Steps With LibClang: Counting Function Extents

Two blog's corresponding rust code

A Simple Demo

For a C++ file traverse_ast.cpp like

template <typename T>
bool f(T x) {
  return x % 2;
}

To get output like

FunctionTemplate (f)
TemplateTypeParameter (T)
ParmDecl (x)
TypeRef (T)
CompoundStmt ()
ReturnStmt ()
BinaryOperator ()
DeclRefExpr (x)
IntegerLiteral ()

You can use something like

use std::path::Path;
use clang_rs_binding::index::{Cursor, Payload, ChildVisitResult};

fn visitor(cursor: &Cursor, _parent: &Cursor, payload: Payload) -> i32 {
    if cursor.is_from_main_file() {
        return ChildVisitResult::CONTINUE;
    }
    let cursor_kind_spelling = cursor.kind_spelling();
    let cursor_spelling = cursor.spelling();
    println!("{} ({})", cursor_kind_spelling, cursor_spelling);
    cursor.visit_children(visitor, payload);
    ChildVisitResult::CONTINUE
}

fn generate_ast<P: AsRef<Path>>(filename: P) -> impl AsRef<Path> {
    let ast_filename = Path::new("traverse_ast.ast");
    std::process::Command::new("clang++")
        .arg("-emit-ast").arg(filename.as_ref()).status().unwrap();
    ast_filename
}

fn main() {
    let traverse_ast_dir = Path::new("tests/artifacts/traverse_ast");
    let ast_filename = generate_ast(traverse_ast_dir.join("traverse_ast.cpp"));

    clang_rs_binding::clang::Clang::default()
        .create_index_with_display_diagnostics()
        .create_translation_unit(&ast_filename)
        .create_cursor()
        .visit_children(visitor, std::ptr::null());
}