mod globs;
mod imports;
mod incremental;
mod macros;
mod mod_resolution;
use base_db::RootQueryDb;
use expect_test::{Expect, expect};
use test_fixture::WithFixture;
use crate::{
nameres::{DefMap, crate_def_map},
test_db::TestDB,
};
fn compute_crate_def_map(
#[rust_analyzer::rust_fixture] ra_fixture: &str,
cb: impl FnOnce(&DefMap),
) {
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
cb(crate_def_map(&db, krate));
}
fn render_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
crate_def_map(&db, krate).dump(&db)
}
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let actual = render_crate_def_map(ra_fixture);
expect.assert_eq(&actual);
}
#[test]
fn crate_def_map_smoke_test() {
check(
r#"
//- /lib.rs
mod foo;
struct S;
use crate::foo::bar::E;
use self::E::V;
//- /foo/mod.rs
pub mod bar;
fn f() {}
//- /foo/bar.rs
pub struct Baz;
union U { to_be: bool, not_to_be: u8 }
enum E { V }
extern {
type Ext;
static EXT: u8;
fn ext();
}
"#,
expect![[r#"
crate
- E : _
- S : type value
- V : _
- foo : type
crate::foo
- bar : type
- f : value
crate::foo::bar
- Baz : type value
- E : type
- EXT : value
- Ext : type
- U : type
- ext : value
"#]],
);
}
#[test]
fn crate_def_map_super_super() {
check(
r#"
mod a {
const A: usize = 0;
mod b {
const B: usize = 0;
mod c {
use super::super::*;
}
}
}
"#,
expect![[r#"
crate
- a : type
crate::a
- A : value
- b : type
crate::a::b
- B : value
- c : type
crate::a::b::c
- A : value (glob)
- b : type (glob)
"#]],
);
}
#[test]
fn crate_def_map_fn_mod_same_name() {
check(
r#"
mod m {
pub mod z {}
pub fn z() {}
}
"#,
expect![[r#"
crate
- m : type
crate::m
- z : type value
crate::m::z
"#]],
);
}
#[test]
fn bogus_paths() {
cov_mark::check!(bogus_paths);
check(
r#"
//- /lib.rs
mod foo;
struct S;
use self;
//- /foo/mod.rs
use super;
use crate;
"#,
expect![[r#"
crate
- S : type value
- foo : type
crate::foo
"#]],
);
}
#[test]
fn use_as() {
check(
r#"
//- /lib.rs
mod foo;
use crate::foo::Baz as Foo;
//- /foo/mod.rs
pub struct Baz;
"#,
expect![[r#"
crate
- Foo : type (import) value (import)
- foo : type
crate::foo
- Baz : type value
"#]],
);
}
#[test]
fn use_trees() {
check(
r#"
//- /lib.rs
mod foo;
use crate::foo::bar::{Baz, Quux};
//- /foo/mod.rs
pub mod bar;
//- /foo/bar.rs
pub struct Baz;
pub enum Quux {};
"#,
expect![[r#"
crate
- Baz : type (import) value (import)
- Quux : type (import)
- foo : type
crate::foo
- bar : type
crate::foo::bar
- Baz : type value
- Quux : type
"#]],
);
}
#[test]
fn re_exports() {
check(
r#"
//- /lib.rs
mod foo;
use self::foo::Baz;
//- /foo/mod.rs
pub mod bar;
pub use self::bar::Baz;
//- /foo/bar.rs
pub struct Baz;
"#,
expect![[r#"
crate
- Baz : type (import) value (import)
- foo : type
crate::foo
- Baz : type (import) value (import)
- bar : type
crate::foo::bar
- Baz : type value
"#]],
);
}
#[test]
fn std_prelude() {
cov_mark::check!(std_prelude);
check(
r#"
//- /main.rs crate:main deps:test_crate
#[prelude_import]
use ::test_crate::prelude::*;
use Foo::*;
//- /lib.rs crate:test_crate
pub mod prelude;
//- /prelude.rs
pub enum Foo { Bar, Baz }
"#,
expect![[r#"
crate
- Bar : type (glob) value (glob)
- Baz : type (glob) value (glob)
"#]],
);
}
#[test]
fn can_import_enum_variant() {
cov_mark::check!(can_import_enum_variant);
check(
r#"
enum E { V }
use self::E::V;
"#,
expect![[r#"
crate
- E : type
- V : type (import) value (import)
"#]],
);
}
#[test]
fn edition_2015_imports() {
check(
r#"
//- /main.rs crate:main deps:other_crate edition:2015
mod foo;
mod bar;
//- /bar.rs
struct Bar;
//- /foo.rs
use bar::Bar;
use other_crate::FromLib;
//- /lib.rs crate:other_crate edition:2018
pub struct FromLib;
"#,
expect![[r#"
crate
- bar : type
- foo : type
crate::bar
- Bar : type value
crate::foo
- Bar : _
- FromLib : type (import) value (import)
"#]],
);
}
#[test]
fn item_map_using_self() {
check(
r#"
//- /lib.rs
mod foo;
use crate::foo::bar::Baz::{self};
//- /foo/mod.rs
pub mod bar;
//- /foo/bar.rs
pub struct Baz;
"#,
expect![[r#"
crate
- Baz : type (import)
- foo : type
crate::foo
- bar : type
crate::foo::bar
- Baz : type value
"#]],
);
}
#[test]
fn item_map_across_crates() {
check(
r#"
//- /main.rs crate:main deps:test_crate
use test_crate::Baz;
//- /lib.rs crate:test_crate
pub struct Baz;
"#,
expect![[r#"
crate
- Baz : type (import) value (import)
"#]],
);
}
#[test]
fn extern_crate_rename() {
check(
r#"
//- /main.rs crate:main deps:alloc
extern crate alloc as alloc_crate;
mod alloc;
mod sync;
//- /sync.rs
use alloc_crate::Arc;
//- /lib.rs crate:alloc
pub struct Arc;
"#,
expect![[r#"
crate
- alloc : type
- alloc_crate : type (extern)
- sync : type
crate::alloc
crate::sync
- Arc : type (import) value (import)
"#]],
);
}
#[test]
fn extern_crate_reexport() {
check(
r#"
//- /main.rs crate:main deps:importer
use importer::*;
use importer::extern_crate1::exported::*;
use importer::allowed_reexport::*;
use importer::extern_crate2::*;
use importer::not_allowed_reexport1;
use importer::not_allowed_reexport2;
//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
extern crate extern_crate1;
extern crate extern_crate2;
pub use extern_crate1;
pub use extern_crate1 as allowed_reexport;
pub use ::extern_crate;
pub use self::extern_crate as not_allowed_reexport1;
pub use crate::extern_crate as not_allowed_reexport2;
//- /extern_crate1.rs crate:extern_crate1
pub mod exported {
pub struct PublicItem;
struct PrivateItem;
}
pub struct Exported;
//- /extern_crate2.rs crate:extern_crate2
pub struct NotExported;
"#,
expect![[r#"
crate
- Exported : type (glob) value (glob)
- PublicItem : type (glob) value (glob)
- allowed_reexport : type (glob)
- exported : type (glob)
- not_allowed_reexport1 : _
- not_allowed_reexport2 : _
"#]],
);
}
#[test]
fn extern_crate_rename_2015_edition() {
check(
r#"
//- /main.rs crate:main deps:alloc edition:2015
extern crate alloc as alloc_crate;
mod alloc;
mod sync;
//- /sync.rs
use alloc_crate::Arc;
//- /lib.rs crate:alloc
pub struct Arc;
"#,
expect![[r#"
crate
- alloc : type
- alloc_crate : type (extern)
- sync : type
crate::alloc
crate::sync
- Arc : type (import) value (import)
"#]],
);
}
#[test]
fn macro_use_extern_crate_self() {
check(
r#"
//- /main.rs crate:main
#[macro_use]
extern crate self as bla;
"#,
expect![[r#"
crate
- bla : type (extern)
"#]],
);
}
#[test]
fn reexport_across_crates() {
check(
r#"
//- /main.rs crate:main deps:test_crate
use test_crate::Baz;
//- /lib.rs crate:test_crate
pub use foo::Baz;
mod foo;
//- /foo.rs
pub struct Baz;
"#,
expect![[r#"
crate
- Baz : type (import) value (import)
"#]],
);
}
#[test]
fn values_dont_shadow_extern_crates() {
check(
r#"
//- /main.rs crate:main deps:foo
fn foo() {}
use foo::Bar;
//- /foo/lib.rs crate:foo
pub struct Bar;
"#,
expect![[r#"
crate
- Bar : type (import) value (import)
- foo : value
"#]],
);
}
#[test]
fn no_std_prelude() {
check(
r#"
//- /main.rs edition:2018 crate:main deps:core,std
#![cfg_attr(not(never), no_std)]
use Rust;
//- /core.rs crate:core
pub mod prelude {
pub mod rust_2018 {
pub struct Rust;
}
}
//- /std.rs crate:std deps:core
pub mod prelude {
pub mod rust_2018 {
}
}
"#,
expect![[r#"
crate
- Rust : type (import) value (import)
"#]],
);
}
#[test]
fn edition_specific_preludes() {
// We can't test the 2015 prelude here since you can't reexport its contents with 2015's
// absolute paths.
check(
r#"
//- /main.rs edition:2018 crate:main deps:std
use Rust2018;
//- /std.rs crate:std
pub mod prelude {
pub mod rust_2018 {
pub struct Rust2018;
}
}
"#,
expect![[r#"
crate
- Rust2018 : type (import) value (import)
"#]],
);
check(
r#"
//- /main.rs edition:2021 crate:main deps:std
use Rust2021;
//- /std.rs crate:std
pub mod prelude {
pub mod rust_2021 {
pub struct Rust2021;
}
}
"#,
expect![[r#"
crate
- Rust2021 : type (import) value (import)
"#]],
);
}
#[test]
fn std_prelude_takes_precedence_above_core_prelude() {
check(
r#"
//- /main.rs edition:2018 crate:main deps:core,std
use {Foo, Bar};
//- /std.rs crate:std deps:core
pub mod prelude {
pub mod rust_2018 {
pub struct Foo;
pub use core::prelude::rust_2018::Bar;
}
}
//- /core.rs crate:core
pub mod prelude {
pub mod rust_2018 {
pub struct Bar;
}
}
"#,
expect![[r#"
crate
- Bar : type (import) value (import)
- Foo : type (import) value (import)
"#]],
);
}
#[test]
fn cfg_not_test() {
check(
r#"
//- /main.rs edition:2018 crate:main deps:std
use {Foo, Bar, Baz};
//- /lib.rs crate:std
pub mod prelude {
pub mod rust_2018 {
#[cfg(test)]
pub struct Foo;
#[cfg(not(test))]
pub struct Bar;
#[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
pub struct Baz;
}
}
"#,
expect![[r#"
crate
- Bar : type (import) value (import)
- Baz : _
- Foo : _
"#]],
);
}
#[test]
fn cfg_test() {
check(
r#"
//- /main.rs edition:2018 crate:main deps:std
use {Foo, Bar, Baz};
//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42
pub mod prelude {
pub mod rust_2018 {
#[cfg(test)]
pub struct Foo;
#[cfg(not(test))]
pub struct Bar;
#[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
pub struct Baz;
}
}
"#,
expect![[r#"
crate
- Bar : _
- Baz : type (import) value (import)
- Foo : type (import) value (import)
"#]],
);
}
#[test]
fn infer_multiple_namespace() {
check(
r#"
//- /main.rs
mod a {
pub type T = ();
pub use crate::b::*;
}
use crate::a::T;
mod b {
pub const T: () = ();
}
"#,
expect![[r#"
crate
- T : type (import) value (import)
- a : type
- b : type
crate::a
- T : type value (glob)
crate::b
- T : value
"#]],
);
}
#[test]
fn underscore_import() {
check(
r#"
//- /main.rs
use tr::Tr as _;
use tr::Tr2 as _;
mod tr {
pub trait Tr {}
pub trait Tr2 {}
}
"#,
expect![[r#"
crate
- _ : type
- _ : type
- tr : type
crate::tr
- Tr : type
- Tr2 : type
"#]],
);
}
#[test]
fn underscore_reexport() {
check(
r#"
//- /main.rs
mod tr {
pub trait PubTr {}
pub trait PrivTr {}
}
mod reex {
use crate::tr::PrivTr as _;
pub use crate::tr::PubTr as _;
}
use crate::reex::*;
"#,
expect![[r#"
crate
- _ : type
- reex : type
- tr : type
crate::reex
- _ : type
- _ : type
crate::tr
- PrivTr : type
- PubTr : type
"#]],
);
}
#[test]
fn underscore_pub_crate_reexport() {
cov_mark::check!(upgrade_underscore_visibility);
check(
r#"
//- /main.rs crate:main deps:lib
use lib::*;
//- /lib.rs crate:lib
use tr::Tr as _;
pub use tr::Tr as _;
mod tr {
pub trait Tr {}
}
"#,
expect![[r#"
crate
- _ : type
"#]],
);
}
#[test]
fn underscore_nontrait() {
check(
r#"
//- /main.rs
mod m {
pub struct Struct;
pub enum Enum {}
pub const CONST: () = ();
}
use crate::m::{Struct as _, Enum as _, CONST as _};
"#,
expect![[r#"
crate
- m : type
crate::m
- CONST : value
- Enum : type
- Struct : type value
"#]],
);
}
#[test]
fn underscore_name_conflict() {
check(
r#"
//- /main.rs
struct Tr;
use tr::Tr as _;
mod tr {
pub trait Tr {}
}
"#,
expect![[r#"
crate
- _ : type
- Tr : type value
- tr : type
crate::tr
- Tr : type
"#]],
);
}
#[test]
fn cfg_the_entire_crate() {
check(
r#"
//- /main.rs
#![cfg(never)]
pub struct S;
pub enum E {}
pub fn f() {}
"#,
expect![[r#"
crate
"#]],
);
}
#[test]
fn use_crate_as() {
check(
r#"
use crate as foo;
use foo::bar as baz;
fn bar() {}
"#,
expect![[r#"
crate
- bar : value
- baz : value (import)
- foo : type (import)
"#]],
);
}
#[test]
fn self_imports_only_types() {
check(
r#"
//- /main.rs
mod m {
pub macro S() {}
pub struct S;
}
use self::m::S::{self};
"#,
expect![[r#"
crate
- S : type (import)
- m : type
crate::m
- S : type value macro!
"#]],
);
}
#[test]
fn import_from_extern_crate_only_imports_public_items() {
check(
r#"
//- /lib.rs crate:lib deps:settings,macros
use macros::settings;
use settings::Settings;
//- /settings.rs crate:settings
pub struct Settings;
//- /macros.rs crate:macros
mod settings {}
pub const settings: () = ();
"#,
expect![[r#"
crate
- Settings : type (import) value (import)
- settings : value (import)
"#]],
)
}
#[test]
fn non_prelude_deps() {
check(
r#"
//- /lib.rs crate:lib deps:dep extern-prelude:
use dep::Struct;
//- /dep.rs crate:dep
pub struct Struct;
"#,
expect![[r#"
crate
- Struct : _
"#]],
);
check(
r#"
//- /lib.rs crate:lib deps:dep extern-prelude:
extern crate dep;
use dep::Struct;
//- /dep.rs crate:dep
pub struct Struct;
"#,
expect![[r#"
crate
- Struct : type (import) value (import)
- dep : type (extern)
"#]],
);
}
#[test]
fn braced_supers_in_use_tree() {
cov_mark::check!(concat_super_mod_paths);
check(
r#"
mod some_module {
pub fn unknown_func() {}
}
mod other_module {
mod some_submodule {
use { super::{ super::unknown_func, }, };
}
}
use some_module::unknown_func;
"#,
expect![[r#"
crate
- other_module : type
- some_module : type
- unknown_func : value (import)
crate::other_module
- some_submodule : type
crate::other_module::some_submodule
- unknown_func : value (import)
crate::some_module
- unknown_func : value
"#]],
)
}