Resolve a `ClassReference` symbol to its definition. Tries same-file lookup (uri_classes_index), then cross-file via PSR-4. When `is_fqn` is `true`, the name is already fully-qualified (the original PHP source used a leading `\`) and should be used as-is without namespace resolution.
(
&self,
uri: &str,
content: &str,
name: &str,
is_fqn: bool,
cursor_offset: u32,
)
| 322 | /// (the original PHP source used a leading `\`) and should be used |
| 323 | /// as-is without namespace resolution. |
| 324 | pub(super) fn resolve_class_reference( |
| 325 | &self, |
| 326 | uri: &str, |
| 327 | content: &str, |
| 328 | name: &str, |
| 329 | is_fqn: bool, |
| 330 | cursor_offset: u32, |
| 331 | ) -> Option<Location> { |
| 332 | let mut candidates = if is_fqn { |
| 333 | // Already fully-qualified — use as-is. |
| 334 | vec![name.to_string()] |
| 335 | } else { |
| 336 | let ctx = self.file_context(uri); |
| 337 | let fqn = ctx.resolve_name_at(name, cursor_offset); |
| 338 | let mut c = vec![fqn]; |
| 339 | if name.contains('\\') && !c.contains(&name.to_string()) { |
| 340 | c.push(name.to_string()); |
| 341 | } |
| 342 | c |
| 343 | }; |
| 344 | // Always include the bare name as a last-resort candidate. |
| 345 | if !candidates.contains(&name.to_string()) { |
| 346 | candidates.push(name.to_string()); |
| 347 | } |
| 348 | |
| 349 | // Same-file lookup. |
| 350 | for fqn in &candidates { |
| 351 | if let Some(location) = self.find_definition_in_uri_classes_index(fqn, content, uri) { |
| 352 | return Some(location); |
| 353 | } |
| 354 | } |
| 355 | |
| 356 | // Cross-file lookup via fqn_uri_index + uri_classes_index. |
| 357 | // |
| 358 | // Classes discovered during autoload scanning (opened files, |
| 359 | // previously navigated-to vendor files) live in |
| 360 | // fqn_uri_index (FQN → URI) and uri_classes_index (URI → [ClassInfo]). |
| 361 | for fqn in &candidates { |
| 362 | let target_uri = self.fqn_uri_index.read().get(fqn.as_str()).cloned(); |
| 363 | if let Some(ref target_uri) = target_uri |
| 364 | && let Some(location) = |
| 365 | self.find_definition_in_uri_classes_index_cross_file(fqn, target_uri) |
| 366 | { |
| 367 | return Some(location); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | // Cross-file via PSR-4: parse on demand and cache. |
| 372 | // PSR-4 mappings only cover user code (from composer.json). |
| 373 | // Vendor classes are resolved by the class index above. |
| 374 | let workspace_root = self.workspace_root.read().clone(); |
| 375 | |
| 376 | if let Some(workspace_root) = workspace_root { |
| 377 | let mappings = self.psr4_mappings.read(); |
| 378 | for fqn in &candidates { |
| 379 | if let Some(file_path) = |
| 380 | composer::resolve_class_path(&mappings, &workspace_root, fqn) |
| 381 | && let Some(location) = self.resolve_class_in_file(&file_path, fqn) |
no test coverage detected