Repository: servo/servo
File: components/script/dom/svg/svgsvgelement.rs (Rust)

Code before:
                if element.local_name() == &local_name!("use") {
                    if let Some(cloned) = self.process_single_use_element(element) {
                        cloned_nodes.push(cloned);
                    }
                }
            }
        }

        cloned_nodes
    }

    fn process_single_use_element(&self, use_element: &Element) -> Option<DomRoot<Node>> {
        let href = use_element.get_string_attribute(&local_name!("href"));
        let href_view = href.str();
        let id_str = href_view.strip_prefix("#")?;
        let id = DOMString::from(id_str);
        let document = self.upcast::<Node>().owner_doc();
        let referenced_element = document.GetElementById(id)?;
        let referenced_node = referenced_element.upcast::<Node>();
        let has_svg_ancestor = referenced_node
            .inclusive_ancestors(crate::dom::node::ShadowIncluding::No)
            .any(|ancestor| ancestor.downcast::<SVGSVGElement>().is_some());
        if !has_svg_ancestor {
            return None;
        }
        let can_gc = crate::script_runtime::CanGc::note();
        let cloned_node = Node::clone(
            referenced_node,
            None,
            crate::dom::node::CloneChildrenFlag::CloneChildren,
            can_gc,
        );
        let root_node = self.upcast::<Node>();
        let _ = root_node.AppendChild(&cloned_node, can_gc);

        Some(cloned_node)
    }

    fn cleanup_cloned_nodes(&self, cloned_nodes: &[DomRoot<Node>]) {
        if cloned_nodes.is_empty() {
            return;
        }
        let can_gc = crate::script_runtime::CanGc::note();
        let root_node = self.upcast::<Node>();

        for cloned_node in cloned_nodes {
            let _ = root_node.RemoveChild(cloned_node, can_gc);
        }
    }

    fn invalidate_cached_serialized_subtree(&self) {

Review comment (suggestion):
We should take a `CanGc` argument for this method (and all of its transitive callers) instead: https://book.servo.org/architecture/borrow_hazard.html

Code after:
        for node in root_node.traverse_preorder(ShadowIncluding::No) {
            if let Some(element) = node.downcast::<Element>() {
                if element.local_name() == &local_name!("use") {
                    if let Some(cloned) = self.process_single_use_element(element, can_gc) {
                        cloned_nodes.push(cloned);
                    }
                }
            }
        }

        cloned_nodes
    }

    fn process_single_use_element(
        &self,
        use_element: &Element,
        can_gc: CanGc,
    ) -> Option<DomRoot<Node>> {
        let href = use_element.get_string_attribute(&local_name!("href"));
        let href_view = href.str();
        let id_str = href_view.strip_prefix("#")?;
        let id = DOMString::from(id_str);
        let document = self.upcast::<Node>().owner_doc();
        let referenced_element = document.GetElementById(id)?;
        let referenced_node = referenced_element.upcast::<Node>();
        let has_svg_ancestor = referenced_node
            .inclusive_ancestors(ShadowIncluding::No)
            .any(|ancestor| ancestor.is::<SVGSVGElement>());
        if !has_svg_ancestor {
            return None;
        }
        let cloned_node = Node::clone(
            referenced_node,
            None,
            CloneChildrenFlag::CloneChildren,
            can_gc,
        );
        let root_node = self.upcast::<Node>();
        let _ = root_node.AppendChild(&cloned_node, can_gc);

        Some(cloned_node)
    }

    fn cleanup_cloned_nodes(&self, cloned_nodes: &[DomRoot<Node>], can_gc: CanGc) {
        if cloned_nodes.is_empty() {
            return;
        }
        let root_node = self.upcast::<Node>();

        for cloned_node in cloned_nodes {
            let _ = root_node.RemoveChild(cloned_node, can_gc);