Resolve implementations of a method call on an interface/abstract class.
(
&self,
uri: &str,
content: &str,
position: Position,
member_name: &str,
ctx: &FileContext,
)
| 452 | |
| 453 | /// Resolve implementations of a method call on an interface/abstract class. |
| 454 | fn resolve_member_implementations( |
| 455 | &self, |
| 456 | uri: &str, |
| 457 | content: &str, |
| 458 | position: Position, |
| 459 | member_name: &str, |
| 460 | ctx: &FileContext, |
| 461 | ) -> Option<Vec<Location>> { |
| 462 | // Extract the subject (left side of -> or ::). |
| 463 | let (subject, access_kind) = self.lookup_member_access_context(uri, content, position)?; |
| 464 | |
| 465 | let cursor_offset = position_to_offset(content, position); |
| 466 | let current_class = find_class_at_offset(&ctx.classes, cursor_offset); |
| 467 | |
| 468 | let class_loader = self.class_loader(ctx); |
| 469 | let function_loader = self.function_loader(ctx); |
| 470 | |
| 471 | // Resolve the subject to candidate classes. |
| 472 | let rctx = ResolutionCtx { |
| 473 | current_class, |
| 474 | all_classes: &ctx.classes, |
| 475 | content, |
| 476 | cursor_offset, |
| 477 | class_loader: &class_loader, |
| 478 | resolved_class_cache: Some(&self.resolved_class_cache), |
| 479 | function_loader: Some(&function_loader), |
| 480 | scope_var_resolver: None, |
| 481 | is_in_static_method: false, |
| 482 | }; |
| 483 | |
| 484 | let candidates = ResolvedType::into_arced_classes( |
| 485 | crate::completion::resolver::resolve_target_classes(&subject, access_kind, &rctx), |
| 486 | ); |
| 487 | |
| 488 | if candidates.is_empty() { |
| 489 | return None; |
| 490 | } |
| 491 | |
| 492 | // Check if ANY candidate is an interface or abstract class with this |
| 493 | // method. If so, find all implementors that have the method. |
| 494 | let mut all_locations = Vec::new(); |
| 495 | |
| 496 | for candidate in &candidates { |
| 497 | if candidate.kind != ClassLikeKind::Interface && !candidate.is_abstract { |
| 498 | continue; |
| 499 | } |
| 500 | |
| 501 | // Verify the method exists on this interface/abstract class |
| 502 | // (directly or inherited). |
| 503 | let merged = crate::virtual_members::resolve_class_fully_cached( |
| 504 | candidate, |
| 505 | &class_loader, |
| 506 | &self.resolved_class_cache, |
| 507 | ); |
| 508 | let has_method = merged.has_method(member_name); |
| 509 | let has_property = merged.properties.iter().any(|p| p.name == member_name); |
| 510 | |
| 511 | if !has_method && !has_property { |
no test coverage detected