clang-ast

repository·master·Indexed 41 days ago

https://github.com/dtolnay/clang-ast

Rust bindings and deserialization logic for processing Clang's `-ast-dump=json` format. Version 0.1.35 provides data structures like `Node<T>`, `Id`, and `SourceRange` to work with Clang's abstract syntax tree in a type-safe, idiomatic Rust manner.

Tokens
1.6K
Snippets
9
Records
12
Agent score
100%

What's inside clang-ast

  1. Use the Node<T> data structure

    master

    The core abstraction is Node<T>. You provide a type T (usually an enum or struct) that defines which fields you want to extract from the AST. This allows you to selectively deserialize only the data you need, improving performance and stability against Clang updates.

    By convention, name your type T as Clang.

    pub struct Node<T> {
        pub id: Id,
        pub kind: T,
        pub inner: Vec<Node<T>>,
    }
    pub struct Node<T> {
        pub id: Id,
        pub kind: T,
        pub inner: Vec<Node<T>>,
    }
  2. Generate Clang AST JSON dumps

    master

    To use this library, you must first generate a JSON AST dump using Clang with the -ast-dump=json flag. Use the -fsyntax-only flag to avoid generating object files.

    clang++ -Xclang -ast-dump=json -fsyntax-only path/to/source.cc
    $ clang++ -Xclang -ast-dump=json -fsyntax-only path/to/source.cc
  3. Use Node<T> to deserialize Clang ASTs

    master

    The core data structure is Node<T>. Instead of providing a single exhaustive structure, clang-ast requires you to define a type T (usually an enum or struct) that specifies exactly which fields and node kinds you want to extract. This improves performance, stability, and compile times.

    Node<T> contains:

    • id: A unique Id for the node.
    • kind: An instance of your custom type T.
    • inner: A Vec<Node<T>> containing child nodes.
    pub struct Node<T> {
        pub id: Id,
        pub kind: T,
        pub inner: Vec<Node<T>>,
    }
  4. Deserialize specific node kinds using an enum

    master
    To extract specific information for certain node types, define an enum where each variant's name matches the `
  5. Handle 'unsupported "kind"' serialization errors

    master

    When using the clang-ast serialization logic, you may encounter a runtime error with the message unsupported "kind". This occurs when the serializer attempts to process a data type or structure that is not supported by the NodeSerializer.

    Specifically, the NodeSerializer is designed to map AST nodes to a map-like structure (using a SerializeMap implementation). It explicitly rejects several common types to enforce a specific output format, including:

    • Primitive types: bool, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, char.
    • Sequences and Tuples: serialize_seq, serialize_tuple, serialize_tuple_struct, serialize_tuple_variant.
    • Byte slices: serialize_bytes.
    • Strings: serialize_str.

    If you encounter this error, it means the data being serialized contains a type that the NodeSerializer cannot represent in its target format.

  6. Represent source ranges with SourceRange

    master

    A SourceRange defines a span in the source code using a begin and an end SourceLocation. This is the primary way to represent the extent of an AST node in the source files.

    #[derive(Default, Clone, Eq, PartialEq, Hash)]
    pub struct SourceRange {
        pub begin: SourceLocation,
        pub end: SourceLocation,
    }
  7. Use the Id type for AST node identifiers

    master

    The Id struct represents a unique identifier for a node within the Clang AST. It is a wrapper around a u64 and is designed to be easily serialized and deserialized from hex-formatted strings (e.g., 0x1234).

    Key features:

    • Null Identifier: Use Id::NULL to represent a null or non-existent identifier.
    • Serialization/Deserialization: It implements serde::Serialize and serde::Deserialize, allowing it to be used in JSON or other formats where IDs are represented as hex strings.
    • Formatting: When displayed via Display, it appears as a hex string (e.g., 0xabc). When using Debug, it appears as Id(0xabc).
    use clang_ast::Id;
    
    // Use the null identifier
    let my_id = Id::NULL;
    
    // Example of what the hex string representation looks like
    // println!("{}", my_id); // Outputs: 0x0
  8. Represent source locations with SourceLocation

    master

    A SourceLocation tracks where a piece of code exists, distinguishing between its spelling_loc (where it is written) and its expansion_loc (where it exists after macro expansion).

    #[derive(Default, Clone, Eq, PartialEq, Hash)]
    pub struct SourceLocation {
        pub spelling_loc: Option<BareSourceLocation,
        pub expansion_loc: Option<BareSourceLocation>,
    }
  9. Access detailed location data with BareSourceLocation

    master

    The BareSourceLocation struct contains the raw, granular details of a specific point in the source code. Use this when you need precise file, line, column, or offset information.

    #[derive(Clone, Eq, PartialEq, Hash, Debug)]
    pub struct BareSourceLocation {
        pub offset: usize,
        pub file: Arc<str>,
        pub line: usize,
        pub presumed_file: Option<Arc<str>>,
        pub presumed_line: Option<usize>,
        pub col: usize,
        pub tok_len: usize,
        pub included_from: Option<IncludedFrom>,
        pub is_macro_arg_expansion: bool,
    }
  10. Track include hierarchies with IncludedFrom

    master

    The IncludedFrom struct provides a way to trace how a file was included, containing the file name and an optional recursive included_from field to represent the inclusion chain.

    #[derive(Clone, Eq, PartialEq, Hash, Debug)]
    pub struct IncludedFrom {
        pub included_from: Option<Box<IncludedFrom>>,
        pub file: Arc<str>,
    }