Check whether `child` is a subclass (direct or transitive) of `parent` by walking the inheritance chain via the class loader. Returns `false` if either class cannot be loaded or if there is no inheritance relationship. Limits the chain walk to 20 steps to avoid infinite loops on cyclic hierarchies.
(
child: &str,
parent: &str,
class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
)
| 2011 | /// no inheritance relationship. Limits the chain walk to 20 steps |
| 2012 | /// to avoid infinite loops on cyclic hierarchies. |
| 2013 | fn is_subclass_of( |
| 2014 | child: &str, |
| 2015 | parent: &str, |
| 2016 | class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>, |
| 2017 | ) -> bool { |
| 2018 | if child.eq_ignore_ascii_case(parent) { |
| 2019 | return false; // same class, not a subclass |
| 2020 | } |
| 2021 | let mut current = child.to_string(); |
| 2022 | for _ in 0..20 { |
| 2023 | let cls = match class_loader(¤t) { |
| 2024 | Some(c) => c, |
| 2025 | None => return false, |
| 2026 | }; |
| 2027 | // Check implemented interfaces at every level. |
| 2028 | for iface in &cls.interfaces { |
| 2029 | if iface.as_str().eq_ignore_ascii_case(parent) { |
| 2030 | return true; |
| 2031 | } |
| 2032 | } |
| 2033 | if let Some(ref p) = cls.parent_class { |
| 2034 | if p.as_str().eq_ignore_ascii_case(parent) { |
| 2035 | return true; |
| 2036 | } |
| 2037 | current = p.to_string(); |
| 2038 | } else { |
| 2039 | return false; |
| 2040 | } |
| 2041 | } |
| 2042 | false |
| 2043 | } |
| 2044 | |
| 2045 | /// Context for the forward walk. |
| 2046 | /// |
no test coverage detected