Resolve a static class reference + method name to a [`ResolvedCallableTarget`]. Resolves the class via [`super::resolver::resolve_static_owner_class`], merges via `resolve_class_fully`, and looks up `method_name`.
(
class: &str,
method_name: &str,
rctx: &ResolutionCtx<'_>,
args_text: Option<&str>,
)
| 533 | /// Resolves the class via [`super::resolver::resolve_static_owner_class`], merges |
| 534 | /// via `resolve_class_fully`, and looks up `method_name`. |
| 535 | fn resolve_static_method_callable( |
| 536 | class: &str, |
| 537 | method_name: &str, |
| 538 | rctx: &ResolutionCtx<'_>, |
| 539 | args_text: Option<&str>, |
| 540 | ) -> Option<ResolvedCallableTarget> { |
| 541 | let owner = super::resolver::resolve_static_owner_class(class, rctx)?; |
| 542 | |
| 543 | // When the class has template params, try to substitute them with |
| 544 | // concrete types. For `parent::` calls, use the child's @extends |
| 545 | // generics to get the concrete type arguments. Otherwise fall back |
| 546 | // to upper bounds / `mixed`. |
| 547 | let merged = if !owner.template_params.is_empty() { |
| 548 | let type_args = if class.eq_ignore_ascii_case("parent") { |
| 549 | // Look up the child's extends_generics for the parent class |
| 550 | rctx.current_class.and_then(|child| { |
| 551 | let parent_short = crate::util::short_name(&owner.name); |
| 552 | child |
| 553 | .extends_generics |
| 554 | .iter() |
| 555 | .find(|(name, _)| crate::util::short_name(name) == parent_short) |
| 556 | .map(|(_, args)| args.clone()) |
| 557 | }) |
| 558 | } else { |
| 559 | None |
| 560 | }; |
| 561 | let args = type_args.unwrap_or_else(|| crate::inheritance::default_type_args(&owner)); |
| 562 | let base = crate::virtual_members::resolve_class_fully_maybe_cached( |
| 563 | &owner, |
| 564 | rctx.class_loader, |
| 565 | rctx.resolved_class_cache, |
| 566 | ); |
| 567 | Arc::new(crate::inheritance::apply_generic_args(&base, &args)) |
| 568 | } else { |
| 569 | crate::virtual_members::resolve_class_fully_maybe_cached( |
| 570 | &owner, |
| 571 | rctx.class_loader, |
| 572 | rctx.resolved_class_cache, |
| 573 | ) |
| 574 | }; |
| 575 | |
| 576 | let m = merged.get_method_ci(method_name)?; |
| 577 | |
| 578 | let mut result_method = m.clone(); |
| 579 | |
| 580 | // Apply method-level template substitutions when call-site |
| 581 | // argument text is available. |
| 582 | if let Some(at) = args_text { |
| 583 | let split_args = crate::completion::types::conditional::split_text_args(at); |
| 584 | let method_subs = |
| 585 | Self::build_method_template_subs(&merged, method_name, &split_args, rctx); |
| 586 | if !method_subs.is_empty() { |
| 587 | crate::inheritance::apply_substitution_to_method(&mut result_method, &method_subs); |
| 588 | } |
| 589 | } |
| 590 | |
| 591 | Some(ResolvedCallableTarget { |
| 592 | parameters: result_method.parameters.clone(), |
nothing calls this directly
no test coverage detected