Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec95ef89 authored by Henri Chataing's avatar Henri Chataing Committed by Gerrit Code Review
Browse files

Merge "pdl: Remove public fields from lint::PacketScope"

parents 9712e53b 1ff1141d
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -46,9 +46,9 @@ pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt {
    syn::parse_str::<syn::LitInt>(&format!("0x{hex_digits}{suffix}")).unwrap()
}

fn generate_packet_size_getter(
    scope: &lint::Scope<'_>,
    fields: &[&analyzer_ast::Field],
fn generate_packet_size_getter<'a>(
    scope: &lint::Scope<'a>,
    fields: impl Iterator<Item = &'a analyzer_ast::Field>,
    is_packet: bool,
) -> (usize, proc_macro2::TokenStream) {
    let mut constant_width = 0;
@@ -174,7 +174,7 @@ fn find_constrained_parent_fields<'a>(
    let packet_scope = &scope.scopes[&scope.typedef[id]];
    find_constrained_fields(scope, id).into_iter().filter(|field| {
        let id = field.id().unwrap();
        packet_scope.all_fields.contains_key(id) && !packet_scope.named.contains_key(id)
        packet_scope.all_fields.contains_key(id) && packet_scope.get_packet_field(id).is_none()
    })
}

@@ -195,7 +195,7 @@ fn generate_data_struct(
    let serializer_span = format_ident!("buffer");
    let mut field_parser = FieldParser::new(scope, endianness, id, &span);
    let mut field_serializer = FieldSerializer::new(scope, endianness, id, &serializer_span);
    for field in &packet_scope.fields {
    for field in packet_scope.iter_fields() {
        field_parser.add(field);
        field_serializer.add(field);
    }
@@ -211,7 +211,7 @@ fn generate_data_struct(
    };

    let (constant_width, packet_size) =
        generate_packet_size_getter(scope, &packet_scope.fields, is_packet);
        generate_packet_size_getter(scope, packet_scope.iter_fields(), is_packet);
    let conforms = if constant_width == 0 {
        quote! { true }
    } else {
@@ -225,7 +225,7 @@ fn generate_data_struct(

    let struct_name = if is_packet { format_ident!("{id}Data") } else { format_ident!("{id}") };
    let fields_with_ids =
        packet_scope.fields.iter().filter(|f| f.id().is_some()).collect::<Vec<_>>();
        packet_scope.iter_fields().filter(|f| f.id().is_some()).collect::<Vec<_>>();
    let mut field_names =
        fields_with_ids.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>();
    let mut field_types = fields_with_ids.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
@@ -376,7 +376,7 @@ fn generate_packet_decl(
    let all_field_getter_names = all_field_names.iter().map(|id| format_ident!("get_{id}"));
    let all_field_self_field = all_fields.iter().map(|f| {
        for (parent, parent_id) in parents.iter().zip(parent_lower_ids.iter()) {
            if scope.scopes[parent].fields.contains(f) {
            if scope.scopes[parent].iter_fields().any(|ff| ff.id() == f.id()) {
                return quote!(self.#parent_id);
            }
        }
@@ -402,7 +402,8 @@ fn generate_packet_decl(
        let parent_packet_scope = &scope.scopes[&scope.typedef[parent_id]];

        let named_fields = {
            let mut names = parent_packet_scope.named.keys().collect::<Vec<_>>();
            let mut names =
                parent_packet_scope.iter_fields().filter_map(ast::Field::id).collect::<Vec<_>>();
            names.sort();
            names
        };
+1 −1
Original line number Diff line number Diff line
@@ -218,7 +218,7 @@ impl<'a> FieldParser<'a> {

    fn payload_field_offset_from_end(&self) -> Option<usize> {
        let packet_scope = self.packet_scope().unwrap();
        let mut fields = packet_scope.fields.iter();
        let mut fields = packet_scope.iter_fields();
        fields.find(|f| {
            matches!(f.desc, ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. })
        })?;
+30 −124
Original line number Diff line number Diff line
@@ -19,16 +19,8 @@ pub struct Scope<'d> {
/// Gather information about a Packet, Struct, or Group declaration.
#[derive(Debug)]
pub struct PacketScope<'d> {
    // Typedef, scalar, array fields.
    pub named: HashMap<String, &'d analyzer_ast::Field>,

    // Flattened field declarations.
    // Contains field declarations from the original Packet, Struct, or Group,
    // where Group fields have been substituted by their body.
    pub fields: Vec<&'d analyzer_ast::Field>,

    // Constraint declarations gathered from Group inlining.
    pub constraints: HashMap<String, &'d Constraint>,
    // Original decl.
    decl: &'d analyzer_ast::Decl,

    // Local and inherited field declarations. Only named fields are preserved.
    // Saved here for reference for parent constraint resolving.
@@ -46,11 +38,6 @@ impl<'d> std::hash::Hash for &'d analyzer_ast::Decl {
}

impl<'d> PacketScope<'d> {
    /// Insert a field declaration into a packet scope.
    fn insert(&mut self, field: &'d analyzer_ast::Field) {
        field.id().and_then(|id| self.named.insert(id.to_owned(), field));
    }

    /// Add parent fields and constraints to the scope.
    /// Only named fields are imported.
    fn inherit(
@@ -66,90 +53,53 @@ impl<'d> PacketScope<'d> {
            self.all_constraints.insert(id, constraint);
        }

        // Merge group constraints into parent constraints,
        // but generate no duplication warnings, the constraints
        // do no apply to the same field set.
        for (id, constraint) in self.constraints.iter() {
            self.all_constraints.insert(id.clone(), constraint);
        }

        // Save parent fields.
        self.all_fields = parent.all_fields.clone();
    }

    /// Insert group field declarations into a packet scope.
    fn inline(
        &mut self,
        packet_scope: &PacketScope<'d>,
        constraints: impl Iterator<Item = &'d Constraint>,
    ) {
        for (id, field) in packet_scope.named.iter() {
            self.named.insert(id.clone(), field);
        }

        // Append group fields to the finalizeed fields.
        for field in packet_scope.fields.iter() {
            self.fields.push(field);
        }

        // Append group constraints to the caller packet_scope.
        for (id, constraint) in packet_scope.constraints.iter() {
            self.constraints.insert(id.clone(), constraint);
        }

        // Add constraints to the packet_scope, checking for duplicate constraints.
        for constraint in constraints {
            let id = constraint.id.clone();
            self.constraints.insert(id, constraint);
        }
    /// Iterate over the packet's fields.
    pub fn iter_fields(&self) -> impl Iterator<Item = &'d analyzer_ast::Field> {
        self.decl.fields()
    }

    /// Lookup a field by name. This will also find the special
    /// `_payload_` and `_body_` fields.
    pub fn get_packet_field(&self, id: &str) -> Option<&analyzer_ast::Field> {
        self.named.get(id).copied().or(match id {
            "_payload_" | "_body_" => self.get_payload_field(),
            _ => None,
        self.decl.fields().find(|field| match &field.desc {
            FieldDesc::Payload { .. } => id == "_payload_",
            FieldDesc::Body { .. } => id == "_body_",
            _ => field.id() == Some(id),
        })
    }

    /// Find the payload or body field, if any.
    pub fn get_payload_field(&self) -> Option<&analyzer_ast::Field> {
        self.fields
            .iter()
        self.decl
            .fields()
            .find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. }))
            .copied()
    }

    /// Lookup the size field for an array field.
    pub fn get_array_size_field(&self, id: &str) -> Option<&analyzer_ast::Field> {
        self.fields
            .iter()
            .find(|field| match &field.desc {
                FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => {
                    field_id == id
                }
        self.decl.fields().find(|field| match &field.desc {
            FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id,
            _ => false,
        })
            .copied()
    }

    /// Find the size field corresponding to the payload or body
    /// field of this packet.
    pub fn get_payload_size_field(&self) -> Option<&analyzer_ast::Field> {
        self.fields
            .iter()
            .find(|field| match &field.desc {
        self.decl.fields().find(|field| match &field.desc {
            FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_",
            _ => false,
        })
            .copied()
    }

    /// Cleanup scope after processing all fields.
    fn finalize(&mut self) {
        // Check field shadowing.
        for f in self.fields.iter() {
        for f in self.decl.fields() {
            if let Some(id) = f.id() {
                self.all_fields.insert(id.to_string(), f);
            }
@@ -169,9 +119,6 @@ impl<'d> Scope<'d> {
            if let Some(id) = decl.id() {
                scope.typedef.insert(id.to_string(), decl);
            }
            if let Some(lscope) = decl_scope(decl) {
                scope.scopes.insert(decl, lscope);
            }
        }

        scope.finalize();
@@ -179,13 +126,7 @@ impl<'d> Scope<'d> {
    }

    // Sort Packet, Struct, and Group declarations by reverse topological
    // orde, and inline Group fields.
    // Raises errors and warnings for:
    //      - undeclared included Groups,
    //      - undeclared Typedef fields,
    //      - undeclared Packet or Struct parents,
    //      - recursive Group insertion,
    //      - recursive Packet or Struct inheritance.
    // order.
    fn finalize(&mut self) -> Vec<&'d analyzer_ast::Decl> {
        // Auxiliary function implementing BFS on Packet tree.
        enum Mark {
@@ -219,34 +160,20 @@ impl<'d> Scope<'d> {
            };

            context.visited.insert(decl, Mark::Temporary);
            let mut lscope = decl_scope(decl).unwrap();
            let mut lscope =
                PacketScope { decl, all_fields: HashMap::new(), all_constraints: HashMap::new() };

            // Iterate over Struct and Group fields.
            for f in fields {
                match &f.desc {
                    FieldDesc::Group { group_id, constraints, .. } => {
                        match scope.typedef.get(group_id) {
                            Some(group_decl @ Decl { desc: DeclDesc::Group { .. }, .. }) => {
                                // Recurse to flatten the inserted group.
                                if let Some(rscope) = bfs(group_decl, context, scope) {
                                    // Inline the group fields and constraints into
                                    // the current scope.
                                    lscope.inline(rscope, constraints.iter())
                                }
                            }
                            None | Some(_) => (),
                        }
                    }
                    FieldDesc::Typedef { type_id, .. } => {
                        lscope.fields.push(f);
                        match scope.typedef.get(type_id) {
                    FieldDesc::Group { .. } => unreachable!(),
                    FieldDesc::Typedef { type_id, .. } => match scope.typedef.get(type_id) {
                        Some(struct_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }) => {
                            bfs(struct_decl, context, scope);
                        }
                        None | Some(_) => (),
                        }
                    }
                    _ => lscope.fields.push(f),
                    },
                    _ => (),
                }
            }

@@ -374,24 +301,3 @@ impl<'d> Scope<'d> {
        }
    }
}

fn decl_scope(decl: &analyzer_ast::Decl) -> Option<PacketScope<'_>> {
    match &decl.desc {
        DeclDesc::Packet { fields, .. }
        | DeclDesc::Struct { fields, .. }
        | DeclDesc::Group { fields, .. } => {
            let mut scope = PacketScope {
                named: HashMap::new(),
                fields: Vec::new(),
                constraints: HashMap::new(),
                all_fields: HashMap::new(),
                all_constraints: HashMap::new(),
            };
            for field in fields {
                scope.insert(field)
            }
            Some(scope)
        }
        _ => None,
    }
}