Skip to main content

qcode/value/util/
named.rs

1use std::borrow::Cow;
2
3use crate::{
4    context::Context,
5    error::{Error, ErrorTy, Result},
6    value::ValueId,
7};
8
9pub trait Named {
10    fn name(&self) -> Option<&str>;
11}
12
13/// Attempts to set the name in the reverse name table that owns `id`'s kind
14/// (function-local for block/instruction/param/Temp, global otherwise).
15pub fn update_context_name<'str>(
16    id: ValueId,
17    ctx: &mut Context<'str>,
18    name: Cow<'str, str>,
19    old_name: Option<&str>,
20) -> Result<()> {
21    if let Some(existing_id) = ctx.get_named_in_scope(id, &name) {
22        if existing_id != id {
23            Err(Error::spanless(ErrorTy::DuplicateName(name.to_string())))
24        } else {
25            Ok(())
26        }
27    } else {
28        ctx.update_name(name, id, old_name)
29    }
30}
31
32pub trait Renameable<'str, 'ctx>: Named {
33    fn rename(&mut self, name: Cow<'str, str>) -> Result<()>;
34
35    fn with_name(mut self, name: Cow<'str, str>) -> Result<Self>
36    where
37        Self: Sized,
38    {
39        self.rename(name)?;
40        Ok(self)
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47    use crate::{
48        context::Context,
49        error::{Error, ErrorTy},
50        value::{Varnode, util::base_ref::WithCtx},
51    };
52
53    #[test]
54    fn test_update_name() {
55        let mut ctx = Context::new();
56        let space_id = ctx.shared.default_space;
57        let mut var = Varnode::make(&mut ctx, 0, 1, space_id);
58
59        assert_eq!(var.ctx().get_named("var"), None);
60
61        var.rename("var".into()).unwrap();
62
63        assert_eq!(var.ctx().get_named("var"), Some(var.id()));
64        assert_eq!(var.name(), Some("var"));
65    }
66
67    #[test]
68    fn test_update_to_same_name() {
69        let mut ctx = Context::new();
70        let space_id = ctx.shared.default_space;
71        let mut var = Varnode::make(&mut ctx, 0, 1, space_id);
72
73        assert_eq!(var.ctx().get_named("var"), None);
74
75        var.rename("var".into()).unwrap();
76
77        assert_eq!(var.ctx().get_named("var"), Some(var.id()));
78        assert_eq!(var.name(), Some("var"));
79
80        var.rename("var".into()).unwrap();
81
82        assert_eq!(var.ctx().get_named("var"), Some(var.id()));
83        assert_eq!(var.name(), Some("var"));
84    }
85
86    #[test]
87    fn test_update_name_conflict() {
88        let mut ctx = Context::new();
89        let space_id = ctx.shared.default_space;
90        let mut var1 = Varnode::make(&mut ctx, 0, 1, space_id);
91        var1.rename("var".into()).unwrap();
92
93        let mut var2 = Varnode::make(&mut ctx, 1, 1, space_id);
94        assert_eq!(
95            var2.rename("var".into()),
96            Err(Error::spanless(ErrorTy::DuplicateName("var".into())))
97        );
98    }
99}