/// Copies/moves all paths rooted in source_path to corresponding paths rooted in target_path.
Copies/moves all paths rooted in source_path to corresponding paths rooted in target_path.
Copies / moves all paths rooted in source_path to corresponding paths rooted in target_path .
pub fn non_patterned_copy_or_move_elements<F>(
        &mut self,
        target_path: Rc<Path>,
        source_path: Rc<Path>,
        root_rustc_type: Ty<'tcx>,
        move_elements: bool,
        update: F,
    ) where
        F: Fn(&mut Self, Rc<Path>, Rc<AbstractValue>, Rc<AbstractValue>),
    {
        trace!("non_patterned_copy_or_move_elements(target_path {:?}, source_path {:?}, root_rustc_type {:?})", target_path, source_path, root_rustc_type);
        let value = self.lookup_path_and_refine_result(source_path.clone(), root_rustc_type);
        if let Expression::Variable { path, .. } = &value.expression {
            if path.eq(&source_path) {
                // The source value is not known and we need to take additional precautions:
                let source_type = self
                    .type_visitor
                    .get_path_rustc_type(&source_path, self.current_span);
                if matches!(source_type.kind(), TyKind::Array(t, _) if *t == root_rustc_type) {
                    // During path refinement, the original source path was of the intermediate form *&p.
                    // Mostly, this can just be canonicalized to just p, but if p has an array type
                    // and *&p is not used as a qualifier, then *&p represents the first element of the array
                    // if &p is the refinement of a pointer obtained from the array via array::as_ptr.
                    let zero = Rc::new(0u128.into());
                    let first_element = Path::new_index(path.clone(), zero);
                    self.non_patterned_copy_or_move_elements(
                        target_path,
                        first_element,
                        root_rustc_type,
                        move_elements,
                        update,
                    );
                    return;
                }
            }
        }
        let val_type = value.expression.infer_type();
        let mut no_children = true;
        // If a non primitive parameter is just returned from a function, for example,
        // there will be no entries rooted with target_path in the final environment.
        // This will lead to an incorrect summary of the function, since only the paths
        // in the final environment are used construct the summary. We work around this
        // by creating an entry for the non primitive (unknown) value. The caller will
        // be saddled with removing it. This case corresponds to no_children being true.
        if val_type == ExpressionType::NonPrimitive || val_type == ExpressionType::Function {
            // First look at paths that are rooted in rpath.
            // Remove an explicit deref from source_path to make it a valid root.
            let source_path = match &source_path.value {
                PathEnum::QualifiedPath {
                    qualifier,
                    selector,
                    ..
                } if **selector == PathSelector::Deref => qualifier.clone(),
                _ => source_path,
            };
            let value_map = self.current_environment.value_map.clone();
            for (path, value) in value_map
                .iter()
                .filter(|(p, _)| p.is_rooted_by(&source_path))
            {
                check_for_early_return!(self);
                let qualified_path = path
                    .replace_root(&source_path, target_path.clone())
                    .refine_paths(&self.current_environment, 0);
                if move_elements {
                    trace!("moving child {:?} to {:?}", value, qualified_path);
                // todo: doing the remove part of the move here makes it difficult to combine
                // strong updates with weak updates. See comments in distribute_over_target_joins.
                // self.current_environment.value_map =
                //     self.current_environment.value_map.remove(path);
                } else {
                    trace!("copying child {:?} to {:?}", value, qualified_path);
                };
                let old_value = value_map.get(&qualified_path).unwrap_or(&value);
                update(self, qualified_path, old_value.clone(), value.clone());
                no_children = false;
            }
            if let Expression::InitialParameterValue { path, .. }
            | Expression::Variable { path, .. } = &value.expression
            {
                if path.is_rooted_by_parameter() {
                    update(self, target_path.clone(), value.clone(), value.clone());
                    no_children = false;
                }
            }
        }
        let target_type: ExpressionType = (root_rustc_type.kind()).into();
        if target_type != ExpressionType::NonPrimitive
            || no_children
            || root_rustc_type.is_closure()
        {
            let old_value =
                self.lookup_path_and_refine_result(target_path.clone(), root_rustc_type);
            // Just copy/move (rpath, value) itself.
            if move_elements {
                trace!("moving {:?} to {:?}", value, target_path);
            // todo: doing the remove part of the move here makes it difficult to combine
            // strong updates with weak updates. See comments in distribute_over_target_joins.
            // self.current_environment.value_map =
            //     self.current_environment.value_map.remove(&source_path);
            } else {
                trace!("copying {:?} to {:?}", value, target_path);
            }
            if let Expression::CompileTimeConstant(ConstantDomain::Str(s)) = &value.expression {
                // The value is a string literal. See if the target will treat it as &[u8].
                if let TyKind::Ref(_, ty, _) = root_rustc_type.kind() {
                    if let TyKind::Slice(elem_ty) = ty.kind() {
                        if let TyKind::Uint(rustc_ast::ast::UintTy::U8) = elem_ty.kind() {
                            self.expand_aliased_string_literals_if_appropriate(
                                &target_path,
                                &value,
                                s,
                                update,
                            );
                            return;
                        }
                    }
                }
            }
            update(self, target_path, old_value, value);
        }
    }
