Analyse the file content and return a [`UseBlockInfo`] describing the existing `use` block. This replaces the older `find_use_insert_position` — instead of a single append-at-bottom position, callers get a structure that supports alphabetical insertion via [`UseBlockInfo::insert_position_for`]. The scanning logic distinguishes top-level `use` imports from trait `use` statements inside class/enum
(content: &str)
| 231 | /// `use` statements inside class/enum/trait bodies by tracking brace |
| 232 | /// depth. |
| 233 | pub(crate) fn analyze_use_block(content: &str) -> UseBlockInfo { |
| 234 | let mut existing: Vec<(u32, String)> = Vec::new(); |
| 235 | let mut namespace_line: Option<u32> = None; |
| 236 | let mut php_open_line: Option<u32> = None; |
| 237 | |
| 238 | // Track brace depth so we can distinguish top-level `use` imports |
| 239 | // from trait `use` statements inside class/enum/trait bodies. |
| 240 | // |
| 241 | // With semicolon-style namespaces (`namespace Foo;`), imports live |
| 242 | // at depth 0 and class bodies are at depth 1. |
| 243 | // |
| 244 | // With brace-style namespaces (`namespace Foo { ... }`), imports |
| 245 | // live at depth 1 and class bodies are at depth 2. |
| 246 | // |
| 247 | // We compute depth at the START of each line and track whether we |
| 248 | // saw a brace-style namespace to set the right threshold. |
| 249 | let mut brace_depth: u32 = 0; |
| 250 | let mut uses_brace_namespace = false; |
| 251 | |
| 252 | for (i, line) in content.lines().enumerate() { |
| 253 | let trimmed = line.trim(); |
| 254 | |
| 255 | // The depth at the start of this line (before counting its braces). |
| 256 | let depth_at_start = brace_depth; |
| 257 | |
| 258 | // Update brace depth for the NEXT line. |
| 259 | for ch in trimmed.chars() { |
| 260 | match ch { |
| 261 | '{' => brace_depth += 1, |
| 262 | '}' => brace_depth = brace_depth.saturating_sub(1), |
| 263 | _ => {} |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | if trimmed.starts_with("<?php") && php_open_line.is_none() { |
| 268 | php_open_line = Some(i as u32); |
| 269 | } |
| 270 | |
| 271 | // Match `namespace Foo\Bar;` or `namespace Foo\Bar {` |
| 272 | // but not `namespace\something` (which is a different construct). |
| 273 | if trimmed.starts_with("namespace ") || trimmed.starts_with("namespace\t") { |
| 274 | namespace_line = Some(i as u32); |
| 275 | if trimmed.contains('{') { |
| 276 | uses_brace_namespace = true; |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | // The maximum brace depth at which `use` statements are still |
| 281 | // namespace imports (not trait imports inside a class body). |
| 282 | let max_import_depth = if uses_brace_namespace { 1 } else { 0 }; |
| 283 | |
| 284 | // Match `use Foo\Bar;`, `use Foo\{Bar, Baz};`, etc. |
| 285 | // Only at the import level — deeper means trait `use` inside a |
| 286 | // class/enum/trait body. |
| 287 | if depth_at_start <= max_import_depth |
| 288 | && (trimmed.starts_with("use ") || trimmed.starts_with("use\t")) |
| 289 | && !trimmed.starts_with("use (") |
| 290 | && !trimmed.starts_with("use(") |