MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / find_declaring_class

Function find_declaring_class

src/hover/mod.rs:189–296  ·  view source on GitHub ↗

Find the class that originally declares a member. When a member is inherited (not declared on `owner` itself), this walks up the parent chain and checks traits and mixins to find the class that actually declares the member. Returns a fully-resolved `ClassInfo` for the declaring class, or falls back to `owner` when the declaring class cannot be determined. This is used by hover and completion-re

(
    owner: &ClassInfo,
    member_name: &str,
    member_kind: &MemberKindForOrigin,
    class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
)

Source from the content-addressed store, hash-verified

187/// shows `class Model { public static function find(...) }` rather than
188/// `class User { ... }` when `find()` is inherited from `Model`.
189pub(crate) fn find_declaring_class(
190 owner: &ClassInfo,
191 member_name: &str,
192 member_kind: &MemberKindForOrigin,
193 class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
194) -> Arc<ClassInfo> {
195 // If the member is declared directly on the owner, no need to search.
196 if raw_class_has_member(owner, member_name, member_kind, class_loader) {
197 return Arc::new(owner.clone());
198 }
199
200 // Check traits used by the owner.
201 for trait_name in &owner.used_traits {
202 if let Some(trait_class) = class_loader(trait_name) {
203 let has = match member_kind {
204 MemberKindForOrigin::Method => trait_class
205 .methods
206 .iter()
207 .any(|m| m.name.eq_ignore_ascii_case(member_name)),
208 MemberKindForOrigin::Property => {
209 trait_class.properties.iter().any(|p| p.name == member_name)
210 }
211 MemberKindForOrigin::Constant => {
212 trait_class.constants.iter().any(|c| c.name == member_name)
213 }
214 };
215 if has {
216 return trait_class;
217 }
218 }
219 }
220
221 // Walk the parent chain.
222 let mut ancestor_name = owner.parent_class;
223 let mut depth = 0u32;
224 while let Some(ref name) = ancestor_name {
225 depth += 1;
226 if depth > 20 {
227 break;
228 }
229 if let Some(ancestor) = class_loader(name) {
230 // Check traits on the ancestor first.
231 for trait_name in &ancestor.used_traits {
232 if let Some(trait_class) = class_loader(trait_name) {
233 let has = match member_kind {
234 MemberKindForOrigin::Method => trait_class
235 .methods
236 .iter()
237 .any(|m| m.name.eq_ignore_ascii_case(member_name)),
238 MemberKindForOrigin::Property => {
239 trait_class.properties.iter().any(|p| p.name == member_name)
240 }
241 MemberKindForOrigin::Constant => {
242 trait_class.constants.iter().any(|c| c.name == member_name)
243 }
244 };
245 if has {
246 return trait_class;

Calls 3

raw_class_has_memberFunction · 0.85
cloneMethod · 0.80
iterMethod · 0.80

Tested by

no test coverage detected