pub fn non_patterned_copy_or_move_elements < F > ( & mut self , target_path : Rc < Path > , source_path : Rc < Path > , root_rustc_type : Ty < ' tcx > , move_elements : bool , update : F , ) where F : Fn ( & mut Self , Rc < Path > , Rc < AbstractValue > , Rc < AbstractValue > ) , { trace ! ( " " target_path source_path root_rustc_type ) ; let value = self . lookup_path_and_refine_result ( source_path . clone ( ) , root_rustc_type ) ; if let Expression :: Variable { path , .. } = & value . expression { if path . eq ( & source_path ) { // The source value is not known and we need to take additional precautions: let source_type = self . type_visitor . get_path_rustc_type ( & source_path , self . current_span ) ; if matches ! ( source_type kind ( ) TyKind Array ( t ) if t root_rustc_type ) { // During path refinement, the original source path was of the intermediate form *&p. // Mostly, this can just be canonicalized to just p, but if p has an array type // and *&p is not used as a qualifier, then *&p represents the first element of the array // if &p is the refinement of a pointer obtained from the array via array::as_ptr. let zero = Rc :: new ( 0u128 . into ( ) ) ; let first_element = Path :: new_index ( path . clone ( ) , zero ) ; self . non_patterned_copy_or_move_elements ( target_path , first_element , root_rustc_type , move_elements , update , ) ; return ; } } } let val_type = value . expression . infer_type ( ) ; let mut no_children = true ; // If a non primitive parameter is just returned from a function, for example, // there will be no entries rooted with target_path in the final environment. // This will lead to an incorrect summary of the function, since only the paths // in the final environment are used construct the summary. We work around this // by creating an entry for the non primitive (unknown) value. The caller will // be saddled with removing it. This case corresponds to no_children being true. if val_type == ExpressionType :: NonPrimitive || val_type == ExpressionType :: Function { // First look at paths that are rooted in rpath. // Remove an explicit deref from source_path to make it a valid root. let source_path = match & source_path . value { PathEnum :: QualifiedPath { qualifier , selector , .. } if * * selector == PathSelector :: Deref => qualifier . clone ( ) , _ => source_path , } ; let value_map = self . current_environment . value_map . clone ( ) ; for ( path , value ) in value_map . iter ( ) . filter ( | ( p , _ ) | p . is_rooted_by ( & source_path ) ) { check_for_early_return ! ( self ) ; let qualified_path = path . replace_root ( & source_path , target_path . clone ( ) ) . refine_paths ( & self . current_environment , 0 ) ; if move_elements { trace ! ( " " value qualified_path ) ; // todo: doing the remove part of the move here makes it difficult to combine // strong updates with weak updates. See comments in distribute_over_target_joins. // self.current_environment.value_map = //     self.current_environment.value_map.remove(path); } else { trace ! ( " " value qualified_path ) ; } ; let old_value = value_map . get ( & qualified_path ) . unwrap_or ( & value ) ; update ( self , qualified_path , old_value . clone ( ) , value . clone ( ) ) ; no_children = false ; } if let Expression :: InitialParameterValue { path , .. } | Expression :: Variable { path , .. } = & value . expression { if path . is_rooted_by_parameter ( ) { update ( self , target_path . clone ( ) , value . clone ( ) , value . clone ( ) ) ; no_children = false ; } } } let target_type : ExpressionType = ( root_rustc_type . kind ( ) ) . into ( ) ; if target_type != ExpressionType :: NonPrimitive || no_children || root_rustc_type . is_closure ( ) { let old_value = self . lookup_path_and_refine_result ( target_path . clone ( ) , root_rustc_type ) ; // Just copy/move (rpath, value) itself. if move_elements { trace ! ( " " value target_path ) ; // todo: doing the remove part of the move here makes it difficult to combine // strong updates with weak updates. See comments in distribute_over_target_joins. // self.current_environment.value_map = //     self.current_environment.value_map.remove(&source_path); } else { trace ! ( " " value target_path ) ; } if let Expression :: CompileTimeConstant ( ConstantDomain :: Str ( s ) ) = & value . expression { // The value is a string literal. See if the target will treat it as &[u8]. if let TyKind :: Ref ( _ , ty , _ ) = root_rustc_type . kind ( ) { if let TyKind :: Slice ( elem_ty ) = ty . kind ( ) { if let TyKind :: Uint ( rustc_ast :: ast :: UintTy :: U8 ) = elem_ty . kind ( ) { self . expand_aliased_string_literals_if_appropriate ( & target_path , & value , s , update , ) ; return ; } } } } update ( self , target_path , old_value , value ) ; } }
Copies/moves all paths rooted in source_path to corresponding paths rooted in target_path.
Copies / moves all paths rooted in source_path to corresponding paths rooted in target_path .
&mut self
target_path
Rc<Path>
source_path
Rc<Path>
root_rustc_type
Ty<'tcx>
move_elements
bool
update
F