//! Completion tests for attributes.
use expect_test::expect;

use crate::tests::{check, check_edit};

#[test]
fn derive_helpers() {
    check(
        r#"
//- /mac.rs crate:mac
#![crate_type = "proc-macro"]

#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))]
pub fn my_derive() {}

//- /lib.rs crate:lib deps:mac
#[rustc_builtin_macro]
pub macro derive($item:item) {}

#[derive(mac::MyDerive)]
pub struct Foo(#[m$0] i32);
"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at derive                                  macro derive
            at derive(…)
            at diagnostic::do_not_recommend
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at ignore = "…"
            at inline
            at link
            at link_name = "…"
            at link_section = "…"
            at macro_export
            at macro_use
            at must_use
            at my_cool_helper_attribute derive helper of `MyDerive`
            at no_mangle
            at non_exhaustive
            at panic_handler
            at path = "…"
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at repr(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at unsafe(…)
            at used
            at warn(…)
            md mac::
            kw crate::
            kw self::
        "#]],
    );
    check(
        r#"
//- /mac.rs crate:mac
#![crate_type = "proc-macro"]

#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))]
pub fn my_derive() {}

//- /lib.rs crate:lib deps:mac
#[rustc_builtin_macro]
pub macro derive($item:item) {}

#[derive(mac::MyDerive)]
pub struct Foo(#[$0] i32);
"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at derive                                  macro derive
            at derive(…)
            at diagnostic::do_not_recommend
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at ignore = "…"
            at inline
            at link
            at link_name = "…"
            at link_section = "…"
            at macro_export
            at macro_use
            at must_use
            at my_cool_helper_attribute derive helper of `MyDerive`
            at no_mangle
            at non_exhaustive
            at panic_handler
            at path = "…"
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at repr(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at unsafe(…)
            at used
            at warn(…)
            md mac::
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn proc_macros() {
    check(
        r#"
//- proc_macros: identity
#[$0]
struct Foo;
"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at derive(…)
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at non_exhaustive
            at repr(…)
            at unsafe(…)
            at warn(…)
            md proc_macros::
            kw crate::
            kw self::
        "#]],
    )
}

#[test]
fn proc_macros_on_comment() {
    check(
        r#"
//- proc_macros: identity
/// $0
#[proc_macros::identity]
struct Foo;
"#,
        expect![[r#""#]],
    )
}

#[test]
fn proc_macros_qualified() {
    check(
        r#"
//- proc_macros: identity
#[proc_macros::$0]
struct Foo;
"#,
        expect![[r#"
            at identity proc_macro identity
        "#]],
    )
}

#[test]
fn with_existing_attr() {
    check(
        r#"#[no_mangle] #[$0] mcall!();"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at expect(…)
            at forbid(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    )
}

#[test]
fn attr_on_source_file() {
    check(
        r#"#![$0]"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at crate_name = ""
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at feature(…)
            at forbid(…)
            at must_use
            at no_implicit_prelude
            at no_main
            at no_mangle
            at no_std
            at recursion_limit = "…"
            at type_length_limit = …
            at unsafe(…)
            at warn(…)
            at windows_subsystem = "…"
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_module() {
    check(
        r#"#[$0] mod foo;"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at macro_use
            at must_use
            at no_mangle
            at path = "…"
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
            kw super::
        "#]],
    );
    check(
        r#"mod foo {#![$0]}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_implicit_prelude
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
            kw super::
        "#]],
    );
}

#[test]
fn attr_on_macro_rules() {
    check(
        r#"#[$0] macro_rules! foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at macro_export
            at macro_use
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_macro_def() {
    check(
        r#"#[$0] macro foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_extern_crate() {
    check(
        r#"#[$0] extern crate foo;"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at macro_use
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_use() {
    check(
        r#"#[$0] use foo;"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_type_alias() {
    check(
        r#"#[$0] type foo = ();"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_struct() {
    check(
        r#"
//- minicore:derive
#[$0]
struct Foo;
"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at derive             macro derive
            at derive(…)
            at derive_const macro derive_const
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at non_exhaustive
            at repr(…)
            at unsafe(…)
            at warn(…)
            md core::
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_enum() {
    check(
        r#"#[$0] enum Foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at derive(…)
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at non_exhaustive
            at repr(…)
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_const() {
    check(
        r#"#[$0] const FOO: () = ();"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_static() {
    check(
        r#"#[$0] static FOO: () = ()"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at link_name = "…"
            at link_section = "…"
            at must_use
            at no_mangle
            at unsafe(…)
            at used
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_trait() {
    check(
        r#"#[$0] trait Foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_impl() {
    check(
        r#"#[$0] impl () {}"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at diagnostic::do_not_recommend
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
    check(
        r#"impl () {#![$0]}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_with_qualifier() {
    check(
        r#"#[diagnostic::$0] impl () {}"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at do_not_recommend
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
        "#]],
    );
    check(
        r#"#[diagnostic::$0] trait Foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at on_unimplemented
            at unsafe(…)
            at warn(…)
        "#]],
    );
}

#[test]
fn attr_on_unsafe_attr() {
    check(
        r#"#[unsafe($0)] static FOO: () = ()"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at link_name = "…"
            at link_section = "…"
            at must_use
            at no_mangle
            at unsafe(…)
            at used
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_diagnostic_on_unimplemented() {
    check(
        r#"#[diagnostic::on_unimplemented($0)] trait Foo {}"#,
        expect![[r#"
            ba label = "…"
            ba message = "…"
            ba note = "…"
        "#]],
    );
    check(
        r#"#[diagnostic::on_unimplemented(message = "foo", $0)] trait Foo {}"#,
        expect![[r#"
            ba label = "…"
            ba note = "…"
        "#]],
    );
    check(
        r#"#[diagnostic::on_unimplemented(note = "foo", $0)] trait Foo {}"#,
        expect![[r#"
            ba label = "…"
            ba message = "…"
            ba note = "…"
        "#]],
    );
}

#[test]
fn attr_on_extern_block() {
    check(
        r#"#[$0] extern {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at link
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
    check(
        r#"extern {#![$0]}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at link
            at must_use
            at no_mangle
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_variant() {
    check(
        r#"enum Foo { #[$0] Bar }"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at expect(…)
            at forbid(…)
            at non_exhaustive
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_fn() {
    check(
        r#"#[$0] fn main() {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at ignore = "…"
            at inline
            at link_name = "…"
            at link_section = "…"
            at must_use
            at no_mangle
            at panic_handler
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at unsafe(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_in_source_file_end() {
    check(
        r#"#[$0]"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at derive(…)
            at diagnostic::do_not_recommend
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at ignore = "…"
            at inline
            at link
            at link_name = "…"
            at link_section = "…"
            at macro_export
            at macro_use
            at must_use
            at no_mangle
            at non_exhaustive
            at panic_handler
            at path = "…"
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at repr(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at unsafe(…)
            at used
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn invalid_path() {
    check(
        r#"
//- proc_macros: identity
#[proc_macros:::$0]
struct Foo;
"#,
        expect![[r#""#]],
    );

    check(
        r#"
//- minicore: derive, copy
mod foo {
    pub use Copy as Bar;
}
#[derive(foo:::::$0)]
struct Foo;
"#,
        expect![""],
    );
}

#[test]
fn issue_17479() {
    check(
        r#"
//- proc_macros: issue_17479
fn main() {
    proc_macros::issue_17479!("te$0");
}
"#,
        expect![""],
    );
    check(
        r#"
//- proc_macros: issue_17479
fn main() {
    proc_macros::issue_17479!("$0");
}
"#,
        expect![""],
    )
}

mod cfg {
    use super::*;

    #[test]
    fn inside_cfg() {
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg($0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg(b$0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
    }

    #[test]
    fn inside_cfg_attr() {
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr($0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr(b$0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr($0, allow(deprecated))]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr(b$0, allow(deprecated))]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
    }

    #[test]
    fn complete_key_attr() {
        check_edit(
            "test",
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg($0)]
"#,
            r#"
#[cfg(test)]
"#,
        );
    }

    #[test]
    fn complete_key_value_attr() {
        check_edit(
            "opt_level",
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg($0)]
"#,
            r#"
#[cfg(opt_level = $0)]
"#,
        );
    }

    #[test]
    fn cfg_target_endian() {
        check(
            r#"#[cfg(target_endian = $0"#,
            expect![[r#"
                ba big
                ba little
            "#]],
        );
        check(
            r#"#[cfg(target_endian = b$0"#,
            expect![[r#"
                ba big
                ba little
            "#]],
        );
    }

    #[test]
    fn inside_conditional() {
        check_edit(
            "all",
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg($0)]
"#,
            r#"
#[cfg(all($0))]
"#,
        );
    }
}

mod derive {
    use super::*;

    #[test]
    fn no_completion_for_incorrect_derive() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive{$0)] struct Test;
"#,
            expect![[]],
        )
    }

    #[test]
    fn empty_derive() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive($0)] struct Test;
"#,
            expect![[r#"
                de Clone              macro Clone
                de Clone, Copy
                de Debug              macro Debug
                de Default          macro Default
                de PartialEq      macro PartialEq
                de PartialEq, Eq
                de PartialEq, Eq, PartialOrd, Ord
                de PartialEq, PartialOrd
                md core::
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_with_input_before() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
"#,
            expect![[r#"
                de Clone     macro Clone
                de Clone, Copy
                de Debug     macro Debug
                de Default macro Default
                de Eq
                de Eq, PartialOrd, Ord
                de PartialOrd
                md core::
                kw crate::
                kw self::
            "#]],
        )
    }

    #[test]
    fn derive_with_input_after() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive($0 serde::Serialize, PartialEq)] struct Test;
"#,
            expect![[r#"
                de Clone     macro Clone
                de Clone, Copy
                de Debug     macro Debug
                de Default macro Default
                de Eq
                de Eq, PartialOrd, Ord
                de PartialOrd
                md core::
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_with_existing_derives() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive(PartialEq, Eq, Or$0)] struct Test;
"#,
            expect![[r#"
                de Clone     macro Clone
                de Clone, Copy
                de Debug     macro Debug
                de Default macro Default
                de PartialOrd
                de PartialOrd, Ord
                md core::
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_flyimport() {
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive
#[derive(der$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity (use proc_macros::DeriveIdentity) proc_macro DeriveIdentity
                md core::
                md proc_macros::
                kw crate::
                kw self::
            "#]],
        );
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive
use proc_macros::DeriveIdentity;
#[derive(der$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity proc_macro DeriveIdentity
                md core::
                md proc_macros::
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_flyimport_edit() {
        check_edit(
            "DeriveIdentity",
            r#"
//- proc_macros: derive_identity
//- minicore: derive
#[derive(der$0)] struct Test;
"#,
            r#"
use proc_macros::DeriveIdentity;

#[derive(DeriveIdentity)] struct Test;
"#,
        );
    }

    #[test]
    fn qualified() {
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive, copy, clone
#[derive(proc_macros::$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity proc_macro DeriveIdentity
            "#]],
        );
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive, copy, clone
#[derive(proc_macros::C$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity proc_macro DeriveIdentity
            "#]],
        );
    }
}

mod lint {
    use super::*;

    #[test]
    fn lint_empty() {
        check_edit(
            "deprecated",
            r#"#[allow($0)] struct Test;"#,
            r#"#[allow(deprecated)] struct Test;"#,
        )
    }

    #[test]
    fn lint_with_existing() {
        check_edit(
            "deprecated",
            r#"#[allow(keyword_idents, $0)] struct Test;"#,
            r#"#[allow(keyword_idents, deprecated)] struct Test;"#,
        )
    }

    #[test]
    fn lint_qualified() {
        check_edit(
            "deprecated",
            r#"#[allow(keyword_idents, $0)] struct Test;"#,
            r#"#[allow(keyword_idents, deprecated)] struct Test;"#,
        )
    }

    #[test]
    fn lint_feature() {
        check_edit(
            "box_patterns",
            r#"#[feature(box_$0)] struct Test;"#,
            r#"#[feature(box_patterns)] struct Test;"#,
        )
    }

    #[test]
    fn lint_clippy_unqualified() {
        check_edit(
            "clippy::as_conversions",
            r#"#[allow($0)] struct Test;"#,
            r#"#[allow(clippy::as_conversions)] struct Test;"#,
        );
    }

    #[test]
    fn lint_clippy_qualified() {
        check_edit(
            "as_conversions",
            r#"#[allow(clippy::$0)] struct Test;"#,
            r#"#[allow(clippy::as_conversions)] struct Test;"#,
        );
    }

    #[test]
    fn lint_rustdoc_unqualified() {
        check_edit(
            "rustdoc::bare_urls",
            r#"#[allow($0)] struct Test;"#,
            r#"#[allow(rustdoc::bare_urls)] struct Test;"#,
        );
    }

    #[test]
    fn lint_rustdoc_qualified() {
        check_edit(
            "bare_urls",
            r#"#[allow(rustdoc::$0)] struct Test;"#,
            r#"#[allow(rustdoc::bare_urls)] struct Test;"#,
        );
    }

    #[test]
    fn lint_unclosed() {
        check_edit(
            "deprecated",
            r#"#[allow(dep$0 struct Test;"#,
            r#"#[allow(deprecated struct Test;"#,
        );
        check_edit(
            "bare_urls",
            r#"#[allow(rustdoc::$0 struct Test;"#,
            r#"#[allow(rustdoc::bare_urls struct Test;"#,
        );
    }
}

mod repr {
    use super::*;

    #[test]
    fn no_completion_for_incorrect_repr() {
        check(r#"#[repr{$0)] struct Test;"#, expect![[]])
    }

    #[test]
    fn empty() {
        check(
            r#"#[repr($0)] struct Test;"#,
            expect![[r#"
                ba C
                ba align($0)
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba packed
                ba transparent
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn transparent() {
        check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]);
    }

    #[test]
    fn align() {
        check(
            r#"#[repr(align(1), $0)] struct Test;"#,
            expect![[r#"
                ba C
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba transparent
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn packed() {
        check(
            r#"#[repr(packed, $0)] struct Test;"#,
            expect![[r#"
                ba C
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba transparent
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn c() {
        check(
            r#"#[repr(C, $0)] struct Test;"#,
            expect![[r#"
                ba align($0)
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba packed
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn prim() {
        check(
            r#"#[repr(usize, $0)] struct Test;"#,
            expect![[r#"
                ba C
                ba align($0)
                ba packed
            "#]],
        );
    }
}

mod macro_use {
    use super::*;

    #[test]
    fn completes_macros() {
        check(
            r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
    () => {};
}

#[macro_export]
macro_rules! bar {
    () => {};
}

//- /main.rs crate:main deps:dep
#[macro_use($0)]
extern crate dep;
"#,
            expect![[r#"
                ma bar
                ma foo
            "#]],
        )
    }

    #[test]
    fn only_completes_exported_macros() {
        check(
            r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
    () => {};
}

macro_rules! bar {
    () => {};
}

//- /main.rs crate:main deps:dep
#[macro_use($0)]
extern crate dep;
"#,
            expect![[r#"
                ma foo
            "#]],
        )
    }

    #[test]
    fn does_not_completes_already_imported_macros() {
        check(
            r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
    () => {};
}

#[macro_export]
macro_rules! bar {
    () => {};
}

//- /main.rs crate:main deps:dep
#[macro_use(foo, $0)]
extern crate dep;
"#,
            expect![[r#"
                ma bar
            "#]],
        )
    }
}

#[test]
fn builtin_macro_completed_only_as_its_kind() {
    check(
        r#"
#[rustc_builtin_macro]
pub macro define_opaque($($tt:tt)*) {
    /* compiler built-in */
}

fn foo() {
    def$0
}
    "#,
        expect![[r#"
            fn foo()  fn()
            bt u32     u32
            kw async
            kw const
            kw crate::
            kw enum
            kw extern
            kw false
            kw fn
            kw for
            kw if
            kw if let
            kw impl
            kw impl for
            kw let
            kw letm
            kw loop
            kw match
            kw mod
            kw return
            kw self::
            kw static
            kw struct
            kw trait
            kw true
            kw type
            kw union
            kw unsafe
            kw use
            kw while
            kw while let
            sn macro_rules
            sn pd
            sn ppd
        "#]],
    );
}
