fn propagate_through_relnodes()

in amzn-smt-string-transformer/src/callgraph.rs [342:413]


    fn propagate_through_relnodes(
        &mut self,
        var: NodeId,
        rel_nodes: &BTreeSet<NodeId>,
        cur_data: &CallnodeData,
        direction: GraphTraversalDir,
    ) -> Result<(NodeSetData, AffectOk), AffectErr> {
        // now the work begins

        // definitely take current literals and immediate neighbour nodes (in the direction specified)
        // then, depending on the type of each node, recurse back
        // need to keep track to detect cycles (if there is one, bail with a cycle error)
        let mut contrib_vars = rel_nodes.iter().cloned().collect::<BTreeSet<_>>();

        // if the nodes include the var itself, cycle detected
        if contrib_vars.contains(&var) {
            return Err(AffectErr::CycleDetected);
        }
        let mut contrib_string_fcts = HashSet::<(StringFct, StringFctArgs)>::new();
        contrib_string_fcts.insert(cur_data.get_string_fct_arg_pair());

        let mut contrib_string_lits = cur_data
            .string_lits_built_from
            .iter()
            .cloned()
            .collect::<BTreeSet<_>>();

        let rel_nodes = rel_nodes.iter().cloned().collect::<BTreeSet<_>>();

        // now actually collect the data from the relevant nodes
        for node in rel_nodes {
            if let Some(node) = self.forest.nodes().get(&node) {
                contrib_string_fcts.insert(node.data.get_string_fct_arg_pair());
                // information doesn't propagate through functions that return a Bool
                if matches!(
                    node.data.string_fct.string_fct_return_type(),
                    IdentType::StringType
                        | IdentType::RegexStringType
                        | IdentType::IntType // int also requires the string chars potentially
                        | IdentType::ConstraintVarType
                ) {
                    let cur_ind = *node.ind();
                    let node_contribs_res = self.propagate_along_path(cur_ind, direction);
                    if let Ok((node_contribs, _)) = node_contribs_res {
                        contrib_vars.extend(node_contribs.vars.iter().cloned());
                        // check again for cycles
                        if contrib_vars.contains(&var) {
                            return Err(AffectErr::CycleDetected);
                        }
                        contrib_string_fcts.extend(node_contribs.string_fcts);
                        contrib_string_lits.extend(node_contribs.string_lits);
                    } else {
                        // if there was an error in processing the affects of rel_node, bail with this error
                        return node_contribs_res;
                    }
                }
            } else {
                // rel_node is not found in the callgraph
                return Err(AffectErr::InvalidNode);
            }
        }

        // finally, once the data has all been collected, update the current node with the contribs
        let new_node_data = cur_data.clone();
        let new_nodeset_data = NodeSetData {
            vars: contrib_vars,
            string_fcts: contrib_string_fcts,
            string_lits: contrib_string_lits,
        };
        self.update_node_with_contribs(var, new_nodeset_data.clone(), new_node_data, direction)?;
        Ok((new_nodeset_data, AffectOk::Done))
    }