Version-aware variant of [`parse_and_cache_content`]. When `php_version` is `Some`, elements annotated with `#[PhpStormStubsElementAvailable]` whose version range excludes the target version are filtered out during extraction. Used when parsing phpstorm-stubs so that only the correct variant of each function, method, or parameter is presented. # Consistency model The five maps (`uri_classes_in
(
&self,
content: &str,
uri: &str,
php_version: Option<PhpVersion>,
)
| 352 | /// for consistency within the same request, the writes here must |
| 353 | /// be batched under a single coordination mechanism. |
| 354 | pub(crate) fn parse_and_cache_content_versioned( |
| 355 | &self, |
| 356 | content: &str, |
| 357 | uri: &str, |
| 358 | php_version: Option<PhpVersion>, |
| 359 | ) -> Option<Vec<Arc<ClassInfo>>> { |
| 360 | let file_use_map = self.parse_use_statements(content); |
| 361 | let file_namespace = self.parse_namespace(content); |
| 362 | |
| 363 | // Parse classes with per-class namespace tracking so that |
| 364 | // multi-namespace files (e.g. PDO.php with both `namespace { }` |
| 365 | // and `namespace Pdo { }`) resolve parent names correctly. |
| 366 | let classes_with_ns = Self::parse_php_versioned_with_namespaces(content, php_version); |
| 367 | |
| 368 | // Group classes by their enclosing namespace and resolve parent |
| 369 | // names once per group, mirroring the logic in `update_ast_inner`. |
| 370 | let mut classes: Vec<ClassInfo> = Vec::with_capacity(classes_with_ns.len()); |
| 371 | let mut ns_groups: HashMap<Option<String>, Vec<usize>> = HashMap::new(); |
| 372 | for (i, (_cls, ns)) in classes_with_ns.iter().enumerate() { |
| 373 | ns_groups.entry(ns.clone()).or_default().push(i); |
| 374 | } |
| 375 | |
| 376 | // Flatten into a single Vec, preserving original order. |
| 377 | for (cls, _) in &classes_with_ns { |
| 378 | classes.push(cls.clone()); |
| 379 | } |
| 380 | |
| 381 | if ns_groups.len() <= 1 { |
| 382 | // Single namespace (common case): resolve with file namespace. |
| 383 | Self::resolve_parent_class_names(&mut classes, &file_use_map, &file_namespace); |
| 384 | } else { |
| 385 | // Multi-namespace file: resolve each group with its own |
| 386 | // namespace context so that classes in `namespace { }` are |
| 387 | // not polluted by a sibling `namespace Pdo { }` block. |
| 388 | for (group_ns, indices) in &ns_groups { |
| 389 | let mut group: Vec<ClassInfo> = |
| 390 | indices.iter().map(|&i| classes[i].clone()).collect(); |
| 391 | Self::resolve_parent_class_names(&mut group, &file_use_map, group_ns); |
| 392 | for (j, &idx) in indices.iter().enumerate() { |
| 393 | classes[idx] = group[j].clone(); |
| 394 | } |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | // Set the per-class file_namespace so that classes loaded via |
| 399 | // PSR-4 / class index carry their namespace. This mirrors the |
| 400 | // same assignment done in `update_ast_inner` for files opened |
| 401 | // through `did_open` / `did_change`. |
| 402 | for (i, cls) in classes.iter_mut().enumerate() { |
| 403 | if cls.file_namespace.is_none() { |
| 404 | cls.file_namespace = classes_with_ns[i] |
| 405 | .1 |
| 406 | .as_deref() |
| 407 | .or(file_namespace.as_deref()) |
| 408 | .map(crate::atom::atom); |
| 409 | } |
| 410 | } |
| 411 |
no test coverage detected