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

Method find_or_load_function

src/resolution.rs:536–684  ·  view source on GitHub ↗

Try to find a standalone function by name, checking user-defined functions first, then falling back to embedded PHP stubs. The lookup order is: 1. `global_functions` — functions from Composer autoload files and opened/changed files. 2. `stub_function_index` — built-in PHP functions embedded from phpstorm-stubs. Parsed lazily on first access and cached in `global_functions` under a `phpantom-stub

(&self, candidates: &[&str])

Source from the content-addressed store, hash-verified

534 /// FQN via use-map, the namespace-qualified name). The first match
535 /// wins.
536 pub fn find_or_load_function(&self, candidates: &[&str]) -> Option<FunctionInfo> {
537 // ── Phase 1: Check global_functions (user code + already-cached stubs) ──
538 {
539 let fmap = self.global_functions.read();
540 for &name in candidates {
541 if let Some((_, info)) = fmap.get(name) {
542 return Some(info.clone());
543 }
544 }
545 }
546
547 // ── Phase 1.5: Check autoload_function_index (byte-level scan) ──
548 // The lightweight `find_symbols` byte-level scan discovers
549 // function names at startup without a full AST parse, for both
550 // non-Composer projects (workspace scan) and Composer projects
551 // (autoload_files.php scan). When a candidate matches here, we
552 // lazily call `update_ast` on the file to get a complete
553 // `FunctionInfo` and cache it in global_functions so subsequent
554 // lookups hit Phase 1.
555 //
556 // Note: the lazy parse is a full AST parse (`update_ast`), which
557 // is the same cost as opening the file. This is acceptable
558 // because it only happens once per function, on first access.
559 {
560 let idx = self.autoload_function_index.read();
561 for &name in candidates {
562 if let Some(path) = idx.get(name) {
563 let path = path.clone();
564 drop(idx); // release read lock before parsing
565
566 if let Ok(content) = std::fs::read_to_string(&path) {
567 let uri = crate::util::path_to_uri(&path);
568 self.update_ast(&uri, &content);
569
570 // Re-check global_functions after parsing.
571 let fmap = self.global_functions.read();
572 for &retry_name in candidates {
573 if let Some((_, info)) = fmap.get(retry_name) {
574 return Some(info.clone());
575 }
576 }
577 }
578 break; // Only try one file per lookup
579 }
580 }
581 }
582
583 // ── Phase 1.75: Last-resort lazy parse of known autoload files ──
584 // The byte-level scanner misses functions wrapped in
585 // `if (! function_exists(...))` guards (brace depth > 0).
586 // These are common in Laravel helpers and similar packages.
587 // As a safety net, lazily parse each known autoload file via
588 // `update_ast` until the function is found. Each file is
589 // parsed at most once: subsequent lookups hit Phase 1
590 // (`global_functions`).
591 {
592 let paths = self.autoload_file_paths.read().clone();
593 for path in &paths {

Calls 14

path_to_uriFunction · 0.85
cloneMethod · 0.80
update_astMethod · 0.80
containsMethod · 0.80
php_versionMethod · 0.80
writeMethod · 0.80
parse_namespaceMethod · 0.80
into_iterMethod · 0.80
getMethod · 0.45
is_emptyMethod · 0.45