Merge #1499
1499: processing attribute #[path] of module r=matklad a=andreevlex support two cases - simple name file `foo.rs` - declaration in mod.rs #1211 Co-authored-by: Alexander Andreev <andreevlex.as@gmail.com>
This commit is contained in:
commit
6c31f5b0a7
@ -1,6 +1,6 @@
|
||||
/// This module implements import-resolution/macro expansion algorithm.
|
||||
///
|
||||
/// The result of this module is `CrateDefMap`: a datastructure which contains:
|
||||
/// The result of this module is `CrateDefMap`: a data structure which contains:
|
||||
///
|
||||
/// * a tree of modules for the crate
|
||||
/// * for each module, a set of items visible in the module (directly declared
|
||||
@ -76,7 +76,7 @@ pub use self::{
|
||||
raw::ImportId,
|
||||
};
|
||||
|
||||
/// Contans all top-level defs from a macro-expanded crate
|
||||
/// Contains all top-level defs from a macro-expanded crate
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct CrateDefMap {
|
||||
krate: Crate,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use arrayvec::ArrayVec;
|
||||
use ra_db::FileId;
|
||||
use ra_syntax::ast;
|
||||
use ra_syntax::{ast, SmolStr};
|
||||
use relative_path::RelativePathBuf;
|
||||
use rustc_hash::FxHashMap;
|
||||
use test_utils::tested_by;
|
||||
@ -508,11 +508,17 @@ where
|
||||
}
|
||||
.collect(&*items);
|
||||
}
|
||||
// out of line module, resovle, parse and recurse
|
||||
raw::ModuleData::Declaration { name, ast_id } => {
|
||||
// out of line module, resolve, parse and recurse
|
||||
raw::ModuleData::Declaration { name, ast_id, attr_path } => {
|
||||
let ast_id = ast_id.with_file_id(self.file_id);
|
||||
let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
|
||||
match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) {
|
||||
match resolve_submodule(
|
||||
self.def_collector.db,
|
||||
self.file_id,
|
||||
name,
|
||||
is_root,
|
||||
attr_path.as_ref(),
|
||||
) {
|
||||
Ok(file_id) => {
|
||||
let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
|
||||
let raw_items = self.def_collector.db.raw_items(file_id.into());
|
||||
@ -626,6 +632,7 @@ fn resolve_submodule(
|
||||
file_id: HirFileId,
|
||||
name: &Name,
|
||||
is_root: bool,
|
||||
attr_path: Option<&SmolStr>,
|
||||
) -> Result<FileId, RelativePathBuf> {
|
||||
// FIXME: handle submodules of inline modules properly
|
||||
let file_id = file_id.original_file(db);
|
||||
@ -639,7 +646,13 @@ fn resolve_submodule(
|
||||
let file_mod = dir_path.join(format!("{}.rs", name));
|
||||
let dir_mod = dir_path.join(format!("{}/mod.rs", name));
|
||||
let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
|
||||
let mut candidates = ArrayVec::<[_; 2]>::new();
|
||||
let mut candidates = ArrayVec::<[_; 3]>::new();
|
||||
let file_attr_mod = attr_path.map(|file_path| {
|
||||
let file_attr_mod = dir_path.join(file_path.to_string());
|
||||
candidates.push(file_attr_mod.clone());
|
||||
|
||||
file_attr_mod
|
||||
});
|
||||
if is_dir_owner {
|
||||
candidates.push(file_mod.clone());
|
||||
candidates.push(dir_mod);
|
||||
@ -651,7 +664,13 @@ fn resolve_submodule(
|
||||
// FIXME: handle ambiguity
|
||||
match points_to.next() {
|
||||
Some(file_id) => Ok(file_id),
|
||||
None => Err(if is_dir_owner { file_mod } else { file_dir_mod }),
|
||||
None => {
|
||||
if let Some(file_attr_mod) = file_attr_mod {
|
||||
Err(file_attr_mod)
|
||||
} else {
|
||||
Err(if is_dir_owner { file_mod } else { file_dir_mod })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::{ops::Index, sync::Arc};
|
||||
use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
|
||||
use ra_syntax::{
|
||||
ast::{self, AttrsOwner, NameOwner},
|
||||
AstNode, AstPtr, SourceFile, TreeArc,
|
||||
AstNode, AstPtr, SmolStr, SourceFile, TreeArc,
|
||||
};
|
||||
use test_utils::tested_by;
|
||||
|
||||
@ -130,7 +130,7 @@ impl_arena_id!(Module);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(super) enum ModuleData {
|
||||
Declaration { name: Name, ast_id: FileAstId<ast::Module> },
|
||||
Declaration { name: Name, ast_id: FileAstId<ast::Module>, attr_path: Option<SmolStr> },
|
||||
Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
|
||||
}
|
||||
|
||||
@ -255,9 +255,12 @@ impl RawItemsCollector {
|
||||
Some(it) => it.as_name(),
|
||||
None => return,
|
||||
};
|
||||
|
||||
let attr_path = extract_mod_path_attribute(module);
|
||||
let ast_id = self.source_ast_id_map.ast_id(module);
|
||||
if module.has_semi() {
|
||||
let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
|
||||
let item =
|
||||
self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path });
|
||||
self.push_item(current_module, RawItem::Module(item));
|
||||
return;
|
||||
}
|
||||
@ -339,3 +342,16 @@ impl RawItemsCollector {
|
||||
.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> {
|
||||
module.attrs().into_iter().find_map(|attr| {
|
||||
attr.as_key_value().and_then(|(name, value)| {
|
||||
let is_path = name == "path";
|
||||
if is_path {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ mod macros;
|
||||
mod globs;
|
||||
mod incremental;
|
||||
mod primitives;
|
||||
mod mods;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -312,83 +313,6 @@ fn edition_2015_imports() {
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_works_for_non_standard_filenames() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /my_library.rs
|
||||
mod foo;
|
||||
use self::foo::Bar;
|
||||
|
||||
//- /foo/mod.rs
|
||||
pub struct Bar;
|
||||
",
|
||||
crate_graph! {
|
||||
"my_library": ("/my_library.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮foo: t
|
||||
⋮
|
||||
⋮crate::foo
|
||||
⋮Bar: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_works_for_raw_modules() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /library.rs
|
||||
mod r#async;
|
||||
use self::r#async::Bar;
|
||||
|
||||
//- /async.rs
|
||||
pub struct Bar;
|
||||
",
|
||||
crate_graph! {
|
||||
"library": ("/library.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮async: t
|
||||
⋮
|
||||
⋮crate::async
|
||||
⋮Bar: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn name_res_works_for_broken_modules() {
|
||||
covers!(name_res_works_for_broken_modules);
|
||||
let map = def_map(
|
||||
"
|
||||
//- /lib.rs
|
||||
mod foo // no `;`, no body
|
||||
|
||||
use self::foo::Baz;
|
||||
|
||||
//- /foo/mod.rs
|
||||
pub mod bar;
|
||||
|
||||
pub use self::bar::Baz;
|
||||
|
||||
//- /foo/bar.rs
|
||||
pub struct Baz;
|
||||
",
|
||||
);
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Baz: _
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn item_map_using_self() {
|
||||
let map = def_map(
|
||||
@ -581,22 +505,3 @@ fn values_dont_shadow_extern_crates() {
|
||||
⋮foo: v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unresolved_module_diagnostics() {
|
||||
let diagnostics = MockDatabase::with_files(
|
||||
r"
|
||||
//- /lib.rs
|
||||
mod foo;
|
||||
mod bar;
|
||||
mod baz {}
|
||||
//- /foo.rs
|
||||
",
|
||||
)
|
||||
.diagnostics();
|
||||
|
||||
assert_snapshot_matches!(diagnostics, @r###"
|
||||
"mod bar;": unresolved module
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
192
crates/ra_hir/src/nameres/tests/mods.rs
Normal file
192
crates/ra_hir/src/nameres/tests/mods.rs
Normal file
@ -0,0 +1,192 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn name_res_works_for_broken_modules() {
|
||||
covers!(name_res_works_for_broken_modules);
|
||||
let map = def_map(
|
||||
"
|
||||
//- /lib.rs
|
||||
mod foo // no `;`, no body
|
||||
|
||||
use self::foo::Baz;
|
||||
|
||||
//- /foo/mod.rs
|
||||
pub mod bar;
|
||||
|
||||
pub use self::bar::Baz;
|
||||
|
||||
//- /foo/bar.rs
|
||||
pub struct Baz;
|
||||
",
|
||||
);
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Baz: _
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_works_for_non_standard_filenames() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /my_library.rs
|
||||
mod foo;
|
||||
use self::foo::Bar;
|
||||
|
||||
//- /foo/mod.rs
|
||||
pub struct Bar;
|
||||
",
|
||||
crate_graph! {
|
||||
"my_library": ("/my_library.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮foo: t
|
||||
⋮
|
||||
⋮crate::foo
|
||||
⋮Bar: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_works_for_raw_modules() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /library.rs
|
||||
mod r#async;
|
||||
use self::r#async::Bar;
|
||||
|
||||
//- /async.rs
|
||||
pub struct Bar;
|
||||
",
|
||||
crate_graph! {
|
||||
"library": ("/library.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮async: t
|
||||
⋮
|
||||
⋮crate::async
|
||||
⋮Bar: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_decl_path() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /library.rs
|
||||
#[path = \"bar/baz/foo.rs\"]
|
||||
mod foo;
|
||||
use self::foo::Bar;
|
||||
|
||||
//- /bar/baz/foo.rs
|
||||
pub struct Bar;
|
||||
",
|
||||
crate_graph! {
|
||||
"library": ("/library.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮foo: t
|
||||
⋮
|
||||
⋮crate::foo
|
||||
⋮Bar: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_module_with_path_in_mod_rs() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /main.rs
|
||||
mod foo;
|
||||
|
||||
//- /foo/mod.rs
|
||||
#[path = \"baz.rs\"]
|
||||
pub mod bar;
|
||||
|
||||
use self::bar::Baz;
|
||||
|
||||
//- /foo/baz.rs
|
||||
pub struct Baz;
|
||||
",
|
||||
crate_graph! {
|
||||
"main": ("/main.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮foo: t
|
||||
⋮
|
||||
⋮crate::foo
|
||||
⋮Baz: t v
|
||||
⋮bar: t
|
||||
⋮
|
||||
⋮crate::foo::bar
|
||||
⋮Baz: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_resolution_module_with_path_non_crate_root() {
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /main.rs
|
||||
mod foo;
|
||||
|
||||
//- /foo.rs
|
||||
#[path = \"baz.rs\"]
|
||||
pub mod bar;
|
||||
|
||||
use self::bar::Baz;
|
||||
|
||||
//- /baz.rs
|
||||
pub struct Baz;
|
||||
",
|
||||
crate_graph! {
|
||||
"main": ("/main.rs", []),
|
||||
},
|
||||
);
|
||||
|
||||
assert_snapshot_matches!(map, @r###"
|
||||
⋮crate
|
||||
⋮foo: t
|
||||
⋮
|
||||
⋮crate::foo
|
||||
⋮Baz: t v
|
||||
⋮bar: t
|
||||
⋮
|
||||
⋮crate::foo::bar
|
||||
⋮Baz: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unresolved_module_diagnostics() {
|
||||
let diagnostics = MockDatabase::with_files(
|
||||
r"
|
||||
//- /lib.rs
|
||||
mod foo;
|
||||
mod bar;
|
||||
mod baz {}
|
||||
//- /foo.rs
|
||||
",
|
||||
)
|
||||
.diagnostics();
|
||||
|
||||
assert_snapshot_matches!(diagnostics, @r###"
|
||||
"mod bar;": unresolved module
|
||||
"###
|
||||
);
|
||||
}
|
@ -116,7 +116,7 @@ impl CrateImplBlocks {
|
||||
|
||||
fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> {
|
||||
// Types like slice can have inherent impls in several crates, (core and alloc).
|
||||
// The correspoinding impls are marked with lang items, so we can use them to find the required crates.
|
||||
// The corresponding impls are marked with lang items, so we can use them to find the required crates.
|
||||
macro_rules! lang_item_crate {
|
||||
($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{
|
||||
let mut v = ArrayVec::<[Crate; 2]>::new();
|
||||
|
@ -52,7 +52,7 @@ pub fn set_filter(f: Filter) {
|
||||
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
|
||||
/// Profiling information is being printed in the stderr.
|
||||
///
|
||||
/// #Example
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use ra_prof::{profile, set_filter, Filter};
|
||||
///
|
||||
|
Loading…
x
Reference in New Issue
Block a user