ide_completion/completions/attribute/
lint.rs

1//! Completion for lints
2use ide_db::{SymbolKind, documentation::Documentation, generated::lints::Lint};
3use syntax::ast;
4
5use crate::{Completions, context::CompletionContext, item::CompletionItem};
6
7pub(super) fn complete_lint(
8    acc: &mut Completions,
9    ctx: &CompletionContext<'_>,
10    is_qualified: bool,
11    existing_lints: &[ast::Path],
12    lints_completions: &[Lint],
13) {
14    for &Lint { label, description, .. } in lints_completions {
15        let (qual, name) = {
16            // FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead?
17            let mut parts = label.split("::");
18            let ns_or_label = match parts.next() {
19                Some(it) => it,
20                None => continue,
21            };
22            let label = parts.next();
23            match label {
24                Some(label) => (Some(ns_or_label), label),
25                None => (None, ns_or_label),
26            }
27        };
28        if qual.is_none() && is_qualified {
29            // qualified completion requested, but this lint is unqualified
30            continue;
31        }
32        let lint_already_annotated = existing_lints
33            .iter()
34            .filter_map(|path| {
35                let q = path.qualifier();
36                if q.as_ref().and_then(|it| it.qualifier()).is_some() {
37                    return None;
38                }
39                Some((q.and_then(|it| it.as_single_name_ref()), path.segment()?.name_ref()?))
40            })
41            .any(|(q, name_ref)| {
42                let qualifier_matches = match (q, qual) {
43                    (None, None) => true,
44                    (None, Some(_)) => false,
45                    (Some(_), None) => false,
46                    (Some(q), Some(ns)) => q.text() == ns,
47                };
48                qualifier_matches && name_ref.text() == name
49            });
50        if lint_already_annotated {
51            continue;
52        }
53        let label = match qual {
54            Some(qual) if !is_qualified => format!("{qual}::{name}"),
55            _ => name.to_owned(),
56        };
57        let mut item =
58            CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition);
59        item.documentation(Documentation::new_owned(description.to_owned()));
60        item.add_to(acc, ctx.db)
61    }
62}