1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use move_binary_format::file_format::{
    CompiledModule, Signature, SignatureToken, StructFieldInformation, TypeSignature,
};
use proptest::sample::Index as PropIndex;

pub struct SignatureRefMutation<'a> {
    module: &'a mut CompiledModule,
    mutations: Vec<(PropIndex, PropIndex)>,
}

impl<'a> SignatureRefMutation<'a> {
    pub fn new(module: &'a mut CompiledModule, mutations: Vec<(PropIndex, PropIndex)>) -> Self {
        Self { module, mutations }
    }

    pub fn apply(self) -> bool {
        if self.module.signatures.is_empty() {
            return false;
        }
        let module = self.module;
        let mut mutations = false;
        for (s_idx, t_idx) in self.mutations {
            let sig_idx = s_idx.index(module.signatures.len());
            let sig = &module.signatures[sig_idx];
            if sig.is_empty() {
                continue;
            }
            let token_idx = t_idx.index(sig.len());
            let new_sig = mutate_sig(sig, token_idx);
            module.signatures[sig_idx] = new_sig;
            mutations = true;
        }
        mutations
    }
}

/// Context for applying a list of `FieldRefMutation` instances.
pub struct FieldRefMutation<'a> {
    module: &'a mut CompiledModule,
    mutations: Vec<(PropIndex, PropIndex)>,
}

impl<'a> FieldRefMutation<'a> {
    pub fn new(module: &'a mut CompiledModule, mutations: Vec<(PropIndex, PropIndex)>) -> Self {
        Self { module, mutations }
    }

    #[inline]
    pub fn apply(self) -> bool {
        if self.module.struct_defs.is_empty() {
            return false;
        }
        let module = self.module;
        let mut mutations = false;
        for (s_idx, f_idx) in self.mutations {
            let struct_idx = s_idx.index(module.struct_defs.len());
            let struct_def = &mut module.struct_defs[struct_idx];
            if let StructFieldInformation::Declared(fields) = &mut struct_def.field_information {
                if fields.is_empty() {
                    continue;
                }
                let field_idx = f_idx.index(fields.len());
                let field_def = &mut fields[field_idx];
                let new_ty = mutate_field(&field_def.signature.0);
                fields[field_idx].signature = TypeSignature(new_ty);
                mutations = true;
            }
        }
        mutations
    }
}

fn mutate_sig(sig: &Signature, token_idx: usize) -> Signature {
    use SignatureToken::*;

    Signature(
        sig.0
            .iter()
            .enumerate()
            .map(|(idx, token)| {
                if idx == token_idx {
                    match &token {
                        Reference(_) | MutableReference(_) => Reference(Box::new(token.clone())),
                        _ => Reference(Box::new(Reference(Box::new(token.clone())))),
                    }
                } else {
                    token.clone()
                }
            })
            .collect(),
    )
}

fn mutate_field(token: &SignatureToken) -> SignatureToken {
    SignatureToken::Reference(Box::new(token.clone()))
}