Find the enclosing function/method and its docblock by walking backward from the given line. We find the function signature by tracking brace depth: from the diagnostic line we walk backward until we find the opening `{` at depth -1 (exiting the function body). Then we look backward past modifiers to find the docblock.
(content: &str, diag_line: usize)
| 272 | /// depth -1 (exiting the function body). Then we look backward past |
| 273 | /// modifiers to find the docblock. |
| 274 | fn find_enclosing_docblock(content: &str, diag_line: usize) -> Option<DocblockInfo> { |
| 275 | let lines: Vec<&str> = content.lines().collect(); |
| 276 | if diag_line >= lines.len() { |
| 277 | return None; |
| 278 | } |
| 279 | |
| 280 | // Convert the diagnostic line to a byte offset to start searching. |
| 281 | let mut diag_byte_offset = 0usize; |
| 282 | for (i, line) in lines.iter().enumerate() { |
| 283 | if i == diag_line { |
| 284 | break; |
| 285 | } |
| 286 | diag_byte_offset += line.len() + 1; // +1 for newline |
| 287 | } |
| 288 | |
| 289 | let search_area = content.get(..diag_byte_offset)?; |
| 290 | |
| 291 | // Walk backward tracking brace depth to find the opening `{` of |
| 292 | // the enclosing function body. |
| 293 | let mut brace_depth = 0i32; |
| 294 | let mut func_open_brace: Option<usize> = None; |
| 295 | |
| 296 | for (i, ch) in search_area.char_indices().rev() { |
| 297 | match ch { |
| 298 | '}' => brace_depth += 1, |
| 299 | '{' => { |
| 300 | brace_depth -= 1; |
| 301 | if brace_depth < 0 { |
| 302 | func_open_brace = Some(i); |
| 303 | break; |
| 304 | } |
| 305 | } |
| 306 | _ => {} |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | let brace_pos = func_open_brace?; |
| 311 | |
| 312 | // Find the `function` keyword before the brace. |
| 313 | let before_brace = content.get(..brace_pos)?; |
| 314 | let mut sig_start = before_brace.len().saturating_sub(2000); |
| 315 | while sig_start > 0 && !before_brace.is_char_boundary(sig_start) { |
| 316 | sig_start -= 1; |
| 317 | } |
| 318 | let sig_region = &before_brace[sig_start..]; |
| 319 | let func_kw_rel = sig_region.rfind("function")?; |
| 320 | let func_kw_pos = sig_start + func_kw_rel; |
| 321 | |
| 322 | // Walk backward from `function` past modifier keywords and whitespace |
| 323 | // to find where the signature truly starts (for docblock detection). |
| 324 | let before_func = content.get(..func_kw_pos)?; |
| 325 | let trimmed = before_func.trim_end(); |
| 326 | |
| 327 | // Strip trailing modifier keywords (public, protected, private, static, |
| 328 | // abstract, final, readonly). |
| 329 | let after_mods = strip_trailing_modifiers(trimmed); |
| 330 | |
| 331 | // Determine the byte offset of the start of the signature line |