~taiite/protodump

7446255fa4146e7fd081b90a6fccdfdd5b1928cf — Hubert Hirtz 1 year, 5 months ago c472587
Show type diffs
3 files changed, 162 insertions(+), 18 deletions(-)

M src/dwarf.rs
M src/main.rs
M src/types.rs
M src/dwarf.rs => src/dwarf.rs +10 -1
@@ 10,7 10,16 @@ pub struct Parameter<R> {
    pub type_: types::InstancePtr<R>,
}

#[derive(Clone)]
impl<R> PartialEq for Parameter<R>
where
    R: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.type_ == other.type_
    }
}

#[derive(Clone, PartialEq)]
pub struct Subprogram<R> {
    pub return_type: types::InstancePtr<R>,
    pub parameters: Option<Vec<Parameter<R>>>,

M src/main.rs => src/main.rs +125 -14
@@ 9,10 9,13 @@ use std::env;
use std::fmt;
use std::fs;
use std::process;
use types::TypePtr;
use yansi::Color;
use yansi::Paint;
use yansi::Style;

use crate::types::Definition;

mod dwarf;
mod types;



@@ 95,17 98,54 @@ fn show_object_info_diff(prev: &ObjectInfo<'_>, next: &ObjectInfo<'_>) {
}

enum SubprogramDiff<'a> {
    /// This subprogram was not in the previous version.
    Added(dwarf::Subprogram<Reader<'a>>),

    /// This subprogram is not in the next version.
    Removed(dwarf::Subprogram<Reader<'a>>),
    Changed(dwarf::Subprogram<Reader<'a>>, dwarf::Subprogram<Reader<'a>>),

    /// The subprograms have different signatures.
    Shallow(dwarf::Subprogram<Reader<'a>>, dwarf::Subprogram<Reader<'a>>),

    /// Both subprograms have the same signature, but some of the types have
    /// changed.
    Deep(dwarf::Subprogram<Reader<'a>>),
}

enum TypeDiff<'a> {
    Added(types::TypePtr<Reader<'a>>),
    Removed(types::TypePtr<Reader<'a>>),
    Shallow(types::TypePtr<Reader<'a>>, types::TypePtr<Reader<'a>>),
}

struct Diff<'a> {
    subprogram_diffs: Vec<(Reader<'a>, SubprogramDiff<'a>)>,
    type_diffs: Vec<(Reader<'a>, types::TypePtr<Reader<'a>>)>,
    type_diffs: Vec<(String, TypeDiff<'a>)>,
}

fn diff_sources<'a>(prev: Sources<'a>, mut next: Sources<'a>) -> Diff<'a> {
    let prev_types = prev.public_types();
    let mut next_types = next.public_types();
    let mut type_diffs: Vec<_> = prev_types
        .into_iter()
        .filter_map(|(name, prev_type)| {
            let next_type = if let Some(t) = next_types.remove(&name) {
                t
            } else {
                return Some((name, TypeDiff::Removed(prev_type)));
            };
            if prev_type.borrow().definition != next_type.borrow().definition {
                return Some((name, TypeDiff::Shallow(prev_type, next_type)));
            }
            None
        })
        .collect();
    let added = next_types
        .into_iter()
        .map(|(name, next_type)| (name, TypeDiff::Added(next_type)));
    type_diffs.extend(added);
    type_diffs.sort_unstable_by(|(name1, _), (name2, _)| String::cmp(name1, name2));

    let mut comparator = types::Comparator::default();
    let mut subprogram_diffs: Vec<_> = prev
        .subprograms


@@ 116,41 156,105 @@ fn diff_sources<'a>(prev: Sources<'a>, mut next: Sources<'a>) -> Diff<'a> {
            } else {
                return Some((prev_func, SubprogramDiff::Removed(prev_prototype)));
            };
            if comparator.subprogram_eq(&prev_prototype, &next_prototype) {
                None
            } else {
                Some((
            if prev_prototype != next_prototype {
                return Some((
                    prev_func,
                    SubprogramDiff::Changed(prev_prototype, next_prototype),
                ))
                    SubprogramDiff::Shallow(prev_prototype, next_prototype),
                ));
            }
            if !comparator.subprogram_eq(&prev_prototype, &next_prototype) {
                return Some((prev_func, SubprogramDiff::Deep(prev_prototype)));
            }
            None
        })
        .collect();

    let added = next
        .subprograms
        .into_iter()
        .map(|(func, prototype)| (func, SubprogramDiff::Added(prototype)));
    subprogram_diffs.extend(added);

    subprogram_diffs.sort_unstable_by(|(func1, _), (func2, _)| func1.slice().cmp(func2.slice()));

    Diff {
        subprogram_diffs,
        type_diffs: Vec::new(), // TODO
        type_diffs,
    }
}

fn color_prefix(c: Color) -> impl fmt::Display {
    struct C(Color);
    impl fmt::Display for C {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            if !Paint::is_enabled() {
                return Ok(());
            }
            Style::new(self.0).fmt_prefix(f)
        }
    }
    C(c)
}

fn color_suffix(c: Color) -> impl fmt::Display {
    struct C(Color);
    impl fmt::Display for C {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            if Paint::is_enabled() {
                return Ok(());
            }
            Style::new(self.0).fmt_suffix(f)
        }
    }
    C(c)
}

fn show_source_diff<'a>(d: &'a Diff<'a>) {
    for (func, diff) in &d.subprogram_diffs {
        match diff {
    for (name, type_diff) in &d.type_diffs {
        match type_diff {
            TypeDiff::Added(t) => {
                println!(
                    "{}+typedef {} {};{}\n",
                    color_prefix(Color::Green),
                    t.borrow().definition,
                    name,
                    color_suffix(Color::Green),
                );
            }
            TypeDiff::Removed(t) => {
                println!(
                    "{}-typedef {} {};{}\n",
                    color_prefix(Color::Red),
                    t.borrow().definition,
                    name,
                    color_suffix(Color::Red),
                );
            }
            TypeDiff::Shallow(old_t, new_t) => {
                println!(
                    "{}-typedef {} {};{}",
                    color_prefix(Color::Red),
                    old_t.borrow().definition,
                    name,
                    color_suffix(Color::Red),
                );
                println!(
                    "{}+typedef {} {};{}\n",
                    color_prefix(Color::Green),
                    new_t.borrow().definition,
                    name,
                    color_suffix(Color::Green),
                );
            }
        }
    }
    for (func, subprogram_diff) in &d.subprogram_diffs {
        match subprogram_diff {
            SubprogramDiff::Added(p) => {
                println!("{}{}", Paint::green("+"), prototype(*func, p, Color::Green));
            }
            SubprogramDiff::Removed(p) => {
                println!("{}{}", Paint::red("-"), prototype(*func, p, Color::Red));
            }
            SubprogramDiff::Changed(old_p, new_p) => {
            SubprogramDiff::Shallow(old_p, new_p) => {
                println!("{}{}", Paint::red("-"), prototype(*func, old_p, Color::Red));
                println!(
                    "{}{}",


@@ 158,6 262,13 @@ fn show_source_diff<'a>(d: &'a Diff<'a>) {
                    prototype(*func, new_p, Color::Green),
                );
            }
            SubprogramDiff::Deep(p) => {
                println!(
                    "{}{}",
                    Paint::yellow("*"),
                    prototype(*func, p, Color::Yellow),
                );
            }
        }
    }
}

M src/types.rs => src/types.rs +27 -3
@@ 32,7 32,7 @@ where
}

/// Member/field of a structure or an union.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct Member<R> {
    /// The name of the field, or [None] if the field is an anonymous/unamed
    /// structure or union.


@@ 53,7 53,7 @@ pub struct Enumerator<R> {
}

/// A callback or function type.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct Subroutine<R> {
    return_type: Option<InstancePtr<R>>,
    parameters: Vec<InstancePtr<R>>,


@@ 120,7 120,7 @@ impl fmt::Display for Primitive {
}

/// Definition of a type.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum Definition<R> {
    Primitive(Primitive),



@@ 246,6 246,20 @@ pub struct Type<R> {
/// Pointer type for [Type] used through protodump in order to avoid copies.
pub type TypePtr<R> = Rc<RefCell<Type<R>>>;

impl<R> PartialEq for Type<R>
where
    R: PartialEq,
{
    /// Shallow equality (name, if any, else definition).
    fn eq(&self, other: &Self) -> bool {
        match (&self.name, &other.name) {
            (None, None) => self.definition == other.definition,
            (Some(_), None) | (None, Some(_)) => false,
            (Some(s), Some(o)) => s == o,
        }
    }
}

impl<R> fmt::Display for Type<R>
where
    R: gimli::Reader,


@@ 310,6 324,16 @@ pub struct Instance<R> {
/// Pointer type for [Instance] used through protodump in order to avoid copies.
pub type InstancePtr<R> = Rc<RefCell<Instance<R>>>;

impl<R> PartialEq for Instance<R>
where
    R: PartialEq,
{
    /// Shallow equality (modifiers and name, if any, else definition).
    fn eq(&self, other: &Self) -> bool {
        self.modifiers == other.modifiers && self.underlying == other.underlying
    }
}

impl<R> fmt::Display for Instance<R>
where
    R: gimli::Reader,