<commit_before>//! Completion for attributes
//!
//! This module uses a bit of static metadata to provide completions
//! for built-in attributes.

use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{ast, AstNode, SyntaxKind};

use crate::{
    context::CompletionContext,
    generated_lint_completions::{CLIPPY_LINTS, FEATURES},
    item::{CompletionItem, CompletionItemKind, CompletionKind},
    Completions,
};

pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    if ctx.mod_declaration_under_caret.is_some() {
        return None;
    }

    let attribute = ctx.attribute_under_caret.as_ref()?;
    match (attribute.path(), attribute.token_tree()) {
        (Some(path), Some(token_tree)) if path.to_string() == "derive" => {
            complete_derive(acc, ctx, token_tree)
        }
        (Some(path), Some(token_tree)) if path.to_string() == "feature" => {
            complete_lint(acc, ctx, token_tree, FEATURES);
        }
        (Some(path), Some(token_tree))
            if ["allow", "warn", "deny", "forbid"]
                .iter()
                .any(|lint_level| lint_level == &path.to_string()) =>
        {
            complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
            complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
        }
        (_, Some(_token_tree)) => {}
        _ => complete_attribute_start(acc, ctx, attribute),
    }
    Some(())
}

fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
    for attr_completion in ATTRIBUTES {
        let mut item = CompletionItem::new(
            CompletionKind::Attribute,
            ctx.source_range(),
            attr_completion.label,
        )
        .kind(CompletionItemKind::Attribute);

        if let Some(lookup) = attr_completion.lookup {
            item = item.lookup_by(lookup);
        }

        match (attr_completion.snippet, ctx.config.snippet_cap) {
            (Some(snippet), Some(cap)) => {
                item = item.insert_snippet(cap, snippet);
            }
            _ => {}
        }

        if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
            acc.add(item.build());
        }
    }
}

struct AttrCompletion {
    label: &'static str,
    lookup: Option<&'static str>,
    snippet: Option<&'static str>,
    prefer_inner: bool,
}

impl AttrCompletion {
    const fn prefer_inner(self) -> AttrCompletion {
        AttrCompletion { prefer_inner: true, ..self }
    }
}

const fn attr(
    label: &'static str,
    lookup: Option<&'static str>,
    snippet: Option<&'static str>,
) -> AttrCompletion {
    AttrCompletion { label, lookup, snippet, prefer_inner: false }
}

/// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index
const ATTRIBUTES: &[AttrCompletion] = &[
    attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
    attr("automatically_derived", None, None),
    attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
    attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
    attr("cold", None, None),
    attr(r#"crate_name = """#, Some("crate_name"), Some(r#"crate_name = "${0:crate_name}""#))
        .prefer_inner(),
    attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
    attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
    attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
    attr(
        r#"export_name = "…""#,
        Some("export_name"),
        Some(r#"export_name = "${0:exported_symbol_name}""#),
    ),
    attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
    attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
    attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
    // FIXME: resolve through macro resolution?
    attr("global_allocator", None, None).prefer_inner(),
    attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
    attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
    attr("link", None, None),
    attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
    attr(
        r#"link_section = "…""#,
        Some("link_section"),
        Some(r#"link_section = "${0:section_name}""#),
    ),
    attr("macro_export", None, None),
    attr("macro_use", None, None),
    attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
    attr("no_link", None, None).prefer_inner(),<commit_msg>Remove a part of the deprecated autocompletion<commit_after>//! Completion for attributes
//!
//! This module uses a bit of static metadata to provide completions
//! for built-in attributes.

use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{ast, AstNode, SyntaxKind};

use crate::{
    context::CompletionContext,
    generated_lint_completions::{CLIPPY_LINTS, FEATURES},
    item::{CompletionItem, CompletionItemKind, CompletionKind},
    Completions,
};

pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
    if ctx.mod_declaration_under_caret.is_some() {
        return None;
    }

    let attribute = ctx.attribute_under_caret.as_ref()?;
    match (attribute.path(), attribute.token_tree()) {
        (Some(path), Some(token_tree)) if path.to_string() == "derive" => {
            complete_derive(acc, ctx, token_tree)
        }
        (Some(path), Some(token_tree)) if path.to_string() == "feature" => {
            complete_lint(acc, ctx, token_tree, FEATURES);
        }
        (Some(path), Some(token_tree))
            if ["allow", "warn", "deny", "forbid"]
                .iter()
                .any(|lint_level| lint_level == &path.to_string()) =>
        {
            complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
            complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
        }
        (_, Some(_token_tree)) => {}
        _ => complete_attribute_start(acc, ctx, attribute),
    }
    Some(())
}

fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
    for attr_completion in ATTRIBUTES {
        let mut item = CompletionItem::new(
            CompletionKind::Attribute,
            ctx.source_range(),
            attr_completion.label,
        )
        .kind(CompletionItemKind::Attribute);

        if let Some(lookup) = attr_completion.lookup {
            item = item.lookup_by(lookup);
        }

        match (attr_completion.snippet, ctx.config.snippet_cap) {
            (Some(snippet), Some(cap)) => {
                item = item.insert_snippet(cap, snippet);
            }
            _ => {}
        }

        if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
            acc.add(item.build());
        }
    }
}

struct AttrCompletion {
    label: &'static str,
    lookup: Option<&'static str>,
    snippet: Option<&'static str>,
    prefer_inner: bool,
}

impl AttrCompletion {
    const fn prefer_inner(self) -> AttrCompletion {
        AttrCompletion { prefer_inner: true, ..self }
    }
}

const fn attr(
    label: &'static str,
    lookup: Option<&'static str>,
    snippet: Option<&'static str>,
) -> AttrCompletion {
    AttrCompletion { label, lookup, snippet, prefer_inner: false }
}

/// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index
const ATTRIBUTES: &[AttrCompletion] = &[
    attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
    attr("automatically_derived", None, None),
    attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
    attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
    attr("cold", None, None),
    attr(r#"crate_name = """#, Some("crate_name"), Some(r#"crate_name = "${0:crate_name}""#))
        .prefer_inner(),
    attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
    attr(r#"deprecated "…""#, Some("deprecated"), Some(r#"deprecated"#)),
    attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
    attr(
        r#"export_name = "…""#,
        Some("export_name"),
        Some(r#"export_name = "${0:exported_symbol_name}""#),
    ),
    attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
    attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
    attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
    // FIXME: resolve through macro resolution?
    attr("global_allocator", None, None).prefer_inner(),
    attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
    attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
    attr("link", None, None),
    attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
    attr(
        r#"link_section = "…""#,
        Some("link_section"),
        Some(r#"link_section = "${0:section_name}""#),
    ),
    attr("macro_export", None, None),
    attr("macro_use", None, None),
    attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
    attr("no_link", None, None).prefer_inner(),
{'fraction_non_alphanumeric': 0.19451371571072318, 'fraction_numerical': 0.0035780114930066137, 'mean_word_length': 3.4049665711556827, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 33, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2226990', 'n_tokens_mistral': 3103, 'n_tokens_neox': 3071, 'n_words': 548}