Build completion items for PHPDoc tags based on context. `content` is the full file text (used to extract symbol info and detect already-documented parameters). `prefix` is the partial tag the user has typed (e.g. `"@par"`, `"@"`). `context` indicates what PHP symbol follows the docblock. `position` is the cursor position (used to scan the docblock and the following declaration). `use_map` maps s
(
content: &str,
prefix: &str,
context: DocblockContext,
position: Position,
use_map: &HashMap<String, String>,
file_namespace: &Option<String>,
smart: &SmartContext<'_>,
)
| 511 | /// |
| 512 | /// Returns the list of matching `CompletionItem`s. |
| 513 | pub fn build_phpdoc_completions( |
| 514 | content: &str, |
| 515 | prefix: &str, |
| 516 | context: DocblockContext, |
| 517 | position: Position, |
| 518 | use_map: &HashMap<String, String>, |
| 519 | file_namespace: &Option<String>, |
| 520 | smart: &SmartContext<'_>, |
| 521 | ) -> Vec<CompletionItem> { |
| 522 | let prefix_lower = prefix.to_lowercase(); |
| 523 | let mut seen = std::collections::HashSet::new(); |
| 524 | let mut items = Vec::new(); |
| 525 | |
| 526 | // Extract symbol info for smart pre-filling |
| 527 | let sym = extract_symbol_info(content, position); |
| 528 | |
| 529 | // Collect all applicable tag lists based on context |
| 530 | let tag_lists: Vec<&[TagDef]> = match context { |
| 531 | DocblockContext::FunctionOrMethod => { |
| 532 | vec![FUNCTION_TAGS, GENERAL_TAGS, PHPSTAN_FUNCTION_TAGS] |
| 533 | } |
| 534 | DocblockContext::ClassLike => vec![CLASS_TAGS, GENERAL_TAGS, PHPSTAN_CLASS_TAGS], |
| 535 | DocblockContext::Property => vec![PROPERTY_TAGS, GENERAL_TAGS, PHPSTAN_PROPERTY_TAGS], |
| 536 | DocblockContext::Constant => vec![CONSTANT_TAGS, GENERAL_TAGS], |
| 537 | DocblockContext::Inline => vec![INLINE_TAGS], |
| 538 | DocblockContext::Unknown => vec![ |
| 539 | FUNCTION_TAGS, |
| 540 | CLASS_TAGS, |
| 541 | PROPERTY_TAGS, |
| 542 | GENERAL_TAGS, |
| 543 | PHPSTAN_FUNCTION_TAGS, |
| 544 | PHPSTAN_CLASS_TAGS, |
| 545 | PHPSTAN_PROPERTY_TAGS, |
| 546 | ], |
| 547 | }; |
| 548 | |
| 549 | for tags in tag_lists { |
| 550 | for def in tags { |
| 551 | if !def.tag.to_lowercase().starts_with(&prefix_lower) { |
| 552 | continue; |
| 553 | } |
| 554 | if !seen.insert(def.tag) { |
| 555 | continue; |
| 556 | } |
| 557 | |
| 558 | // ── Smart items for @throws ───────────────────────────── |
| 559 | if def.tag == "@throws" |
| 560 | && matches!( |
| 561 | context, |
| 562 | DocblockContext::FunctionOrMethod | DocblockContext::Unknown |
| 563 | ) |
| 564 | { |
| 565 | let uncaught = if let Some(cl) = smart.class_loader { |
| 566 | throws_analysis::find_uncaught_throw_types_with_context( |
| 567 | content, |
| 568 | position, |
| 569 | Some(&ThrowsContext { |
| 570 | class_loader: cl, |