sigmd 0.1.0

Windows API signature metadata
Documentation
//! Translation-unit walking.

use super::{
    BuildContext, ScoredMetadata, clang, function::build_function, interface::build_interface,
};

/// Walks the TU and carves a `name -> byte size` map from named type
/// declarations.
pub fn collect_sizeofs(cursor: clang::Entity<'_>, ctx: &mut BuildContext) {
    match cursor.get_kind() {
        clang::EntityKind::TranslationUnit
        | clang::EntityKind::LinkageSpec
        | clang::EntityKind::Namespace
        | clang::EntityKind::UnexposedDecl => {
            for child in cursor.get_children() {
                collect_sizeofs(child, ctx);
            }
        }
        clang::EntityKind::StructDecl
        | clang::EntityKind::ClassDecl
        | clang::EntityKind::UnionDecl
        | clang::EntityKind::TypedefDecl
        | clang::EntityKind::TypeAliasDecl => {
            let name = match cursor.get_name() {
                Some(name) => name,
                None => return,
            };

            let ty = match cursor.get_type() {
                Some(ty) => ty,
                None => return,
            };

            let size = match ty.get_sizeof() {
                Some(size) => size,
                None => return,
            };

            if let Some(prev) = ctx.sizeofs.insert(name.clone(), size)
                && prev != size
            {
                tracing::debug!(name, prev, size, "sizeof conflict; last wins");
            }
        }
        _ => {}
    }
}

pub fn visit(cursor: clang::Entity<'_>, ctx: &BuildContext, out: &mut ScoredMetadata) {
    match cursor.get_kind() {
        clang::EntityKind::TranslationUnit
        | clang::EntityKind::LinkageSpec
        | clang::EntityKind::Namespace
        | clang::EntityKind::UnexposedDecl => {
            for child in cursor.get_children() {
                visit(child, ctx, out);
            }
        }
        clang::EntityKind::FunctionDecl => {
            // Conversion failures are expected for declarations that
            // are not monitored functions (e.g. inlines without SAL).
            match build_function(cursor, ctx) {
                Ok(scored) => out.functions.push(scored),
                Err(err) => tracing::trace!(%err, "skipping non-function decl"),
            }
        }
        clang::EntityKind::StructDecl | clang::EntityKind::ClassDecl => {
            // Most SDK structs are not COM interfaces. They lack the
            // `__UUID|...` annotation.
            match build_interface(cursor, ctx) {
                Ok(scored) => out.interfaces.push(scored),
                Err(err) => tracing::trace!(%err, "skipping non-interface decl"),
            }
        }
        _ => {}
    }
}