Inner implementation of [`update_ast`] that performs the actual parsing and map updates. Separated so that [`update_ast`] can wrap the call in [`std::panic::catch_unwind`]. Returns `true` when at least one class signature changed.
(&self, uri: &str, content: &str)
| 86 | /// |
| 87 | /// Returns `true` when at least one class signature changed. |
| 88 | fn update_ast_inner(&self, uri: &str, content: &str) -> bool { |
| 89 | let arena = Bump::new(); |
| 90 | let file_id = mago_database::file::FileId::new("input.php"); |
| 91 | let program = parse_file_content(&arena, file_id, content); |
| 92 | |
| 93 | // Run mago-names resolver while the arena is still alive. |
| 94 | // This produces a `ResolvedNames` that maps every identifier's |
| 95 | // byte offset to its fully-qualified name. We immediately copy |
| 96 | // the data into an owned `OwnedResolvedNames` so it survives |
| 97 | // the arena drop. |
| 98 | let name_resolver = mago_names::resolver::NameResolver::new(&arena); |
| 99 | let mago_resolved = name_resolver.resolve(program); |
| 100 | let owned_resolved = crate::names::OwnedResolvedNames::from_resolved(&mago_resolved); |
| 101 | |
| 102 | // Cache parse errors for the syntax-error diagnostic collector. |
| 103 | // Extract (message, start_byte, end_byte) tuples from the |
| 104 | // arena-allocated errors before the arena is dropped. |
| 105 | { |
| 106 | use mago_span::HasSpan; |
| 107 | |
| 108 | let errors: Vec<(String, u32, u32)> = program |
| 109 | .errors |
| 110 | .iter() |
| 111 | .map(|e| { |
| 112 | let span = e.span(); |
| 113 | ( |
| 114 | super::error_format::format_parse_error(e), |
| 115 | span.start.offset, |
| 116 | span.end.offset, |
| 117 | ) |
| 118 | }) |
| 119 | .collect(); |
| 120 | self.parse_errors.write().insert(uri.to_string(), errors); |
| 121 | } |
| 122 | |
| 123 | let doc_ctx = DocblockCtx { |
| 124 | trivias: program.trivia.as_slice(), |
| 125 | content, |
| 126 | php_version: Some(self.php_version()), |
| 127 | use_map: HashMap::new(), |
| 128 | namespace: None, |
| 129 | }; |
| 130 | |
| 131 | // Extract all three in a single parse pass. |
| 132 | // |
| 133 | // `classes_with_ns` tracks each extracted class together with the |
| 134 | // namespace block it was declared in. This is critical for files |
| 135 | // that contain multiple `namespace { }` blocks (e.g. example.php |
| 136 | // places demo classes in `Demo` and Illuminate stubs in their own |
| 137 | // namespace blocks). The per-class namespace is used later when |
| 138 | // building the `fqn_uri_index` and when resolving parent/trait names. |
| 139 | let mut classes_with_ns: Vec<(ClassInfo, Option<String>)> = Vec::new(); |
| 140 | let mut use_map = HashMap::new(); |
| 141 | let mut namespace: Option<String> = None; |
| 142 | let mut namespace_spans: Vec<crate::types::NamespaceSpan> = Vec::new(); |
| 143 | |
| 144 | for statement in program.statements.iter() { |
| 145 | match statement { |
no test coverage detected