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

Method try_member_access_completion

src/completion/handler.rs:895–1033  ·  view source on GitHub ↗

Try to offer member completions after `->`, `?->`, or `::`. Resolves the subject to one or more `ClassInfo` values, merges inherited members, and builds completion items filtered by access kind and visibility. Returns `None` when there is no access operator before the cursor or when resolution produces no results.

(
        &self,
        uri: &str,
        content: &str,
        position: Position,
        ctx: &FileContext,
    )

Source from the content-addressed store, hash-verified

893 /// Returns `None` when there is no access operator before the cursor
894 /// or when resolution produces no results.
895 fn try_member_access_completion(
896 &self,
897 uri: &str,
898 content: &str,
899 position: Position,
900 ctx: &FileContext,
901 ) -> Option<CompletionResponse> {
902 // ── Primary path: AST-based detection via symbol map ────────
903 // The symbol map's `MemberAccess` correctly handles `(new Foo)->`,
904 // call-result chains, array access chains, and null-safe chains.
905 // Fall back to text scanning when the symbol map has no hit.
906 let target = self
907 .extract_completion_target_from_symbol_map(uri, content, position)
908 .or_else(|| super::target::extract_completion_target(content, position))?;
909
910 let cursor_offset = position_to_offset(content, position);
911 let current_class = find_class_at_offset(&ctx.classes, cursor_offset);
912
913 let class_loader = self.class_loader(ctx);
914 let function_loader = self.function_loader(ctx);
915
916 // `static::` in a final class is equivalent to `self::` but
917 // suggests the class can be subclassed — which it can't.
918 // Suppress suggestions to nudge the developer toward `self::`.
919 let suppress = target.subject == "static" && current_class.is_some_and(|cc| cc.is_final);
920
921 // Wrap resolution + inheritance merging in catch_unwind so
922 // that a stack overflow (e.g. from deep trait/inheritance
923 // resolution when the subject is a call expression like
924 // `collect($x)->`) doesn't crash the LSP server process.
925 // The variable-resolution path already has its own
926 // catch_unwind, but the direct call-expression path
927 // (resolve_call_return_types_expr → type_hint_to_classes_typed →
928 // class_loader → find_or_load_class → parse_php →
929 // resolve_class_with_inheritance) does not.
930 let member_items = crate::util::catch_panic_unwind_safe(
931 "member-access completion",
932 uri,
933 Some(position),
934 || {
935 let candidates = if suppress {
936 vec![]
937 } else {
938 let rctx = ResolutionCtx {
939 current_class,
940 all_classes: &ctx.classes,
941 content,
942 cursor_offset,
943 class_loader: &class_loader,
944 resolved_class_cache: Some(&self.resolved_class_cache),
945 function_loader: Some(&function_loader),
946 scope_var_resolver: None,
947 is_in_static_method: false,
948 };
949 let mut resolved = super::resolver::resolve_target_classes(
950 &target.subject,
951 target.access_kind,
952 &rctx,

Callers 1

handle_completionMethod · 0.80

Calls 15

find_class_at_offsetFunction · 0.85
catch_panic_unwind_safeFunction · 0.85
resolve_target_classesFunction · 0.85
paren_follows_cursorFunction · 0.85
strip_snippet_parensFunction · 0.85
class_loaderMethod · 0.80
into_iterMethod · 0.80
parse_phpMethod · 0.80
position_to_offsetFunction · 0.50

Tested by

no test coverage detected