mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #119988 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? ghost
This commit is contained in:
commit
bfcc027a75
@ -513,7 +513,8 @@ dependencies = [
|
|||||||
"mbe",
|
"mbe",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"profile",
|
"profile",
|
||||||
"rustc-dependencies",
|
"ra-ap-rustc_abi",
|
||||||
|
"ra-ap-rustc_parse_format",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"span",
|
"span",
|
||||||
@ -579,7 +580,8 @@ dependencies = [
|
|||||||
"oorandom",
|
"oorandom",
|
||||||
"profile",
|
"profile",
|
||||||
"project-model",
|
"project-model",
|
||||||
"rustc-dependencies",
|
"ra-ap-rustc_abi",
|
||||||
|
"ra-ap-rustc_index",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@ -1196,7 +1198,7 @@ dependencies = [
|
|||||||
"drop_bomb",
|
"drop_bomb",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"limit",
|
"limit",
|
||||||
"rustc-dependencies",
|
"ra-ap-rustc_lexer",
|
||||||
"sourcegen",
|
"sourcegen",
|
||||||
"stdx",
|
"stdx",
|
||||||
]
|
]
|
||||||
@ -1540,7 +1542,6 @@ dependencies = [
|
|||||||
"profile",
|
"profile",
|
||||||
"project-model",
|
"project-model",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rustc-dependencies",
|
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"scip",
|
"scip",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1567,9 +1568,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-analyzer-salsa"
|
name = "rust-analyzer-salsa"
|
||||||
version = "0.17.0-pre.4"
|
version = "0.17.0-pre.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16c42b8737c320578b441a82daf7cdf8d897468de64e8a774fa54b53a50b6cc0"
|
checksum = "ca9d387a9801f4fb9b366789ad1bfc08448cafc49cf148d907cfcd88ab665d7f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
@ -1579,13 +1580,14 @@ dependencies = [
|
|||||||
"rust-analyzer-salsa-macros",
|
"rust-analyzer-salsa-macros",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
"triomphe",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-analyzer-salsa-macros"
|
name = "rust-analyzer-salsa-macros"
|
||||||
version = "0.17.0-pre.4"
|
version = "0.17.0-pre.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db72b0883f3592ade2be15a10583c75e0b269ec26e1190800fda2e2ce5ae6634"
|
checksum = "a2035f385d7fae31e9b086f40b272ee1d79c484472f31c9a10348a406e841eaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -1599,16 +1601,6 @@ version = "0.1.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-dependencies"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"ra-ap-rustc_abi",
|
|
||||||
"ra-ap-rustc_index",
|
|
||||||
"ra-ap-rustc_lexer",
|
|
||||||
"ra-ap-rustc_parse_format",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1751,6 +1743,12 @@ dependencies = [
|
|||||||
"vfs",
|
"vfs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1808,9 +1806,9 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"profile",
|
"profile",
|
||||||
"quote",
|
"quote",
|
||||||
|
"ra-ap-rustc_lexer",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rowan",
|
"rowan",
|
||||||
"rustc-dependencies",
|
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smol_str",
|
"smol_str",
|
||||||
"sourcegen",
|
"sourcegen",
|
||||||
@ -2028,9 +2026,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "triomphe"
|
name = "triomphe"
|
||||||
version = "0.1.10"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0c5a71827ac326072b6405552093e2ad2accd25a32fd78d4edc82d98c7f2409"
|
checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tt"
|
name = "tt"
|
||||||
|
@ -78,7 +78,11 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" }
|
|||||||
tt = { path = "./crates/tt", version = "0.0.0" }
|
tt = { path = "./crates/tt", version = "0.0.0" }
|
||||||
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
||||||
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||||
rustc-dependencies = { path = "./crates/rustc-dependencies", version = "0.0.0" }
|
|
||||||
|
ra-ap-rustc_lexer = { version = "0.21.0", default-features = false }
|
||||||
|
ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false }
|
||||||
|
ra-ap-rustc_index = { version = "0.21.0", default-features = false }
|
||||||
|
ra-ap-rustc_abi = { version = "0.21.0", default-features = false }
|
||||||
|
|
||||||
# local crates that aren't published to crates.io. These should not have versions.
|
# local crates that aren't published to crates.io. These should not have versions.
|
||||||
sourcegen = { path = "./crates/sourcegen" }
|
sourcegen = { path = "./crates/sourcegen" }
|
||||||
@ -108,7 +112,7 @@ itertools = "0.12.0"
|
|||||||
libc = "0.2.150"
|
libc = "0.2.150"
|
||||||
nohash-hasher = "0.2.0"
|
nohash-hasher = "0.2.0"
|
||||||
rayon = "1.8.0"
|
rayon = "1.8.0"
|
||||||
rust-analyzer-salsa = "0.17.0-pre.4"
|
rust-analyzer-salsa = "0.17.0-pre.5"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
semver = "1.0.14"
|
semver = "1.0.14"
|
||||||
serde = { version = "1.0.192", features = ["derive"] }
|
serde = { version = "1.0.192", features = ["derive"] }
|
||||||
|
@ -7,7 +7,6 @@ mod change;
|
|||||||
|
|
||||||
use std::panic;
|
use std::panic;
|
||||||
|
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use syntax::{ast, Parse, SourceFile};
|
use syntax::{ast, Parse, SourceFile};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
@ -44,12 +43,13 @@ pub trait Upcast<T: ?Sized> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
|
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
|
||||||
|
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 256;
|
||||||
|
|
||||||
pub trait FileLoader {
|
pub trait FileLoader {
|
||||||
/// Text of the file.
|
/// Text of the file.
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<str>;
|
fn file_text(&self, file_id: FileId) -> Arc<str>;
|
||||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
|
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
|
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Database which stores all significant input facts: source code and project
|
/// Database which stores all significant input facts: source code and project
|
||||||
@ -84,19 +84,21 @@ pub trait SourceDatabaseExt: SourceDatabase {
|
|||||||
#[salsa::input]
|
#[salsa::input]
|
||||||
fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
|
fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
|
||||||
|
|
||||||
fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
|
fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
|
fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<[CrateId]> {
|
||||||
let graph = db.crate_graph();
|
let graph = db.crate_graph();
|
||||||
let res = graph
|
let mut crates = graph
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&krate| {
|
.filter(|&krate| {
|
||||||
let root_file = graph[krate].root_file_id;
|
let root_file = graph[krate].root_file_id;
|
||||||
db.file_source_root(root_file) == id
|
db.file_source_root(root_file) == id
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
Arc::new(res)
|
crates.sort();
|
||||||
|
crates.dedup();
|
||||||
|
crates.into_iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Silly workaround for cyclic deps between the traits
|
/// Silly workaround for cyclic deps between the traits
|
||||||
@ -113,7 +115,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
|
|||||||
source_root.resolve_path(path)
|
source_root.resolve_path(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
|
||||||
let _p = profile::span("relevant_crates");
|
let _p = profile::span("relevant_crates");
|
||||||
let source_root = self.0.file_source_root(file_id);
|
let source_root = self.0.file_source_root(file_id);
|
||||||
self.0.source_root_crates(source_root)
|
self.0.source_root_crates(source_root)
|
||||||
|
@ -29,7 +29,8 @@ smallvec.workspace = true
|
|||||||
hashbrown.workspace = true
|
hashbrown.workspace = true
|
||||||
triomphe.workspace = true
|
triomphe.workspace = true
|
||||||
|
|
||||||
rustc-dependencies.workspace = true
|
ra-ap-rustc_parse_format.workspace = true
|
||||||
|
ra-ap-rustc_abi.workspace = true
|
||||||
|
|
||||||
# local deps
|
# local deps
|
||||||
stdx.workspace = true
|
stdx.workspace = true
|
||||||
@ -53,7 +54,7 @@ test-utils.workspace = true
|
|||||||
test-fixture.workspace = true
|
test-fixture.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
in-rust-tree = []
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -207,6 +207,13 @@ impl Attrs {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_doc_notable_trait(&self) -> bool {
|
||||||
|
self.by_key("doc").tt_values().any(|tt| {
|
||||||
|
tt.delimiter.kind == DelimiterKind::Parenthesis &&
|
||||||
|
matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "notable_trait")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn doc_exprs(&self) -> impl Iterator<Item = DocExpr> + '_ {
|
pub fn doc_exprs(&self) -> impl Iterator<Item = DocExpr> + '_ {
|
||||||
self.by_key("doc").tt_values().map(DocExpr::parse)
|
self.by_key("doc").tt_values().map(DocExpr::parse)
|
||||||
}
|
}
|
||||||
@ -355,7 +362,7 @@ fn parse_comma_sep<S>(subtree: &tt::Subtree<S>) -> Vec<SmolStr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AttrsWithOwner {
|
impl AttrsWithOwner {
|
||||||
pub(crate) fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self {
|
pub fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self {
|
||||||
Self { attrs: db.attrs(owner), owner }
|
Self { attrs: db.attrs(owner), owner }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,11 +965,10 @@ impl ExprCollector<'_> {
|
|||||||
|
|
||||||
let res = match self.def_map.modules[module]
|
let res = match self.def_map.modules[module]
|
||||||
.scope
|
.scope
|
||||||
.macro_invocations
|
.macro_invoc(InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr)))
|
||||||
.get(&InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr)))
|
|
||||||
{
|
{
|
||||||
// fast path, macro call is in a block module
|
// fast path, macro call is in a block module
|
||||||
Some(&call) => Ok(self.expander.enter_expand_id(self.db, call)),
|
Some(call) => Ok(self.expander.enter_expand_id(self.db, call)),
|
||||||
None => self.expander.enter_expand(self.db, mcall, |path| {
|
None => self.expander.enter_expand(self.db, mcall, |path| {
|
||||||
self.def_map
|
self.def_map
|
||||||
.resolve_path(
|
.resolve_path(
|
||||||
|
@ -92,7 +92,7 @@ impl ChildBySource for ItemScope {
|
|||||||
self.impls().for_each(|imp| add_impl(db, res, file_id, imp));
|
self.impls().for_each(|imp| add_impl(db, res, file_id, imp));
|
||||||
self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext));
|
self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext));
|
||||||
self.use_decls().for_each(|ext| add_use(db, res, file_id, ext));
|
self.use_decls().for_each(|ext| add_use(db, res, file_id, ext));
|
||||||
self.unnamed_consts().for_each(|konst| {
|
self.unnamed_consts(db).for_each(|konst| {
|
||||||
let loc = konst.lookup(db);
|
let loc = konst.lookup(db);
|
||||||
if loc.id.file_id() == file_id {
|
if loc.id.file_id() == file_id {
|
||||||
res[keys::CONST].insert(loc.source(db).value, konst);
|
res[keys::CONST].insert(loc.source(db).value, konst);
|
||||||
|
@ -11,7 +11,7 @@ use hir_expand::{
|
|||||||
};
|
};
|
||||||
use intern::Interned;
|
use intern::Interned;
|
||||||
use la_arena::{Arena, ArenaMap};
|
use la_arena::{Arena, ArenaMap};
|
||||||
use rustc_dependencies::abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
||||||
use syntax::ast::{self, HasName, HasVisibility};
|
use syntax::ast::{self, HasName, HasVisibility};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -210,13 +210,10 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
|||||||
#[salsa::invoke(AttrsWithOwner::attrs_query)]
|
#[salsa::invoke(AttrsWithOwner::attrs_query)]
|
||||||
fn attrs(&self, def: AttrDefId) -> Attrs;
|
fn attrs(&self, def: AttrDefId) -> Attrs;
|
||||||
|
|
||||||
|
#[salsa::transparent]
|
||||||
#[salsa::invoke(lang_item::lang_attr_query)]
|
#[salsa::invoke(lang_item::lang_attr_query)]
|
||||||
fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
|
fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
|
||||||
|
|
||||||
#[salsa::transparent]
|
|
||||||
#[salsa::invoke(AttrsWithOwner::attrs_with_owner)]
|
|
||||||
fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner;
|
|
||||||
|
|
||||||
// endregion:attrs
|
// endregion:attrs
|
||||||
|
|
||||||
#[salsa::invoke(LangItems::lang_item_query)]
|
#[salsa::invoke(LangItems::lang_item_query)]
|
||||||
@ -240,7 +237,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
|||||||
// endregion:visibilities
|
// endregion:visibilities
|
||||||
|
|
||||||
#[salsa::invoke(LangItems::crate_lang_items_query)]
|
#[salsa::invoke(LangItems::crate_lang_items_query)]
|
||||||
fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
|
fn crate_lang_items(&self, krate: CrateId) -> Option<Arc<LangItems>>;
|
||||||
|
|
||||||
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
|
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
item_scope::ItemInNs,
|
item_scope::ItemInNs,
|
||||||
nameres::DefMap,
|
nameres::DefMap,
|
||||||
path::{ModPath, PathKind},
|
path::{ModPath, PathKind},
|
||||||
visibility::Visibility,
|
visibility::{Visibility, VisibilityExplicity},
|
||||||
CrateRootModuleId, ModuleDefId, ModuleId,
|
CrateRootModuleId, ModuleDefId, ModuleId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ pub fn find_path(
|
|||||||
prefer_prelude: bool,
|
prefer_prelude: bool,
|
||||||
) -> Option<ModPath> {
|
) -> Option<ModPath> {
|
||||||
let _p = profile::span("find_path");
|
let _p = profile::span("find_path");
|
||||||
find_path_inner(db, item, from, None, prefer_no_std, prefer_prelude)
|
find_path_inner(FindPathCtx { db, prefixed: None, prefer_no_std, prefer_prelude }, item, from)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_path_prefixed(
|
pub fn find_path_prefixed(
|
||||||
@ -36,7 +36,11 @@ pub fn find_path_prefixed(
|
|||||||
prefer_prelude: bool,
|
prefer_prelude: bool,
|
||||||
) -> Option<ModPath> {
|
) -> Option<ModPath> {
|
||||||
let _p = profile::span("find_path_prefixed");
|
let _p = profile::span("find_path_prefixed");
|
||||||
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std, prefer_prelude)
|
find_path_inner(
|
||||||
|
FindPathCtx { db, prefixed: Some(prefix_kind), prefer_no_std, prefer_prelude },
|
||||||
|
item,
|
||||||
|
from,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@ -83,64 +87,60 @@ impl PrefixKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
|
#[derive(Copy, Clone)]
|
||||||
fn find_path_inner(
|
struct FindPathCtx<'db> {
|
||||||
db: &dyn DefDatabase,
|
db: &'db dyn DefDatabase,
|
||||||
item: ItemInNs,
|
|
||||||
from: ModuleId,
|
|
||||||
prefixed: Option<PrefixKind>,
|
prefixed: Option<PrefixKind>,
|
||||||
prefer_no_std: bool,
|
prefer_no_std: bool,
|
||||||
prefer_prelude: bool,
|
prefer_prelude: bool,
|
||||||
) -> Option<ModPath> {
|
}
|
||||||
|
|
||||||
|
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
|
||||||
|
fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
|
||||||
// - if the item is a builtin, it's in scope
|
// - if the item is a builtin, it's in scope
|
||||||
if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
|
if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
|
||||||
return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
|
return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_map = from.def_map(db);
|
let def_map = from.def_map(ctx.db);
|
||||||
let crate_root = def_map.crate_root();
|
let crate_root = def_map.crate_root();
|
||||||
// - if the item is a module, jump straight to module search
|
// - if the item is a module, jump straight to module search
|
||||||
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
|
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
|
||||||
let mut visited_modules = FxHashSet::default();
|
let mut visited_modules = FxHashSet::default();
|
||||||
return find_path_for_module(
|
return find_path_for_module(
|
||||||
db,
|
FindPathCtx {
|
||||||
|
prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate),
|
||||||
|
..ctx
|
||||||
|
},
|
||||||
&def_map,
|
&def_map,
|
||||||
&mut visited_modules,
|
&mut visited_modules,
|
||||||
crate_root,
|
crate_root,
|
||||||
from,
|
from,
|
||||||
module_id,
|
module_id,
|
||||||
MAX_PATH_LEN,
|
MAX_PATH_LEN,
|
||||||
prefixed,
|
|
||||||
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
|
||||||
prefer_prelude,
|
|
||||||
)
|
)
|
||||||
.map(|(item, _)| item);
|
.map(|(item, _)| item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is already in scope, return the name under which it is
|
// - if the item is already in scope, return the name under which it is
|
||||||
let scope_name = find_in_scope(db, &def_map, from, item);
|
let scope_name = find_in_scope(ctx.db, &def_map, from, item);
|
||||||
if prefixed.is_none() {
|
if ctx.prefixed.is_none() {
|
||||||
if let Some(scope_name) = scope_name {
|
if let Some(scope_name) = scope_name {
|
||||||
return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
|
return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is in the prelude, return the name from there
|
// - if the item is in the prelude, return the name from there
|
||||||
if let value @ Some(_) = find_in_prelude(db, &crate_root.def_map(db), &def_map, item, from) {
|
if let value @ Some(_) =
|
||||||
|
find_in_prelude(ctx.db, &crate_root.def_map(ctx.db), &def_map, item, from)
|
||||||
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
|
if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
|
||||||
// - if the item is an enum variant, refer to it via the enum
|
// - if the item is an enum variant, refer to it via the enum
|
||||||
if let Some(mut path) = find_path_inner(
|
if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(variant.parent.into()), from) {
|
||||||
db,
|
let data = ctx.db.enum_data(variant.parent);
|
||||||
ItemInNs::Types(variant.parent.into()),
|
|
||||||
from,
|
|
||||||
prefixed,
|
|
||||||
prefer_no_std,
|
|
||||||
prefer_prelude,
|
|
||||||
) {
|
|
||||||
let data = db.enum_data(variant.parent);
|
|
||||||
path.push_segment(data.variants[variant.local_id].name.clone());
|
path.push_segment(data.variants[variant.local_id].name.clone());
|
||||||
return Some(path);
|
return Some(path);
|
||||||
}
|
}
|
||||||
@ -152,32 +152,29 @@ fn find_path_inner(
|
|||||||
let mut visited_modules = FxHashSet::default();
|
let mut visited_modules = FxHashSet::default();
|
||||||
|
|
||||||
calculate_best_path(
|
calculate_best_path(
|
||||||
db,
|
FindPathCtx {
|
||||||
|
prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate),
|
||||||
|
..ctx
|
||||||
|
},
|
||||||
&def_map,
|
&def_map,
|
||||||
&mut visited_modules,
|
&mut visited_modules,
|
||||||
crate_root,
|
crate_root,
|
||||||
MAX_PATH_LEN,
|
MAX_PATH_LEN,
|
||||||
item,
|
item,
|
||||||
from,
|
from,
|
||||||
prefixed,
|
|
||||||
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
|
||||||
prefer_prelude,
|
|
||||||
scope_name,
|
scope_name,
|
||||||
)
|
)
|
||||||
.map(|(item, _)| item)
|
.map(|(item, _)| item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_path_for_module(
|
fn find_path_for_module(
|
||||||
db: &dyn DefDatabase,
|
ctx: FindPathCtx<'_>,
|
||||||
def_map: &DefMap,
|
def_map: &DefMap,
|
||||||
visited_modules: &mut FxHashSet<ModuleId>,
|
visited_modules: &mut FxHashSet<ModuleId>,
|
||||||
crate_root: CrateRootModuleId,
|
crate_root: CrateRootModuleId,
|
||||||
from: ModuleId,
|
from: ModuleId,
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
prefixed: Option<PrefixKind>,
|
|
||||||
prefer_no_std: bool,
|
|
||||||
prefer_prelude: bool,
|
|
||||||
) -> Option<(ModPath, Stability)> {
|
) -> Option<(ModPath, Stability)> {
|
||||||
if max_len == 0 {
|
if max_len == 0 {
|
||||||
return None;
|
return None;
|
||||||
@ -185,8 +182,8 @@ fn find_path_for_module(
|
|||||||
|
|
||||||
// Base cases:
|
// Base cases:
|
||||||
// - if the item is already in scope, return the name under which it is
|
// - if the item is already in scope, return the name under which it is
|
||||||
let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
|
let scope_name = find_in_scope(ctx.db, def_map, from, ItemInNs::Types(module_id.into()));
|
||||||
if prefixed.is_none() {
|
if ctx.prefixed.is_none() {
|
||||||
if let Some(scope_name) = scope_name {
|
if let Some(scope_name) = scope_name {
|
||||||
return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable));
|
return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable));
|
||||||
}
|
}
|
||||||
@ -198,20 +195,20 @@ fn find_path_for_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// - if relative paths are fine, check if we are searching for a parent
|
// - if relative paths are fine, check if we are searching for a parent
|
||||||
if prefixed.filter(PrefixKind::is_absolute).is_none() {
|
if ctx.prefixed.filter(PrefixKind::is_absolute).is_none() {
|
||||||
if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
|
if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
|
||||||
return modpath.zip(Some(Stable));
|
return modpath.zip(Some(Stable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
|
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
|
||||||
let root_def_map = crate_root.def_map(db);
|
let root_def_map = crate_root.def_map(ctx.db);
|
||||||
for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() {
|
for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() {
|
||||||
if module_id == def_id {
|
if module_id == def_id {
|
||||||
let name = scope_name.unwrap_or_else(|| name.clone());
|
let name = scope_name.unwrap_or_else(|| name.clone());
|
||||||
|
|
||||||
let name_already_occupied_in_type_ns = def_map
|
let name_already_occupied_in_type_ns = def_map
|
||||||
.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
|
.with_ancestor_maps(ctx.db, from.local_id, &mut |def_map, local_id| {
|
||||||
def_map[local_id]
|
def_map[local_id]
|
||||||
.scope
|
.scope
|
||||||
.type_(&name)
|
.type_(&name)
|
||||||
@ -229,21 +226,18 @@ fn find_path_for_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let value @ Some(_) =
|
if let value @ Some(_) =
|
||||||
find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
|
find_in_prelude(ctx.db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
|
||||||
{
|
{
|
||||||
return value.zip(Some(Stable));
|
return value.zip(Some(Stable));
|
||||||
}
|
}
|
||||||
calculate_best_path(
|
calculate_best_path(
|
||||||
db,
|
ctx,
|
||||||
def_map,
|
def_map,
|
||||||
visited_modules,
|
visited_modules,
|
||||||
crate_root,
|
crate_root,
|
||||||
max_len,
|
max_len,
|
||||||
ItemInNs::Types(module_id.into()),
|
ItemInNs::Types(module_id.into()),
|
||||||
from,
|
from,
|
||||||
prefixed,
|
|
||||||
prefer_no_std,
|
|
||||||
prefer_prelude,
|
|
||||||
scope_name,
|
scope_name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -256,7 +250,7 @@ fn find_in_scope(
|
|||||||
item: ItemInNs,
|
item: ItemInNs,
|
||||||
) -> Option<Name> {
|
) -> Option<Name> {
|
||||||
def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
|
def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
|
||||||
def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
|
def_map[local_id].scope.name_of(item).map(|(name, _, _)| name.clone())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +267,7 @@ fn find_in_prelude(
|
|||||||
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
|
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
|
||||||
let prelude_def_map = prelude_module.def_map(db);
|
let prelude_def_map = prelude_module.def_map(db);
|
||||||
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
|
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
|
||||||
let (name, vis) = prelude_scope.name_of(item)?;
|
let (name, vis, _declared) = prelude_scope.name_of(item)?;
|
||||||
if !vis.is_visible_from(db, from) {
|
if !vis.is_visible_from(db, from) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -315,16 +309,13 @@ fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<M
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_best_path(
|
fn calculate_best_path(
|
||||||
db: &dyn DefDatabase,
|
ctx: FindPathCtx<'_>,
|
||||||
def_map: &DefMap,
|
def_map: &DefMap,
|
||||||
visited_modules: &mut FxHashSet<ModuleId>,
|
visited_modules: &mut FxHashSet<ModuleId>,
|
||||||
crate_root: CrateRootModuleId,
|
crate_root: CrateRootModuleId,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
item: ItemInNs,
|
item: ItemInNs,
|
||||||
from: ModuleId,
|
from: ModuleId,
|
||||||
mut prefixed: Option<PrefixKind>,
|
|
||||||
prefer_no_std: bool,
|
|
||||||
prefer_prelude: bool,
|
|
||||||
scope_name: Option<Name>,
|
scope_name: Option<Name>,
|
||||||
) -> Option<(ModPath, Stability)> {
|
) -> Option<(ModPath, Stability)> {
|
||||||
if max_len <= 1 {
|
if max_len <= 1 {
|
||||||
@ -341,32 +332,29 @@ fn calculate_best_path(
|
|||||||
};
|
};
|
||||||
// Recursive case:
|
// Recursive case:
|
||||||
// - otherwise, look for modules containing (reexporting) it and import it from one of those
|
// - otherwise, look for modules containing (reexporting) it and import it from one of those
|
||||||
if item.krate(db) == Some(from.krate) {
|
if item.krate(ctx.db) == Some(from.krate) {
|
||||||
let mut best_path_len = max_len;
|
let mut best_path_len = max_len;
|
||||||
// Item was defined in the same crate that wants to import it. It cannot be found in any
|
// Item was defined in the same crate that wants to import it. It cannot be found in any
|
||||||
// dependency in this case.
|
// dependency in this case.
|
||||||
for (module_id, name) in find_local_import_locations(db, item, from) {
|
for (module_id, name) in find_local_import_locations(ctx.db, item, from) {
|
||||||
if !visited_modules.insert(module_id) {
|
if !visited_modules.insert(module_id) {
|
||||||
cov_mark::hit!(recursive_imports);
|
cov_mark::hit!(recursive_imports);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(mut path) = find_path_for_module(
|
if let Some(mut path) = find_path_for_module(
|
||||||
db,
|
ctx,
|
||||||
def_map,
|
def_map,
|
||||||
visited_modules,
|
visited_modules,
|
||||||
crate_root,
|
crate_root,
|
||||||
from,
|
from,
|
||||||
module_id,
|
module_id,
|
||||||
best_path_len - 1,
|
best_path_len - 1,
|
||||||
prefixed,
|
|
||||||
prefer_no_std,
|
|
||||||
prefer_prelude,
|
|
||||||
) {
|
) {
|
||||||
path.0.push_segment(name);
|
path.0.push_segment(name);
|
||||||
|
|
||||||
let new_path = match best_path.take() {
|
let new_path = match best_path.take() {
|
||||||
Some(best_path) => {
|
Some(best_path) => {
|
||||||
select_best_path(best_path, path, prefer_no_std, prefer_prelude)
|
select_best_path(best_path, path, ctx.prefer_no_std, ctx.prefer_prelude)
|
||||||
}
|
}
|
||||||
None => path,
|
None => path,
|
||||||
};
|
};
|
||||||
@ -379,8 +367,8 @@ fn calculate_best_path(
|
|||||||
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
|
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
|
||||||
// that wants to import it here, but we always prefer to use the external path here.
|
// that wants to import it here, but we always prefer to use the external path here.
|
||||||
|
|
||||||
for dep in &db.crate_graph()[from.krate].dependencies {
|
for dep in &ctx.db.crate_graph()[from.krate].dependencies {
|
||||||
let import_map = db.import_map(dep.crate_id);
|
let import_map = ctx.db.import_map(dep.crate_id);
|
||||||
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
|
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
|
||||||
for info in import_info_for {
|
for info in import_info_for {
|
||||||
if info.is_doc_hidden {
|
if info.is_doc_hidden {
|
||||||
@ -391,16 +379,13 @@ fn calculate_best_path(
|
|||||||
// Determine best path for containing module and append last segment from `info`.
|
// Determine best path for containing module and append last segment from `info`.
|
||||||
// FIXME: we should guide this to look up the path locally, or from the same crate again?
|
// FIXME: we should guide this to look up the path locally, or from the same crate again?
|
||||||
let Some((mut path, path_stability)) = find_path_for_module(
|
let Some((mut path, path_stability)) = find_path_for_module(
|
||||||
db,
|
ctx,
|
||||||
def_map,
|
def_map,
|
||||||
visited_modules,
|
visited_modules,
|
||||||
crate_root,
|
crate_root,
|
||||||
from,
|
from,
|
||||||
info.container,
|
info.container,
|
||||||
max_len - 1,
|
max_len - 1,
|
||||||
prefixed,
|
|
||||||
prefer_no_std,
|
|
||||||
prefer_prelude,
|
|
||||||
) else {
|
) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@ -413,17 +398,21 @@ fn calculate_best_path(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let new_path_with_stab = match best_path.take() {
|
let new_path_with_stab = match best_path.take() {
|
||||||
Some(best_path) => {
|
Some(best_path) => select_best_path(
|
||||||
select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude)
|
best_path,
|
||||||
}
|
path_with_stab,
|
||||||
|
ctx.prefer_no_std,
|
||||||
|
ctx.prefer_prelude,
|
||||||
|
),
|
||||||
None => path_with_stab,
|
None => path_with_stab,
|
||||||
};
|
};
|
||||||
update_best_path(&mut best_path, new_path_with_stab);
|
update_best_path(&mut best_path, new_path_with_stab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(module) = item.module(db) {
|
let mut prefixed = ctx.prefixed;
|
||||||
if module.containing_block().is_some() && prefixed.is_some() {
|
if let Some(module) = item.module(ctx.db) {
|
||||||
|
if module.containing_block().is_some() && ctx.prefixed.is_some() {
|
||||||
cov_mark::hit!(prefixed_in_block_expression);
|
cov_mark::hit!(prefixed_in_block_expression);
|
||||||
prefixed = Some(PrefixKind::Plain);
|
prefixed = Some(PrefixKind::Plain);
|
||||||
}
|
}
|
||||||
@ -548,34 +537,35 @@ fn find_local_import_locations(
|
|||||||
&ext_def_map[module.local_id]
|
&ext_def_map[module.local_id]
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((name, vis)) = data.scope.name_of(item) {
|
if let Some((name, vis, declared)) = data.scope.name_of(item) {
|
||||||
if vis.is_visible_from(db, from) {
|
if vis.is_visible_from(db, from) {
|
||||||
let is_private = match vis {
|
let is_pub_or_explicit = match vis {
|
||||||
Visibility::Module(private_to) => private_to.local_id == module.local_id,
|
Visibility::Module(_, VisibilityExplicity::Explicit) => {
|
||||||
Visibility::Public => false,
|
cov_mark::hit!(explicit_private_imports);
|
||||||
};
|
true
|
||||||
let is_original_def = match item.as_module_def_id() {
|
}
|
||||||
Some(module_def_id) => data.scope.declarations().any(|it| it == module_def_id),
|
Visibility::Module(_, VisibilityExplicity::Implicit) => {
|
||||||
None => false,
|
cov_mark::hit!(discount_private_imports);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Visibility::Public => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ignore private imports. these could be used if we are
|
// Ignore private imports unless they are explicit. these could be used if we are
|
||||||
// in a submodule of this module, but that's usually not
|
// in a submodule of this module, but that's usually not
|
||||||
// what the user wants; and if this module can import
|
// what the user wants; and if this module can import
|
||||||
// the item and we're a submodule of it, so can we.
|
// the item and we're a submodule of it, so can we.
|
||||||
// Also this keeps the cached data smaller.
|
// Also this keeps the cached data smaller.
|
||||||
if !is_private || is_original_def {
|
if is_pub_or_explicit || declared {
|
||||||
locations.push((module, name.clone()));
|
locations.push((module, name.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Descend into all modules visible from `from`.
|
// Descend into all modules visible from `from`.
|
||||||
for (ty, vis) in data.scope.types() {
|
for (module, vis) in data.scope.modules_in_scope() {
|
||||||
if let ModuleDefId::ModuleId(module) = ty {
|
if vis.is_visible_from(db, from) {
|
||||||
if vis.is_visible_from(db, from) {
|
worklist.push(module);
|
||||||
worklist.push(module);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -625,16 +615,14 @@ mod tests {
|
|||||||
.expect("path does not resolve to a type");
|
.expect("path does not resolve to a type");
|
||||||
|
|
||||||
let found_path = find_path_inner(
|
let found_path = find_path_inner(
|
||||||
&db,
|
FindPathCtx { prefer_no_std: false, db: &db, prefixed: prefix_kind, prefer_prelude },
|
||||||
ItemInNs::Types(resolved),
|
ItemInNs::Types(resolved),
|
||||||
module,
|
module,
|
||||||
prefix_kind,
|
|
||||||
false,
|
|
||||||
prefer_prelude,
|
|
||||||
);
|
);
|
||||||
assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}");
|
assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
fn check_found_path(
|
fn check_found_path(
|
||||||
ra_fixture: &str,
|
ra_fixture: &str,
|
||||||
unprefixed: &str,
|
unprefixed: &str,
|
||||||
@ -1004,6 +992,7 @@ pub use crate::foo::bar::S;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn discount_private_imports() {
|
fn discount_private_imports() {
|
||||||
|
cov_mark::check!(discount_private_imports);
|
||||||
check_found_path(
|
check_found_path(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
//- /main.rs
|
||||||
@ -1021,6 +1010,47 @@ $0
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn explicit_private_imports_crate() {
|
||||||
|
cov_mark::check!(explicit_private_imports);
|
||||||
|
check_found_path(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
mod foo;
|
||||||
|
pub mod bar { pub struct S; }
|
||||||
|
pub(crate) use bar::S;
|
||||||
|
//- /foo.rs
|
||||||
|
$0
|
||||||
|
"#,
|
||||||
|
"crate::S",
|
||||||
|
"crate::S",
|
||||||
|
"crate::S",
|
||||||
|
"crate::S",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn explicit_private_imports() {
|
||||||
|
cov_mark::check!(explicit_private_imports);
|
||||||
|
check_found_path(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
pub mod bar {
|
||||||
|
mod foo;
|
||||||
|
pub mod baz { pub struct S; }
|
||||||
|
pub(self) use baz::S;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /bar/foo.rs
|
||||||
|
$0
|
||||||
|
"#,
|
||||||
|
"super::S",
|
||||||
|
"super::S",
|
||||||
|
"crate::bar::S",
|
||||||
|
"super::S",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn import_cycle() {
|
fn import_cycle() {
|
||||||
check_found_path(
|
check_found_path(
|
||||||
|
@ -107,11 +107,11 @@ impl TypeOrConstParamData {
|
|||||||
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
|
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
|
||||||
|
|
||||||
/// Data about the generic parameters of a function, struct, impl, etc.
|
/// Data about the generic parameters of a function, struct, impl, etc.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct GenericParams {
|
pub struct GenericParams {
|
||||||
pub type_or_consts: Arena<TypeOrConstParamData>,
|
pub type_or_consts: Arena<TypeOrConstParamData>,
|
||||||
pub lifetimes: Arena<LifetimeParamData>,
|
pub lifetimes: Arena<LifetimeParamData>,
|
||||||
pub where_predicates: Vec<WherePredicate>,
|
pub where_predicates: Box<[WherePredicate]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
||||||
@ -142,109 +142,14 @@ pub enum WherePredicateTypeTarget {
|
|||||||
TypeOrConstParam(LocalTypeOrConstParamId),
|
TypeOrConstParam(LocalTypeOrConstParamId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericParams {
|
#[derive(Clone, Default)]
|
||||||
/// Iterator of type_or_consts field
|
pub(crate) struct GenericParamsCollector {
|
||||||
pub fn iter(
|
pub(crate) type_or_consts: Arena<TypeOrConstParamData>,
|
||||||
&self,
|
lifetimes: Arena<LifetimeParamData>,
|
||||||
) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
|
where_predicates: Vec<WherePredicate>,
|
||||||
self.type_or_consts.iter()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn generic_params_query(
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
def: GenericDefId,
|
|
||||||
) -> Interned<GenericParams> {
|
|
||||||
let _p = profile::span("generic_params_query");
|
|
||||||
|
|
||||||
let krate = def.module(db).krate;
|
|
||||||
let cfg_options = db.crate_graph();
|
|
||||||
let cfg_options = &cfg_options[krate].cfg_options;
|
|
||||||
|
|
||||||
// Returns the generic parameters that are enabled under the current `#[cfg]` options
|
|
||||||
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
|
|
||||||
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
|
|
||||||
|
|
||||||
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
|
|
||||||
// Therefore, make a first pass to check if all parameters are enabled and, if so,
|
|
||||||
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
|
|
||||||
let all_type_or_consts_enabled =
|
|
||||||
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
|
|
||||||
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
|
|
||||||
|
|
||||||
if all_type_or_consts_enabled && all_lifetimes_enabled {
|
|
||||||
params.clone()
|
|
||||||
} else {
|
|
||||||
Interned::new(GenericParams {
|
|
||||||
type_or_consts: all_type_or_consts_enabled
|
|
||||||
.then(|| params.type_or_consts.clone())
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
params
|
|
||||||
.type_or_consts
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(idx, param)| {
|
|
||||||
enabled(idx.into()).then(|| param.clone())
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}),
|
|
||||||
lifetimes: all_lifetimes_enabled
|
|
||||||
.then(|| params.lifetimes.clone())
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
params
|
|
||||||
.lifetimes
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(idx, param)| {
|
|
||||||
enabled(idx.into()).then(|| param.clone())
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}),
|
|
||||||
where_predicates: params.where_predicates.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
macro_rules! id_to_generics {
|
|
||||||
($id:ident) => {{
|
|
||||||
let id = $id.lookup(db).id;
|
|
||||||
let tree = id.item_tree(db);
|
|
||||||
let item = &tree[id.value];
|
|
||||||
enabled_params(&item.generic_params, &tree)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
match def {
|
|
||||||
GenericDefId::FunctionId(id) => {
|
|
||||||
let loc = id.lookup(db);
|
|
||||||
let tree = loc.id.item_tree(db);
|
|
||||||
let item = &tree[loc.id.value];
|
|
||||||
|
|
||||||
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
|
|
||||||
let mut generic_params = GenericParams::clone(&enabled_params);
|
|
||||||
|
|
||||||
let module = loc.container.module(db);
|
|
||||||
let func_data = db.function_data(id);
|
|
||||||
|
|
||||||
// Don't create an `Expander` if not needed since this
|
|
||||||
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
|
|
||||||
let mut expander =
|
|
||||||
Lazy::new(|| (module.def_map(db), Expander::new(db, loc.id.file_id(), module)));
|
|
||||||
for param in func_data.params.iter() {
|
|
||||||
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
Interned::new(generic_params)
|
|
||||||
}
|
|
||||||
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id),
|
|
||||||
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id),
|
|
||||||
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id),
|
|
||||||
GenericDefId::TraitId(id) => id_to_generics!(id),
|
|
||||||
GenericDefId::TraitAliasId(id) => id_to_generics!(id),
|
|
||||||
GenericDefId::TypeAliasId(id) => id_to_generics!(id),
|
|
||||||
GenericDefId::ImplId(id) => id_to_generics!(id),
|
|
||||||
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
|
|
||||||
Interned::new(GenericParams::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl GenericParamsCollector {
|
||||||
pub(crate) fn fill(
|
pub(crate) fn fill(
|
||||||
&mut self,
|
&mut self,
|
||||||
lower_ctx: &LowerCtx<'_>,
|
lower_ctx: &LowerCtx<'_>,
|
||||||
@ -444,11 +349,131 @@ impl GenericParams {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn shrink_to_fit(&mut self) {
|
pub(crate) fn finish(self) -> GenericParams {
|
||||||
let Self { lifetimes, type_or_consts: types, where_predicates } = self;
|
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
|
||||||
lifetimes.shrink_to_fit();
|
lifetimes.shrink_to_fit();
|
||||||
types.shrink_to_fit();
|
type_or_consts.shrink_to_fit();
|
||||||
where_predicates.shrink_to_fit();
|
GenericParams {
|
||||||
|
type_or_consts,
|
||||||
|
lifetimes,
|
||||||
|
where_predicates: where_predicates.into_boxed_slice(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenericParams {
|
||||||
|
/// Iterator of type_or_consts field
|
||||||
|
pub fn iter(
|
||||||
|
&self,
|
||||||
|
) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
|
||||||
|
self.type_or_consts.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn generic_params_query(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
def: GenericDefId,
|
||||||
|
) -> Interned<GenericParams> {
|
||||||
|
let _p = profile::span("generic_params_query");
|
||||||
|
|
||||||
|
let krate = def.module(db).krate;
|
||||||
|
let cfg_options = db.crate_graph();
|
||||||
|
let cfg_options = &cfg_options[krate].cfg_options;
|
||||||
|
|
||||||
|
// Returns the generic parameters that are enabled under the current `#[cfg]` options
|
||||||
|
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
|
||||||
|
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
|
||||||
|
|
||||||
|
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
|
||||||
|
// Therefore, make a first pass to check if all parameters are enabled and, if so,
|
||||||
|
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
|
||||||
|
let all_type_or_consts_enabled =
|
||||||
|
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
|
||||||
|
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
|
||||||
|
|
||||||
|
if all_type_or_consts_enabled && all_lifetimes_enabled {
|
||||||
|
params.clone()
|
||||||
|
} else {
|
||||||
|
Interned::new(GenericParams {
|
||||||
|
type_or_consts: all_type_or_consts_enabled
|
||||||
|
.then(|| params.type_or_consts.clone())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
params
|
||||||
|
.type_or_consts
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(idx, param)| {
|
||||||
|
enabled(idx.into()).then(|| param.clone())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}),
|
||||||
|
lifetimes: all_lifetimes_enabled
|
||||||
|
.then(|| params.lifetimes.clone())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
params
|
||||||
|
.lifetimes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(idx, param)| {
|
||||||
|
enabled(idx.into()).then(|| param.clone())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}),
|
||||||
|
where_predicates: params.where_predicates.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
macro_rules! id_to_generics {
|
||||||
|
($id:ident) => {{
|
||||||
|
let id = $id.lookup(db).id;
|
||||||
|
let tree = id.item_tree(db);
|
||||||
|
let item = &tree[id.value];
|
||||||
|
enabled_params(&item.generic_params, &tree)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
match def {
|
||||||
|
GenericDefId::FunctionId(id) => {
|
||||||
|
let loc = id.lookup(db);
|
||||||
|
let tree = loc.id.item_tree(db);
|
||||||
|
let item = &tree[loc.id.value];
|
||||||
|
|
||||||
|
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
|
||||||
|
|
||||||
|
let module = loc.container.module(db);
|
||||||
|
let func_data = db.function_data(id);
|
||||||
|
if func_data.params.is_empty() {
|
||||||
|
enabled_params
|
||||||
|
} else {
|
||||||
|
let mut generic_params = GenericParamsCollector {
|
||||||
|
type_or_consts: enabled_params.type_or_consts.clone(),
|
||||||
|
lifetimes: enabled_params.lifetimes.clone(),
|
||||||
|
where_predicates: enabled_params.where_predicates.clone().into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Don't create an `Expander` if not needed since this
|
||||||
|
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
|
||||||
|
let mut expander = Lazy::new(|| {
|
||||||
|
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
|
||||||
|
});
|
||||||
|
for param in func_data.params.iter() {
|
||||||
|
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
|
||||||
|
}
|
||||||
|
Interned::new(generic_params.finish())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id),
|
||||||
|
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id),
|
||||||
|
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id),
|
||||||
|
GenericDefId::TraitId(id) => id_to_generics!(id),
|
||||||
|
GenericDefId::TraitAliasId(id) => id_to_generics!(id),
|
||||||
|
GenericDefId::TypeAliasId(id) => id_to_generics!(id),
|
||||||
|
GenericDefId::ImplId(id) => id_to_generics!(id),
|
||||||
|
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
|
||||||
|
Interned::new(GenericParams {
|
||||||
|
type_or_consts: Default::default(),
|
||||||
|
lifetimes: Default::default(),
|
||||||
|
where_predicates: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
|
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use rustc_dependencies::parse_format as parse;
|
use rustc_parse_format as parse;
|
||||||
use stdx::TupleExt;
|
use stdx::TupleExt;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, IsString},
|
ast::{self, IsString},
|
||||||
|
@ -116,8 +116,7 @@ pub enum TypeRef {
|
|||||||
Path(Path),
|
Path(Path),
|
||||||
RawPtr(Box<TypeRef>, Mutability),
|
RawPtr(Box<TypeRef>, Mutability),
|
||||||
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
|
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
|
||||||
// FIXME: for full const generics, the latter element (length) here is going to have to be an
|
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
|
||||||
// expression that is further lowered later in hir_ty.
|
|
||||||
Array(Box<TypeRef>, ConstRef),
|
Array(Box<TypeRef>, ConstRef),
|
||||||
Slice(Box<TypeRef>),
|
Slice(Box<TypeRef>),
|
||||||
/// A fn pointer. Last element of the vector is the return type.
|
/// A fn pointer. Last element of the vector is the return type.
|
||||||
|
@ -15,9 +15,11 @@ use stdx::format_to;
|
|||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
|
db::DefDatabase,
|
||||||
ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId,
|
per_ns::PerNs,
|
||||||
TraitId, UseId,
|
visibility::{Visibility, VisibilityExplicity},
|
||||||
|
AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId,
|
||||||
|
ModuleDefId, ModuleId, TraitId, UseId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@ -105,7 +107,7 @@ pub struct ItemScope {
|
|||||||
/// The attribute macro invocations in this scope.
|
/// The attribute macro invocations in this scope.
|
||||||
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
|
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
|
||||||
/// The macro invocations in this scope.
|
/// The macro invocations in this scope.
|
||||||
pub macro_invocations: FxHashMap<AstId<ast::MacroCall>, MacroCallId>,
|
macro_invocations: FxHashMap<AstId<ast::MacroCall>, MacroCallId>,
|
||||||
/// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
|
/// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
|
||||||
/// paired with the derive macro invocations for the specific attribute.
|
/// paired with the derive macro invocations for the specific attribute.
|
||||||
derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
|
derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
|
||||||
@ -145,8 +147,8 @@ impl ItemScope {
|
|||||||
.chain(self.values.keys())
|
.chain(self.values.keys())
|
||||||
.chain(self.macros.keys())
|
.chain(self.macros.keys())
|
||||||
.chain(self.unresolved.iter())
|
.chain(self.unresolved.iter())
|
||||||
.unique()
|
|
||||||
.sorted()
|
.sorted()
|
||||||
|
.dedup()
|
||||||
.map(move |name| (name, self.get(name)))
|
.map(move |name| (name, self.get(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,8 +159,8 @@ impl ItemScope {
|
|||||||
.filter_map(ImportOrExternCrate::into_import)
|
.filter_map(ImportOrExternCrate::into_import)
|
||||||
.chain(self.use_imports_values.keys().copied())
|
.chain(self.use_imports_values.keys().copied())
|
||||||
.chain(self.use_imports_macros.keys().copied())
|
.chain(self.use_imports_macros.keys().copied())
|
||||||
.unique()
|
|
||||||
.sorted()
|
.sorted()
|
||||||
|
.dedup()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
|
pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
|
||||||
@ -234,20 +236,37 @@ impl ItemScope {
|
|||||||
self.impls.iter().copied()
|
self.impls.iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn values(
|
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
|
||||||
&self,
|
self.types.values().copied().filter_map(|(def, vis, _)| match def {
|
||||||
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
|
ModuleDefId::ModuleId(module) => Some((module, vis)),
|
||||||
self.values.values().copied().map(|(a, b, _)| (a, b))
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn types(
|
pub fn unnamed_consts<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
|
db: &'a dyn DefDatabase,
|
||||||
self.types.values().copied().map(|(def, vis, _)| (def, vis))
|
) -> impl Iterator<Item = ConstId> + 'a {
|
||||||
}
|
// FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
|
||||||
|
// Should be removed once synstructure stops doing that.
|
||||||
|
let synstructure_hack_consts = self.values.values().filter_map(|(item, _, _)| match item {
|
||||||
|
&ModuleDefId::ConstId(id) => {
|
||||||
|
let loc = id.lookup(db);
|
||||||
|
let item_tree = loc.id.item_tree(db);
|
||||||
|
if item_tree[loc.id.value]
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
|
||||||
|
{
|
||||||
|
Some(id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
|
self.unnamed_consts.iter().copied().chain(synstructure_hack_consts)
|
||||||
self.unnamed_consts.iter().copied()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all module scoped macros
|
/// Iterate over all module scoped macros
|
||||||
@ -274,21 +293,18 @@ impl ItemScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
|
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
|
||||||
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
|
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> {
|
||||||
match item {
|
match item {
|
||||||
ItemInNs::Macros(def) => self
|
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||||
.macros
|
(other_def == def).then_some((name, vis, i.is_none()))
|
||||||
.iter()
|
}),
|
||||||
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
|
ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||||
ItemInNs::Types(def) => self
|
(other_def == def).then_some((name, vis, i.is_none()))
|
||||||
.types
|
}),
|
||||||
.iter()
|
|
||||||
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
|
|
||||||
|
|
||||||
ItemInNs::Values(def) => self
|
ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||||
.values
|
(other_def == def).then_some((name, vis, i.is_none()))
|
||||||
.iter()
|
}),
|
||||||
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +332,10 @@ impl ItemScope {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn macro_invoc(&self, call: AstId<ast::MacroCall>) -> Option<MacroCallId> {
|
||||||
|
self.macro_invocations.get(&call).copied()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemScope {
|
impl ItemScope {
|
||||||
@ -624,18 +644,17 @@ impl ItemScope {
|
|||||||
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
|
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
|
||||||
self.types
|
self.types
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.map(|(def, vis, _)| (def, vis))
|
.map(|(_, vis, _)| vis)
|
||||||
.chain(self.values.values_mut().map(|(def, vis, _)| (def, vis)))
|
.chain(self.values.values_mut().map(|(_, vis, _)| vis))
|
||||||
.map(|(_, v)| v)
|
|
||||||
.chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
|
.chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
|
||||||
.for_each(|vis| *vis = Visibility::Module(this_module));
|
.for_each(|vis| *vis = Visibility::Module(this_module, VisibilityExplicity::Implicit));
|
||||||
|
|
||||||
for (mac, vis, import) in self.macros.values_mut() {
|
for (mac, vis, import) in self.macros.values_mut() {
|
||||||
if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
|
if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*vis = Visibility::Module(this_module);
|
*vis = Visibility::Module(this_module, VisibilityExplicity::Implicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ use crate::{
|
|||||||
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
|
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
|
||||||
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
||||||
visibility::RawVisibility,
|
visibility::{RawVisibility, VisibilityExplicity},
|
||||||
BlockId, Lookup,
|
BlockId, Lookup,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,8 +78,9 @@ pub struct RawVisibilityId(u32);
|
|||||||
|
|
||||||
impl RawVisibilityId {
|
impl RawVisibilityId {
|
||||||
pub const PUB: Self = RawVisibilityId(u32::max_value());
|
pub const PUB: Self = RawVisibilityId(u32::max_value());
|
||||||
pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
|
pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
|
||||||
pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
|
pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2);
|
||||||
|
pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for RawVisibilityId {
|
impl fmt::Debug for RawVisibilityId {
|
||||||
@ -87,7 +88,7 @@ impl fmt::Debug for RawVisibilityId {
|
|||||||
let mut f = f.debug_tuple("RawVisibilityId");
|
let mut f = f.debug_tuple("RawVisibilityId");
|
||||||
match *self {
|
match *self {
|
||||||
Self::PUB => f.field(&"pub"),
|
Self::PUB => f.field(&"pub"),
|
||||||
Self::PRIV => f.field(&"pub(self)"),
|
Self::PRIV_IMPLICIT | Self::PRIV_EXPLICIT => f.field(&"pub(self)"),
|
||||||
Self::PUB_CRATE => f.field(&"pub(crate)"),
|
Self::PUB_CRATE => f.field(&"pub(crate)"),
|
||||||
_ => f.field(&self.0),
|
_ => f.field(&self.0),
|
||||||
};
|
};
|
||||||
@ -249,19 +250,30 @@ impl ItemVisibilities {
|
|||||||
fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
|
fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
|
||||||
match &vis {
|
match &vis {
|
||||||
RawVisibility::Public => RawVisibilityId::PUB,
|
RawVisibility::Public => RawVisibilityId::PUB,
|
||||||
RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind {
|
RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => {
|
||||||
PathKind::Super(0) => RawVisibilityId::PRIV,
|
match (&path.kind, explicitiy) {
|
||||||
PathKind::Crate => RawVisibilityId::PUB_CRATE,
|
(PathKind::Super(0), VisibilityExplicity::Explicit) => {
|
||||||
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
|
RawVisibilityId::PRIV_EXPLICIT
|
||||||
},
|
}
|
||||||
|
(PathKind::Super(0), VisibilityExplicity::Implicit) => {
|
||||||
|
RawVisibilityId::PRIV_IMPLICIT
|
||||||
|
}
|
||||||
|
(PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
|
||||||
|
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
|
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VIS_PUB: RawVisibility = RawVisibility::Public;
|
static VIS_PUB: RawVisibility = RawVisibility::Public;
|
||||||
static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)));
|
static VIS_PRIV_IMPLICIT: RawVisibility =
|
||||||
static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
|
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Implicit);
|
||||||
|
static VIS_PRIV_EXPLICIT: RawVisibility =
|
||||||
|
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Explicit);
|
||||||
|
static VIS_PUB_CRATE: RawVisibility =
|
||||||
|
RawVisibility::Module(ModPath::from_kind(PathKind::Crate), VisibilityExplicity::Explicit);
|
||||||
|
|
||||||
#[derive(Default, Debug, Eq, PartialEq)]
|
#[derive(Default, Debug, Eq, PartialEq)]
|
||||||
struct ItemTreeData {
|
struct ItemTreeData {
|
||||||
@ -540,7 +552,8 @@ impl Index<RawVisibilityId> for ItemTree {
|
|||||||
type Output = RawVisibility;
|
type Output = RawVisibility;
|
||||||
fn index(&self, index: RawVisibilityId) -> &Self::Output {
|
fn index(&self, index: RawVisibilityId) -> &Self::Output {
|
||||||
match index {
|
match index {
|
||||||
RawVisibilityId::PRIV => &VIS_PRIV,
|
RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
|
||||||
|
RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
|
||||||
RawVisibilityId::PUB => &VIS_PUB,
|
RawVisibilityId::PUB => &VIS_PUB,
|
||||||
RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
|
RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
|
||||||
_ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
|
_ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
|
||||||
|
@ -6,7 +6,7 @@ use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef, HirFileId};
|
|||||||
use syntax::ast::{self, HasModuleItem, HasTypeBounds};
|
use syntax::ast::{self, HasModuleItem, HasTypeBounds};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
generics::{GenericParams, TypeParamData, TypeParamProvenance},
|
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
|
||||||
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
|
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
|
||||||
LocalLifetimeParamId, LocalTypeOrConstParamId,
|
LocalLifetimeParamId, LocalTypeOrConstParamId,
|
||||||
};
|
};
|
||||||
@ -386,17 +386,16 @@ impl<'a> Ctx<'a> {
|
|||||||
flags |= FnFlags::HAS_UNSAFE_KW;
|
flags |= FnFlags::HAS_UNSAFE_KW;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = Function {
|
let res = Function {
|
||||||
name,
|
name,
|
||||||
visibility,
|
visibility,
|
||||||
explicit_generic_params: Interned::new(GenericParams::default()),
|
explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
|
||||||
abi,
|
abi,
|
||||||
params,
|
params,
|
||||||
ret_type: Interned::new(ret_type),
|
ret_type: Interned::new(ret_type),
|
||||||
ast_id,
|
ast_id,
|
||||||
flags,
|
flags,
|
||||||
};
|
};
|
||||||
res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func);
|
|
||||||
|
|
||||||
Some(id(self.data().functions.alloc(res)))
|
Some(id(self.data().functions.alloc(res)))
|
||||||
}
|
}
|
||||||
@ -604,7 +603,7 @@ impl<'a> Ctx<'a> {
|
|||||||
has_implicit_self: HasImplicitSelf,
|
has_implicit_self: HasImplicitSelf,
|
||||||
node: &dyn ast::HasGenericParams,
|
node: &dyn ast::HasGenericParams,
|
||||||
) -> Interned<GenericParams> {
|
) -> Interned<GenericParams> {
|
||||||
let mut generics = GenericParams::default();
|
let mut generics = GenericParamsCollector::default();
|
||||||
|
|
||||||
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
|
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
|
||||||
// Traits and trait aliases get the Self type as an implicit first type parameter.
|
// Traits and trait aliases get the Self type as an implicit first type parameter.
|
||||||
@ -642,8 +641,7 @@ impl<'a> Ctx<'a> {
|
|||||||
};
|
};
|
||||||
generics.fill(&self.body_ctx, node, add_param_attrs);
|
generics.fill(&self.body_ctx, node, add_param_attrs);
|
||||||
|
|
||||||
generics.shrink_to_fit();
|
Interned::new(generics.finish())
|
||||||
Interned::new(generics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
|
fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
|
||||||
|
@ -104,7 +104,9 @@ impl Printer<'_> {
|
|||||||
|
|
||||||
fn print_visibility(&mut self, vis: RawVisibilityId) {
|
fn print_visibility(&mut self, vis: RawVisibilityId) {
|
||||||
match &self.tree[vis] {
|
match &self.tree[vis] {
|
||||||
RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db.upcast())),
|
RawVisibility::Module(path, _expl) => {
|
||||||
|
w!(self, "pub({}) ", path.display(self.db.upcast()))
|
||||||
|
}
|
||||||
RawVisibility::Public => w!(self, "pub "),
|
RawVisibility::Public => w!(self, "pub "),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,10 @@ impl LangItems {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Salsa query. This will look for lang items in a specific crate.
|
/// Salsa query. This will look for lang items in a specific crate.
|
||||||
pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<LangItems> {
|
pub(crate) fn crate_lang_items_query(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
|
) -> Option<Arc<LangItems>> {
|
||||||
let _p = profile::span("crate_lang_items_query");
|
let _p = profile::span("crate_lang_items_query");
|
||||||
|
|
||||||
let mut lang_items = LangItems::default();
|
let mut lang_items = LangItems::default();
|
||||||
@ -150,7 +153,11 @@ impl LangItems {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Arc::new(lang_items)
|
if lang_items.items.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Arc::new(lang_items))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Salsa query. Look for a lang item, starting from the specified crate and recursively
|
/// Salsa query. Look for a lang item, starting from the specified crate and recursively
|
||||||
@ -161,9 +168,9 @@ impl LangItems {
|
|||||||
item: LangItem,
|
item: LangItem,
|
||||||
) -> Option<LangItemTarget> {
|
) -> Option<LangItemTarget> {
|
||||||
let _p = profile::span("lang_item_query");
|
let _p = profile::span("lang_item_query");
|
||||||
let lang_items = db.crate_lang_items(start_crate);
|
if let Some(target) =
|
||||||
let start_crate_target = lang_items.items.get(&item);
|
db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied())
|
||||||
if let Some(&target) = start_crate_target {
|
{
|
||||||
return Some(target);
|
return Some(target);
|
||||||
}
|
}
|
||||||
db.crate_graph()[start_crate]
|
db.crate_graph()[start_crate]
|
||||||
|
@ -10,10 +10,17 @@
|
|||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||||
|
|
||||||
#[allow(unused)]
|
#[cfg(feature = "in-rust-tree")]
|
||||||
macro_rules! eprintln {
|
extern crate rustc_parse_format;
|
||||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
|
||||||
}
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
|
extern crate ra_ap_rustc_parse_format as rustc_parse_format;
|
||||||
|
|
||||||
|
#[cfg(feature = "in-rust-tree")]
|
||||||
|
extern crate rustc_abi;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
|
extern crate ra_ap_rustc_abi as rustc_abi;
|
||||||
|
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
@ -49,7 +56,7 @@ pub mod visibility;
|
|||||||
pub mod find_path;
|
pub mod find_path;
|
||||||
pub mod import_map;
|
pub mod import_map;
|
||||||
|
|
||||||
pub use rustc_dependencies::abi as layout;
|
pub use rustc_abi as layout;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -16,13 +16,12 @@ struct Foo;
|
|||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
impl < > core::marker::Copy for Foo< > where {}"#]],
|
impl < > $crate::marker::Copy for Foo< > where {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_copy_expand_in_core() {
|
fn test_copy_expand_in_core() {
|
||||||
cov_mark::check!(test_copy_expand_in_core);
|
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
//- /lib.rs crate:core
|
//- /lib.rs crate:core
|
||||||
@ -41,7 +40,7 @@ macro Copy {}
|
|||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
impl < > crate ::marker::Copy for Foo< > where {}"#]],
|
impl < > $crate::marker::Copy for Foo< > where {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ struct Foo<A, B>;
|
|||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo<A, B>;
|
struct Foo<A, B>;
|
||||||
|
|
||||||
impl <A: core::marker::Copy, B: core::marker::Copy, > core::marker::Copy for Foo<A, B, > where {}"#]],
|
impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ struct Foo<A, B, 'a, 'b>;
|
|||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Foo<A, B, 'a, 'b>;
|
struct Foo<A, B, 'a, 'b>;
|
||||||
|
|
||||||
impl <A: core::marker::Copy, B: core::marker::Copy, > core::marker::Copy for Foo<A, B, > where {}"#]],
|
impl <A: $crate::marker::Copy, B: $crate::marker::Copy, > $crate::marker::Copy for Foo<A, B, > where {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +97,7 @@ enum Command<A, B> {
|
|||||||
Jump,
|
Jump,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <A: core::clone::Clone, B: core::clone::Clone, > core::clone::Clone for Command<A, B, > where {
|
impl <A: $crate::clone::Clone, B: $crate::clone::Clone, > $crate::clone::Clone for Command<A, B, > where {
|
||||||
fn clone(&self ) -> Self {
|
fn clone(&self ) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Command::Move {
|
Command::Move {
|
||||||
@ -158,7 +157,7 @@ where
|
|||||||
generic: Vec<T::InGenericArg>,
|
generic: Vec<T::InGenericArg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: core::clone::Clone, > core::clone::Clone for Foo<T, > where T: Trait, T::InFieldShorthand: core::clone::Clone, T::InGenericArg: core::clone::Clone, {
|
impl <T: $crate::clone::Clone, > $crate::clone::Clone for Foo<T, > where T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, {
|
||||||
fn clone(&self ) -> Self {
|
fn clone(&self ) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Foo {
|
Foo {
|
||||||
@ -186,7 +185,7 @@ struct Foo<const X: usize, T>(u32);
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Foo<const X: usize, T>(u32);
|
struct Foo<const X: usize, T>(u32);
|
||||||
|
|
||||||
impl <const X: usize, T: core::clone::Clone, > core::clone::Clone for Foo<X, T, > where {
|
impl <const X: usize, T: $crate::clone::Clone, > $crate::clone::Clone for Foo<X, T, > where {
|
||||||
fn clone(&self ) -> Self {
|
fn clone(&self ) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Foo(f0, )=>Foo(f0.clone(), ),
|
Foo(f0, )=>Foo(f0.clone(), ),
|
||||||
@ -226,14 +225,14 @@ enum Bar {
|
|||||||
Bar,
|
Bar,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::default::Default for Foo< > where {
|
impl < > $crate::default::Default for Foo< > where {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Foo {
|
Foo {
|
||||||
field1: core::default::Default::default(), field2: core::default::Default::default(),
|
field1: $crate::default::Default::default(), field2: $crate::default::Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl < > core::default::Default for Bar< > where {
|
impl < > $crate::default::Default for Bar< > where {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Bar::Bar
|
Bar::Bar
|
||||||
}
|
}
|
||||||
@ -261,7 +260,7 @@ enum Command {
|
|||||||
Jump,
|
Jump,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::cmp::PartialEq for Command< > where {
|
impl < > $crate::cmp::PartialEq for Command< > where {
|
||||||
fn eq(&self , other: &Self ) -> bool {
|
fn eq(&self , other: &Self ) -> bool {
|
||||||
match (self , other) {
|
match (self , other) {
|
||||||
(Command::Move {
|
(Command::Move {
|
||||||
@ -274,7 +273,7 @@ impl < > core::cmp::PartialEq for Command< > where {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl < > core::cmp::Eq for Command< > where {}"#]],
|
impl < > $crate::cmp::Eq for Command< > where {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +298,7 @@ enum Command {
|
|||||||
Jump,
|
Jump,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::cmp::PartialEq for Command< > where {
|
impl < > $crate::cmp::PartialEq for Command< > where {
|
||||||
fn eq(&self , other: &Self ) -> bool {
|
fn eq(&self , other: &Self ) -> bool {
|
||||||
match (self , other) {
|
match (self , other) {
|
||||||
(Command::Move {
|
(Command::Move {
|
||||||
@ -312,7 +311,7 @@ impl < > core::cmp::PartialEq for Command< > where {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl < > core::cmp::Eq for Command< > where {}"#]],
|
impl < > $crate::cmp::Eq for Command< > where {}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,10 +335,10 @@ enum Command {
|
|||||||
Jump,
|
Jump,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::cmp::PartialOrd for Command< > where {
|
impl < > $crate::cmp::PartialOrd for Command< > where {
|
||||||
fn partial_cmp(&self , other: &Self ) -> core::option::Option::Option<core::cmp::Ordering> {
|
fn partial_cmp(&self , other: &Self ) -> $crate::option::Option::Option<$crate::cmp::Ordering> {
|
||||||
match core::intrinsics::discriminant_value(self ).partial_cmp(&core::intrinsics::discriminant_value(other)) {
|
match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) {
|
||||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||||
match (self , other) {
|
match (self , other) {
|
||||||
(Command::Move {
|
(Command::Move {
|
||||||
x: x_self, y: y_self,
|
x: x_self, y: y_self,
|
||||||
@ -348,10 +347,10 @@ impl < > core::cmp::PartialOrd for Command< > where {
|
|||||||
x: x_other, y: y_other,
|
x: x_other, y: y_other,
|
||||||
}
|
}
|
||||||
)=>match x_self.partial_cmp(&x_other) {
|
)=>match x_self.partial_cmp(&x_other) {
|
||||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||||
match y_self.partial_cmp(&y_other) {
|
match y_self.partial_cmp(&y_other) {
|
||||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||||
core::option::Option::Some(core::cmp::Ordering::Equal)
|
$crate::option::Option::Some($crate::cmp::Ordering::Equal)
|
||||||
}
|
}
|
||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
@ -359,22 +358,22 @@ impl < > core::cmp::PartialOrd for Command< > where {
|
|||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) {
|
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) {
|
||||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||||
core::option::Option::Some(core::cmp::Ordering::Equal)
|
$crate::option::Option::Some($crate::cmp::Ordering::Equal)
|
||||||
}
|
}
|
||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
, (Command::Jump, Command::Jump)=>core::option::Option::Some(core::cmp::Ordering::Equal), _unused=>core::option::Option::Some(core::cmp::Ordering::Equal)
|
, (Command::Jump, Command::Jump)=>$crate::option::Option::Some($crate::cmp::Ordering::Equal), _unused=>$crate::option::Option::Some($crate::cmp::Ordering::Equal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl < > core::cmp::Ord for Command< > where {
|
impl < > $crate::cmp::Ord for Command< > where {
|
||||||
fn cmp(&self , other: &Self ) -> core::cmp::Ordering {
|
fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering {
|
||||||
match core::intrinsics::discriminant_value(self ).cmp(&core::intrinsics::discriminant_value(other)) {
|
match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) {
|
||||||
core::cmp::Ordering::Equal=> {
|
$crate::cmp::Ordering::Equal=> {
|
||||||
match (self , other) {
|
match (self , other) {
|
||||||
(Command::Move {
|
(Command::Move {
|
||||||
x: x_self, y: y_self,
|
x: x_self, y: y_self,
|
||||||
@ -383,10 +382,10 @@ impl < > core::cmp::Ord for Command< > where {
|
|||||||
x: x_other, y: y_other,
|
x: x_other, y: y_other,
|
||||||
}
|
}
|
||||||
)=>match x_self.cmp(&x_other) {
|
)=>match x_self.cmp(&x_other) {
|
||||||
core::cmp::Ordering::Equal=> {
|
$crate::cmp::Ordering::Equal=> {
|
||||||
match y_self.cmp(&y_other) {
|
match y_self.cmp(&y_other) {
|
||||||
core::cmp::Ordering::Equal=> {
|
$crate::cmp::Ordering::Equal=> {
|
||||||
core::cmp::Ordering::Equal
|
$crate::cmp::Ordering::Equal
|
||||||
}
|
}
|
||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
@ -394,12 +393,12 @@ impl < > core::cmp::Ord for Command< > where {
|
|||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) {
|
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) {
|
||||||
core::cmp::Ordering::Equal=> {
|
$crate::cmp::Ordering::Equal=> {
|
||||||
core::cmp::Ordering::Equal
|
$crate::cmp::Ordering::Equal
|
||||||
}
|
}
|
||||||
c=>return c,
|
c=>return c,
|
||||||
}
|
}
|
||||||
, (Command::Jump, Command::Jump)=>core::cmp::Ordering::Equal, _unused=>core::cmp::Ordering::Equal
|
, (Command::Jump, Command::Jump)=>$crate::cmp::Ordering::Equal, _unused=>$crate::cmp::Ordering::Equal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c=>return c,
|
c=>return c,
|
||||||
@ -433,8 +432,8 @@ struct Foo {
|
|||||||
z: (i32, u64),
|
z: (i32, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::hash::Hash for Foo< > where {
|
impl < > $crate::hash::Hash for Foo< > where {
|
||||||
fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
||||||
match self {
|
match self {
|
||||||
Foo {
|
Foo {
|
||||||
x: x, y: y, z: z,
|
x: x, y: y, z: z,
|
||||||
@ -471,9 +470,9 @@ enum Command {
|
|||||||
Jump,
|
Jump,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::hash::Hash for Command< > where {
|
impl < > $crate::hash::Hash for Command< > where {
|
||||||
fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
||||||
core::mem::discriminant(self ).hash(ra_expand_state);
|
$crate::mem::discriminant(self ).hash(ra_expand_state);
|
||||||
match self {
|
match self {
|
||||||
Command::Move {
|
Command::Move {
|
||||||
x: x, y: y,
|
x: x, y: y,
|
||||||
@ -517,8 +516,8 @@ enum Command {
|
|||||||
Jump,
|
Jump,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl < > core::fmt::Debug for Command< > where {
|
impl < > $crate::fmt::Debug for Command< > where {
|
||||||
fn fmt(&self , f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Command::Move {
|
Command::Move {
|
||||||
x: x, y: y,
|
x: x, y: y,
|
||||||
|
@ -136,7 +136,7 @@ fn main() { option_env!("TEST_ENV_VAR"); }
|
|||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! option_env {() => {}}
|
macro_rules! option_env {() => {}}
|
||||||
|
|
||||||
fn main() { ::core::option::Option::None:: < &str>; }
|
fn main() { $crate::option::Option::None:: < &str>; }
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ use crate::{
|
|||||||
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
|
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
|
||||||
path::ModPath,
|
path::ModPath,
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
visibility::Visibility,
|
visibility::{Visibility, VisibilityExplicity},
|
||||||
AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
|
AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
|
||||||
MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||||
};
|
};
|
||||||
@ -332,7 +332,10 @@ impl DefMap {
|
|||||||
// NB: we use `None` as block here, which would be wrong for implicit
|
// NB: we use `None` as block here, which would be wrong for implicit
|
||||||
// modules declared by blocks with items. At the moment, we don't use
|
// modules declared by blocks with items. At the moment, we don't use
|
||||||
// this visibility for anything outside IDE, so that's probably OK.
|
// this visibility for anything outside IDE, so that's probably OK.
|
||||||
let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
|
let visibility = Visibility::Module(
|
||||||
|
ModuleId { krate, local_id, block: None },
|
||||||
|
VisibilityExplicity::Implicit,
|
||||||
|
);
|
||||||
let module_data = ModuleData::new(
|
let module_data = ModuleData::new(
|
||||||
ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
|
ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
|
||||||
visibility,
|
visibility,
|
||||||
|
@ -87,7 +87,7 @@ impl DefMap {
|
|||||||
within_impl: bool,
|
within_impl: bool,
|
||||||
) -> Option<Visibility> {
|
) -> Option<Visibility> {
|
||||||
let mut vis = match visibility {
|
let mut vis = match visibility {
|
||||||
RawVisibility::Module(path) => {
|
RawVisibility::Module(path, explicity) => {
|
||||||
let (result, remaining) =
|
let (result, remaining) =
|
||||||
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
|
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
|
||||||
if remaining.is_some() {
|
if remaining.is_some() {
|
||||||
@ -95,7 +95,7 @@ impl DefMap {
|
|||||||
}
|
}
|
||||||
let types = result.take_types()?;
|
let types = result.take_types()?;
|
||||||
match types {
|
match types {
|
||||||
ModuleDefId::ModuleId(m) => Visibility::Module(m),
|
ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicity),
|
||||||
// error: visibility needs to refer to module
|
// error: visibility needs to refer to module
|
||||||
_ => {
|
_ => {
|
||||||
return None;
|
return None;
|
||||||
@ -108,11 +108,11 @@ impl DefMap {
|
|||||||
// In block expressions, `self` normally refers to the containing non-block module, and
|
// In block expressions, `self` normally refers to the containing non-block module, and
|
||||||
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
|
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
|
||||||
// DefMap they're written in, so we restrict them when that happens.
|
// DefMap they're written in, so we restrict them when that happens.
|
||||||
if let Visibility::Module(m) = vis {
|
if let Visibility::Module(m, mv) = vis {
|
||||||
// ...unless we're resolving visibility for an associated item in an impl.
|
// ...unless we're resolving visibility for an associated item in an impl.
|
||||||
if self.block_id() != m.block && !within_impl {
|
if self.block_id() != m.block && !within_impl {
|
||||||
cov_mark::hit!(adjust_vis_in_block_def_map);
|
cov_mark::hit!(adjust_vis_in_block_def_map);
|
||||||
vis = Visibility::Module(self.module_id(Self::ROOT));
|
vis = Visibility::Module(self.module_id(Self::ROOT), mv);
|
||||||
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
|
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1264,6 +1264,54 @@ struct A;
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_include() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- minicore: include
|
||||||
|
//- /lib.rs
|
||||||
|
include!("out_dir/includes.rs");
|
||||||
|
|
||||||
|
//- /out_dir/includes.rs
|
||||||
|
pub mod company_name {
|
||||||
|
pub mod network {
|
||||||
|
pub mod v1 {
|
||||||
|
include!("company_name.network.v1.rs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//- /out_dir/company_name.network.v1.rs
|
||||||
|
pub struct IpAddress {
|
||||||
|
pub ip_type: &'static str,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `IpAddress`.
|
||||||
|
pub mod ip_address {
|
||||||
|
pub enum IpType {
|
||||||
|
IpV4(u32),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
crate
|
||||||
|
company_name: t
|
||||||
|
|
||||||
|
crate::company_name
|
||||||
|
network: t
|
||||||
|
|
||||||
|
crate::company_name::network
|
||||||
|
v1: t
|
||||||
|
|
||||||
|
crate::company_name::network::v1
|
||||||
|
IpAddress: t
|
||||||
|
ip_address: t
|
||||||
|
|
||||||
|
crate::company_name::network::v1::ip_address
|
||||||
|
IpType: t
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn macro_use_imports_all_macro_types() {
|
fn macro_use_imports_all_macro_types() {
|
||||||
let db = TestDB::with_files(
|
let db = TestDB::with_files(
|
||||||
|
@ -242,7 +242,7 @@ impl Resolver {
|
|||||||
let within_impl =
|
let within_impl =
|
||||||
self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some();
|
self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some();
|
||||||
match visibility {
|
match visibility {
|
||||||
RawVisibility::Module(_) => {
|
RawVisibility::Module(_, _) => {
|
||||||
let (item_map, module) = self.item_scope();
|
let (item_map, module) = self.item_scope();
|
||||||
item_map.resolve_visibility(db, module, visibility, within_impl)
|
item_map.resolve_visibility(db, module, visibility, within_impl)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ use base_db::{
|
|||||||
Upcast,
|
Upcast,
|
||||||
};
|
};
|
||||||
use hir_expand::{db::ExpandDatabase, InFile};
|
use hir_expand::{db::ExpandDatabase, InFile};
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use syntax::{algo, ast, AstNode};
|
use syntax::{algo, ast, AstNode};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
@ -76,7 +75,7 @@ impl FileLoader for TestDB {
|
|||||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,14 @@ use crate::{
|
|||||||
pub enum RawVisibility {
|
pub enum RawVisibility {
|
||||||
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
|
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
|
||||||
/// equivalent to `pub(self)`.
|
/// equivalent to `pub(self)`.
|
||||||
Module(ModPath),
|
Module(ModPath, VisibilityExplicity),
|
||||||
/// `pub`.
|
/// `pub`.
|
||||||
Public,
|
Public,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawVisibility {
|
impl RawVisibility {
|
||||||
pub(crate) const fn private() -> RawVisibility {
|
pub(crate) const fn private() -> RawVisibility {
|
||||||
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
|
RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicity::Implicit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_ast(
|
pub(crate) fn from_ast(
|
||||||
@ -41,18 +41,9 @@ impl RawVisibility {
|
|||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
node: Option<ast::Visibility>,
|
node: Option<ast::Visibility>,
|
||||||
span_map: SpanMapRef<'_>,
|
span_map: SpanMapRef<'_>,
|
||||||
) -> RawVisibility {
|
|
||||||
Self::from_ast_with_span_map_and_default(db, node, RawVisibility::private(), span_map)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_ast_with_span_map_and_default(
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
node: Option<ast::Visibility>,
|
|
||||||
default: RawVisibility,
|
|
||||||
span_map: SpanMapRef<'_>,
|
|
||||||
) -> RawVisibility {
|
) -> RawVisibility {
|
||||||
let node = match node {
|
let node = match node {
|
||||||
None => return default,
|
None => return RawVisibility::private(),
|
||||||
Some(node) => node,
|
Some(node) => node,
|
||||||
};
|
};
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
@ -62,19 +53,19 @@ impl RawVisibility {
|
|||||||
None => return RawVisibility::private(),
|
None => return RawVisibility::private(),
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
};
|
};
|
||||||
RawVisibility::Module(path)
|
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||||
}
|
}
|
||||||
ast::VisibilityKind::PubCrate => {
|
ast::VisibilityKind::PubCrate => {
|
||||||
let path = ModPath::from_kind(PathKind::Crate);
|
let path = ModPath::from_kind(PathKind::Crate);
|
||||||
RawVisibility::Module(path)
|
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||||
}
|
}
|
||||||
ast::VisibilityKind::PubSuper => {
|
ast::VisibilityKind::PubSuper => {
|
||||||
let path = ModPath::from_kind(PathKind::Super(1));
|
let path = ModPath::from_kind(PathKind::Super(1));
|
||||||
RawVisibility::Module(path)
|
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||||
}
|
}
|
||||||
ast::VisibilityKind::PubSelf => {
|
ast::VisibilityKind::PubSelf => {
|
||||||
let path = ModPath::from_kind(PathKind::Super(0));
|
let path = ModPath::from_kind(PathKind::Super(0));
|
||||||
RawVisibility::Module(path)
|
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||||
}
|
}
|
||||||
ast::VisibilityKind::Pub => RawVisibility::Public,
|
ast::VisibilityKind::Pub => RawVisibility::Public,
|
||||||
}
|
}
|
||||||
@ -94,7 +85,7 @@ impl RawVisibility {
|
|||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Visibility {
|
pub enum Visibility {
|
||||||
/// Visibility is restricted to a certain module.
|
/// Visibility is restricted to a certain module.
|
||||||
Module(ModuleId),
|
Module(ModuleId, VisibilityExplicity),
|
||||||
/// Visibility is unrestricted.
|
/// Visibility is unrestricted.
|
||||||
Public,
|
Public,
|
||||||
}
|
}
|
||||||
@ -102,7 +93,7 @@ pub enum Visibility {
|
|||||||
impl Visibility {
|
impl Visibility {
|
||||||
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
|
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
|
||||||
let to_module = match self {
|
let to_module = match self {
|
||||||
Visibility::Module(m) => m,
|
Visibility::Module(m, _) => m,
|
||||||
Visibility::Public => return true,
|
Visibility::Public => return true,
|
||||||
};
|
};
|
||||||
// if they're not in the same crate, it can't be visible
|
// if they're not in the same crate, it can't be visible
|
||||||
@ -124,7 +115,7 @@ impl Visibility {
|
|||||||
mut from_module: LocalModuleId,
|
mut from_module: LocalModuleId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut to_module = match self {
|
let mut to_module = match self {
|
||||||
Visibility::Module(m) => m,
|
Visibility::Module(m, _) => m,
|
||||||
Visibility::Public => return true,
|
Visibility::Public => return true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,9 +172,9 @@ impl Visibility {
|
|||||||
/// visible in unrelated modules).
|
/// visible in unrelated modules).
|
||||||
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
|
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Visibility::Module(_) | Visibility::Public, Visibility::Public)
|
(Visibility::Module(_, _) | Visibility::Public, Visibility::Public)
|
||||||
| (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public),
|
| (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public),
|
||||||
(Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
|
(Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => {
|
||||||
if mod_a.krate != mod_b.krate {
|
if mod_a.krate != mod_b.krate {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -199,12 +190,12 @@ impl Visibility {
|
|||||||
|
|
||||||
if a_ancestors.any(|m| m == mod_b.local_id) {
|
if a_ancestors.any(|m| m == mod_b.local_id) {
|
||||||
// B is above A
|
// B is above A
|
||||||
return Some(Visibility::Module(mod_b));
|
return Some(Visibility::Module(mod_b, vis_b));
|
||||||
}
|
}
|
||||||
|
|
||||||
if b_ancestors.any(|m| m == mod_a.local_id) {
|
if b_ancestors.any(|m| m == mod_a.local_id) {
|
||||||
// A is above B
|
// A is above B
|
||||||
return Some(Visibility::Module(mod_a));
|
return Some(Visibility::Module(mod_a, vis_a));
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -213,6 +204,19 @@ impl Visibility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the item was imported through `pub(crate) use` or just `use`.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum VisibilityExplicity {
|
||||||
|
Explicit,
|
||||||
|
Implicit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisibilityExplicity {
|
||||||
|
pub fn is_explicit(&self) -> bool {
|
||||||
|
matches!(self, Self::Explicit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve visibility of all specific fields of a struct or union variant.
|
/// Resolve visibility of all specific fields of a struct or union variant.
|
||||||
pub(crate) fn field_visibilities_query(
|
pub(crate) fn field_visibilities_query(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! Builtin derives.
|
//! Builtin derives.
|
||||||
|
|
||||||
use base_db::{CrateOrigin, LangCrateOrigin};
|
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use span::{MacroCallId, Span};
|
use span::{MacroCallId, Span};
|
||||||
@ -10,6 +9,7 @@ use tracing::debug;
|
|||||||
use crate::{
|
use crate::{
|
||||||
hygiene::span_with_def_site_ctxt,
|
hygiene::span_with_def_site_ctxt,
|
||||||
name::{AsName, Name},
|
name::{AsName, Name},
|
||||||
|
quote::dollar_crate,
|
||||||
span_map::SpanMapRef,
|
span_map::SpanMapRef,
|
||||||
tt,
|
tt,
|
||||||
};
|
};
|
||||||
@ -38,7 +38,7 @@ macro_rules! register_builtin {
|
|||||||
|
|
||||||
let span = db.lookup_intern_macro_call(id).call_site;
|
let span = db.lookup_intern_macro_call(id).call_site;
|
||||||
let span = span_with_def_site_ctxt(db, span, id);
|
let span = span_with_def_site_ctxt(db, span, id);
|
||||||
expander(db, id, span, tt, token_map)
|
expander(span, tt, token_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_by_name(name: &name::Name) -> Option<Self> {
|
fn find_by_name(name: &name::Name) -> Option<Self> {
|
||||||
@ -398,41 +398,13 @@ fn expand_simple_derive(
|
|||||||
ExpandResult::ok(expanded)
|
ExpandResult::ok(expanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId, span: Span) -> tt::TokenTree {
|
fn copy_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
// FIXME: make hygiene works for builtin derive macro
|
let krate = dollar_crate(span);
|
||||||
// such that $crate can be used here.
|
|
||||||
let cg = db.crate_graph();
|
|
||||||
let krate = db.lookup_intern_macro_call(id).krate;
|
|
||||||
|
|
||||||
let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) {
|
|
||||||
cov_mark::hit!(test_copy_expand_in_core);
|
|
||||||
quote! {span => crate }
|
|
||||||
} else {
|
|
||||||
quote! {span => core }
|
|
||||||
};
|
|
||||||
|
|
||||||
tt.token_trees[0].clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy_expand(
|
|
||||||
db: &dyn ExpandDatabase,
|
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_expand(
|
fn clone_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| {
|
||||||
if matches!(adt.shape, AdtShape::Union) {
|
if matches!(adt.shape, AdtShape::Union) {
|
||||||
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
|
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
|
||||||
@ -482,14 +454,8 @@ fn and_and(span: Span) -> tt::Subtree {
|
|||||||
quote! {span => #and& }
|
quote! {span => #and& }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_expand(
|
fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = &dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = &find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| {
|
||||||
let body = match &adt.shape {
|
let body = match &adt.shape {
|
||||||
AdtShape::Struct(fields) => {
|
AdtShape::Struct(fields) => {
|
||||||
@ -527,14 +493,8 @@ fn default_expand(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_expand(
|
fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = &dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = &find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| {
|
||||||
let for_variant = |name: String, v: &VariantShape| match v {
|
let for_variant = |name: String, v: &VariantShape| match v {
|
||||||
VariantShape::Struct(fields) => {
|
VariantShape::Struct(fields) => {
|
||||||
@ -605,14 +565,8 @@ fn debug_expand(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_expand(
|
fn hash_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = &dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = &find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| {
|
||||||
if matches!(adt.shape, AdtShape::Union) {
|
if matches!(adt.shape, AdtShape::Union) {
|
||||||
// FIXME: Return expand error here
|
// FIXME: Return expand error here
|
||||||
@ -658,25 +612,13 @@ fn hash_expand(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_expand(
|
fn eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_eq_expand(
|
fn partial_eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| {
|
||||||
if matches!(adt.shape, AdtShape::Union) {
|
if matches!(adt.shape, AdtShape::Union) {
|
||||||
// FIXME: Return expand error here
|
// FIXME: Return expand error here
|
||||||
@ -747,17 +689,11 @@ fn self_and_other_patterns(
|
|||||||
(self_patterns, other_patterns)
|
(self_patterns, other_patterns)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ord_expand(
|
fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = &dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = &find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| {
|
||||||
fn compare(
|
fn compare(
|
||||||
krate: &tt::TokenTree,
|
krate: &tt::Ident,
|
||||||
left: tt::Subtree,
|
left: tt::Subtree,
|
||||||
right: tt::Subtree,
|
right: tt::Subtree,
|
||||||
rest: tt::Subtree,
|
rest: tt::Subtree,
|
||||||
@ -811,17 +747,11 @@ fn ord_expand(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_ord_expand(
|
fn partial_ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||||
db: &dyn ExpandDatabase,
|
let krate = &dollar_crate(span);
|
||||||
id: MacroCallId,
|
|
||||||
span: Span,
|
|
||||||
tt: &ast::Adt,
|
|
||||||
tm: SpanMapRef<'_>,
|
|
||||||
) -> ExpandResult<tt::Subtree> {
|
|
||||||
let krate = &find_builtin_crate(db, id, span);
|
|
||||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| {
|
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| {
|
||||||
fn compare(
|
fn compare(
|
||||||
krate: &tt::TokenTree,
|
krate: &tt::Ident,
|
||||||
left: tt::Subtree,
|
left: tt::Subtree,
|
||||||
right: tt::Subtree,
|
right: tt::Subtree,
|
||||||
rest: tt::Subtree,
|
rest: tt::Subtree,
|
||||||
|
@ -6,18 +6,16 @@ use either::Either;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
|
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
|
||||||
use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
|
use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
|
||||||
use syntax::{
|
use syntax::ast::{self, AstToken};
|
||||||
ast::{self, AstToken},
|
|
||||||
SmolStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::ExpandDatabase,
|
db::ExpandDatabase,
|
||||||
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
|
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
|
||||||
name::{self, known},
|
name::{self, known},
|
||||||
quote,
|
quote,
|
||||||
|
quote::dollar_crate,
|
||||||
tt::{self, DelimSpan},
|
tt::{self, DelimSpan},
|
||||||
ExpandError, ExpandResult, HirFileIdExt, MacroCallId,
|
ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! register_builtin {
|
macro_rules! register_builtin {
|
||||||
@ -205,7 +203,7 @@ fn assert_expand(
|
|||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
||||||
let args = parse_exprs_with_sep(tt, ',', call_site_span);
|
let args = parse_exprs_with_sep(tt, ',', call_site_span);
|
||||||
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
|
let dollar_crate = dollar_crate(span);
|
||||||
let expanded = match &*args {
|
let expanded = match &*args {
|
||||||
[cond, panic_args @ ..] => {
|
[cond, panic_args @ ..] => {
|
||||||
let comma = tt::Subtree {
|
let comma = tt::Subtree {
|
||||||
@ -300,7 +298,7 @@ fn asm_expand(
|
|||||||
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
|
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
|
||||||
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
|
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
|
||||||
{
|
{
|
||||||
let dollar_krate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
|
let dollar_krate = dollar_crate(span);
|
||||||
literals.push(quote!(span=>#dollar_krate::format_args!(#lit);));
|
literals.push(quote!(span=>#dollar_krate::format_args!(#lit);));
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
@ -345,7 +343,7 @@ fn panic_expand(
|
|||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
|
let dollar_crate = dollar_crate(span);
|
||||||
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
||||||
|
|
||||||
let mac =
|
let mac =
|
||||||
@ -371,7 +369,7 @@ fn unreachable_expand(
|
|||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
|
let dollar_crate = dollar_crate(span);
|
||||||
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
||||||
|
|
||||||
let mac = if use_panic_2021(db, call_site_span) {
|
let mac = if use_panic_2021(db, call_site_span) {
|
||||||
@ -611,7 +609,7 @@ fn relative_file(
|
|||||||
path_str: &str,
|
path_str: &str,
|
||||||
allow_recursion: bool,
|
allow_recursion: bool,
|
||||||
) -> Result<FileId, ExpandError> {
|
) -> Result<FileId, ExpandError> {
|
||||||
let call_site = call_id.as_file().original_file(db);
|
let call_site = call_id.as_macro_file().parent(db).original_file_respecting_includes(db);
|
||||||
let path = AnchoredPath { anchor: call_site, path: path_str };
|
let path = AnchoredPath { anchor: call_site, path: path_str };
|
||||||
let res = db
|
let res = db
|
||||||
.resolve_path(path)
|
.resolve_path(path)
|
||||||
@ -763,10 +761,10 @@ fn option_env_expand(
|
|||||||
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
|
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// FIXME: Use `DOLLAR_CRATE` when that works in eager macros.
|
let dollar_crate = dollar_crate(span);
|
||||||
let expanded = match get_env_inner(db, arg_id, &key) {
|
let expanded = match get_env_inner(db, arg_id, &key) {
|
||||||
None => quote! {span => ::core::option::Option::None::<&str> },
|
None => quote! {span => #dollar_crate::option::Option::None::<&str> },
|
||||||
Some(s) => quote! {span => ::core::option::Option::Some(#s) },
|
Some(s) => quote! {span => #dollar_crate::option::Option::Some(#s) },
|
||||||
};
|
};
|
||||||
|
|
||||||
ExpandResult::ok(expanded)
|
ExpandResult::ok(expanded)
|
||||||
|
@ -318,6 +318,7 @@ pub trait MacroFileIdExt {
|
|||||||
fn expansion_level(self, db: &dyn ExpandDatabase) -> u32;
|
fn expansion_level(self, db: &dyn ExpandDatabase) -> u32;
|
||||||
/// If this is a macro call, returns the syntax node of the call.
|
/// If this is a macro call, returns the syntax node of the call.
|
||||||
fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode>;
|
fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode>;
|
||||||
|
fn parent(self, db: &dyn ExpandDatabase) -> HirFileId;
|
||||||
|
|
||||||
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo;
|
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo;
|
||||||
|
|
||||||
@ -353,6 +354,9 @@ impl MacroFileIdExt for MacroFileId {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn parent(self, db: &dyn ExpandDatabase) -> HirFileId {
|
||||||
|
self.macro_call_id.lookup(db).kind.file_id()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return expansion information if it is a macro-expansion file
|
/// Return expansion information if it is a macro-expansion file
|
||||||
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo {
|
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo {
|
||||||
|
@ -4,6 +4,10 @@ use span::Span;
|
|||||||
|
|
||||||
use crate::name::Name;
|
use crate::name::Name;
|
||||||
|
|
||||||
|
pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> {
|
||||||
|
tt::Ident { text: syntax::SmolStr::new_inline("$crate"), span }
|
||||||
|
}
|
||||||
|
|
||||||
// A helper macro quote macro
|
// A helper macro quote macro
|
||||||
// FIXME:
|
// FIXME:
|
||||||
// 1. Not all puncts are handled
|
// 1. Not all puncts are handled
|
||||||
|
@ -34,7 +34,9 @@ nohash-hasher.workspace = true
|
|||||||
typed-arena = "2.0.1"
|
typed-arena = "2.0.1"
|
||||||
indexmap.workspace = true
|
indexmap.workspace = true
|
||||||
|
|
||||||
rustc-dependencies.workspace = true
|
ra-ap-rustc_abi.workspace = true
|
||||||
|
ra-ap-rustc_index.workspace = true
|
||||||
|
|
||||||
|
|
||||||
# local deps
|
# local deps
|
||||||
stdx.workspace = true
|
stdx.workspace = true
|
||||||
@ -58,7 +60,7 @@ test-utils.workspace = true
|
|||||||
test-fixture.workspace = true
|
test-fixture.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
in-rust-tree = []
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -167,7 +167,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.map(|block_id| self.db.trait_impls_in_block(block_id));
|
.filter_map(|block_id| self.db.trait_impls_in_block(block_id));
|
||||||
|
|
||||||
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
|
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
@ -183,7 +183,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||||||
def_blocks
|
def_blocks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.for_each(|it| f(&self.db.trait_impls_in_block(it)));
|
.filter_map(|it| self.db.trait_impls_in_block(it))
|
||||||
|
.for_each(|it| f(&it));
|
||||||
}
|
}
|
||||||
fps => {
|
fps => {
|
||||||
let mut f =
|
let mut f =
|
||||||
@ -198,7 +199,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||||||
def_blocks
|
def_blocks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.for_each(|it| f(&self.db.trait_impls_in_block(it)));
|
.filter_map(|it| self.db.trait_impls_in_block(it))
|
||||||
|
.for_each(|it| f(&it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||||||
#[salsa::invoke(crate::infer::infer_query)]
|
#[salsa::invoke(crate::infer::infer_query)]
|
||||||
fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
|
fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
|
||||||
|
|
||||||
|
// region:mir
|
||||||
|
|
||||||
#[salsa::invoke(crate::mir::mir_body_query)]
|
#[salsa::invoke(crate::mir::mir_body_query)]
|
||||||
#[salsa::cycle(crate::mir::mir_body_recover)]
|
#[salsa::cycle(crate::mir::mir_body_recover)]
|
||||||
fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;
|
fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;
|
||||||
@ -61,20 +63,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||||||
#[salsa::invoke(crate::mir::borrowck_query)]
|
#[salsa::invoke(crate::mir::borrowck_query)]
|
||||||
fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>;
|
fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::ty_query)]
|
|
||||||
#[salsa::cycle(crate::lower::ty_recover)]
|
|
||||||
fn ty(&self, def: TyDefId) -> Binders<Ty>;
|
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::value_ty_query)]
|
|
||||||
fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
|
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::impl_self_ty_query)]
|
|
||||||
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
|
|
||||||
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
|
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
|
||||||
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
|
||||||
|
|
||||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||||
fn const_eval(
|
fn const_eval(
|
||||||
@ -92,6 +80,22 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||||||
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
|
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
|
||||||
fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
|
fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
|
||||||
|
|
||||||
|
// endregion:mir
|
||||||
|
|
||||||
|
#[salsa::invoke(crate::lower::ty_query)]
|
||||||
|
#[salsa::cycle(crate::lower::ty_recover)]
|
||||||
|
fn ty(&self, def: TyDefId) -> Binders<Ty>;
|
||||||
|
|
||||||
|
#[salsa::invoke(crate::lower::value_ty_query)]
|
||||||
|
fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
|
||||||
|
|
||||||
|
#[salsa::invoke(crate::lower::impl_self_ty_query)]
|
||||||
|
#[salsa::cycle(crate::lower::impl_self_ty_recover)]
|
||||||
|
fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
|
||||||
|
|
||||||
|
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
||||||
|
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::impl_trait_query)]
|
#[salsa::invoke(crate::lower::impl_trait_query)]
|
||||||
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
||||||
|
|
||||||
@ -158,7 +162,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||||||
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
|
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
|
||||||
|
|
||||||
#[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
|
#[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
|
||||||
fn inherent_impls_in_block(&self, block: BlockId) -> Arc<InherentImpls>;
|
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
|
||||||
|
|
||||||
/// Collects all crates in the dependency graph that have impls for the
|
/// Collects all crates in the dependency graph that have impls for the
|
||||||
/// given fingerprint. This is only used for primitive types and types
|
/// given fingerprint. This is only used for primitive types and types
|
||||||
@ -175,7 +179,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||||||
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
|
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
|
||||||
|
|
||||||
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
|
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
|
||||||
fn trait_impls_in_block(&self, block: BlockId) -> Arc<TraitImpls>;
|
fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
|
||||||
|
|
||||||
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
|
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
|
||||||
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;
|
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;
|
||||||
|
@ -1629,7 +1629,7 @@ pub fn write_visibility(
|
|||||||
) -> Result<(), HirDisplayError> {
|
) -> Result<(), HirDisplayError> {
|
||||||
match vis {
|
match vis {
|
||||||
Visibility::Public => write!(f, "pub "),
|
Visibility::Public => write!(f, "pub "),
|
||||||
Visibility::Module(vis_id) => {
|
Visibility::Module(vis_id, _) => {
|
||||||
let def_map = module_id.def_map(f.db.upcast());
|
let def_map = module_id.def_map(f.db.upcast());
|
||||||
let root_module_id = def_map.module_id(DefMap::ROOT);
|
let root_module_id = def_map.module_id(DefMap::ROOT);
|
||||||
if vis_id == module_id {
|
if vis_id == module_id {
|
||||||
|
@ -12,10 +12,9 @@ use hir_def::{
|
|||||||
LocalEnumVariantId, LocalFieldId, StructId,
|
LocalEnumVariantId, LocalFieldId, StructId,
|
||||||
};
|
};
|
||||||
use la_arena::{Idx, RawIdx};
|
use la_arena::{Idx, RawIdx};
|
||||||
use rustc_dependencies::{
|
use rustc_abi::AddressSpace;
|
||||||
abi::AddressSpace,
|
use rustc_index::{IndexSlice, IndexVec};
|
||||||
index::{IndexSlice, IndexVec},
|
|
||||||
};
|
|
||||||
use stdx::never;
|
use stdx::never;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ mod target;
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
|
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
|
||||||
|
|
||||||
impl rustc_dependencies::index::Idx for RustcEnumVariantIdx {
|
impl rustc_index::Idx for RustcEnumVariantIdx {
|
||||||
fn new(idx: usize) -> Self {
|
fn new(idx: usize) -> Self {
|
||||||
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||||
}
|
}
|
||||||
@ -54,7 +53,7 @@ impl RustcFieldIdx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl rustc_dependencies::index::Idx for RustcFieldIdx {
|
impl rustc_index::Idx for RustcFieldIdx {
|
||||||
fn new(idx: usize) -> Self {
|
fn new(idx: usize) -> Self {
|
||||||
RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use hir_def::{
|
|||||||
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
|
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
|
||||||
};
|
};
|
||||||
use la_arena::RawIdx;
|
use la_arena::RawIdx;
|
||||||
use rustc_dependencies::index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ fn check_fail(ra_fixture: &str, e: LayoutError) {
|
|||||||
macro_rules! size_and_align {
|
macro_rules! size_and_align {
|
||||||
(minicore: $($x:tt),*;$($t:tt)*) => {
|
(minicore: $($x:tt),*;$($t:tt)*) => {
|
||||||
{
|
{
|
||||||
#[allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
$($t)*
|
$($t)*
|
||||||
check_size_and_align(
|
check_size_and_align(
|
||||||
stringify!($($t)*),
|
stringify!($($t)*),
|
||||||
@ -130,7 +130,7 @@ macro_rules! size_and_align {
|
|||||||
};
|
};
|
||||||
($($t:tt)*) => {
|
($($t:tt)*) => {
|
||||||
{
|
{
|
||||||
#[allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
$($t)*
|
$($t)*
|
||||||
check_size_and_align(
|
check_size_and_align(
|
||||||
stringify!($($t)*),
|
stringify!($($t)*),
|
||||||
|
@ -3,10 +3,17 @@
|
|||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||||
|
|
||||||
#[allow(unused)]
|
#[cfg(feature = "in-rust-tree")]
|
||||||
macro_rules! eprintln {
|
extern crate rustc_index;
|
||||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
|
||||||
}
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
|
extern crate ra_ap_rustc_index as rustc_index;
|
||||||
|
|
||||||
|
#[cfg(feature = "in-rust-tree")]
|
||||||
|
extern crate rustc_abi;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
|
extern crate ra_ap_rustc_abi as rustc_abi;
|
||||||
|
|
||||||
mod builder;
|
mod builder;
|
||||||
mod chalk_db;
|
mod chalk_db;
|
||||||
|
@ -1601,7 +1601,7 @@ fn implicitly_sized_clauses<'a>(
|
|||||||
pub(crate) fn generic_defaults_query(
|
pub(crate) fn generic_defaults_query(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
def: GenericDefId,
|
def: GenericDefId,
|
||||||
) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
|
) -> Arc<[Binders<crate::GenericArg>]> {
|
||||||
let resolver = def.resolver(db.upcast());
|
let resolver = def.resolver(db.upcast());
|
||||||
let ctx = TyLoweringContext::new(db, &resolver, def.into())
|
let ctx = TyLoweringContext::new(db, &resolver, def.into())
|
||||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||||
|
@ -8,10 +8,9 @@ use base_db::{CrateId, Edition};
|
|||||||
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
|
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
data::{adt::StructFlags, ImplData},
|
data::{adt::StructFlags, ImplData},
|
||||||
item_scope::ItemScope,
|
|
||||||
nameres::DefMap,
|
nameres::DefMap,
|
||||||
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
||||||
ModuleDefId, ModuleId, TraitId,
|
ModuleId, TraitId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
@ -132,34 +131,40 @@ pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
|
|||||||
TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
|
TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>;
|
||||||
|
type TraitFpMapCollector = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>;
|
||||||
|
|
||||||
/// Trait impls defined or available in some crate.
|
/// Trait impls defined or available in some crate.
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct TraitImpls {
|
pub struct TraitImpls {
|
||||||
// If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
|
// If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
|
||||||
map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
|
map: TraitFpMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TraitImpls {
|
impl TraitImpls {
|
||||||
pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
|
pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
|
||||||
let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
|
let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
|
||||||
let mut impls = Self { map: FxHashMap::default() };
|
let mut impls = FxHashMap::default();
|
||||||
|
|
||||||
let crate_def_map = db.crate_def_map(krate);
|
Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
|
||||||
impls.collect_def_map(db, &crate_def_map);
|
|
||||||
impls.shrink_to_fit();
|
|
||||||
|
|
||||||
Arc::new(impls)
|
Arc::new(Self::finish(impls))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn trait_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc<Self> {
|
pub(crate) fn trait_impls_in_block_query(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
block: BlockId,
|
||||||
|
) -> Option<Arc<Self>> {
|
||||||
let _p = profile::span("trait_impls_in_block_query");
|
let _p = profile::span("trait_impls_in_block_query");
|
||||||
let mut impls = Self { map: FxHashMap::default() };
|
let mut impls = FxHashMap::default();
|
||||||
|
|
||||||
let block_def_map = db.block_def_map(block);
|
Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
|
||||||
impls.collect_def_map(db, &block_def_map);
|
|
||||||
impls.shrink_to_fit();
|
|
||||||
|
|
||||||
Arc::new(impls)
|
if impls.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Arc::new(Self::finish(impls)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn trait_impls_in_deps_query(
|
pub(crate) fn trait_impls_in_deps_query(
|
||||||
@ -174,15 +179,16 @@ impl TraitImpls {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shrink_to_fit(&mut self) {
|
fn finish(map: TraitFpMapCollector) -> TraitImpls {
|
||||||
self.map.shrink_to_fit();
|
TraitImpls {
|
||||||
self.map.values_mut().for_each(|map| {
|
map: map
|
||||||
map.shrink_to_fit();
|
.into_iter()
|
||||||
map.values_mut().for_each(Vec::shrink_to_fit);
|
.map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into_boxed_slice())).collect()))
|
||||||
});
|
.collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
|
fn collect_def_map(db: &dyn HirDatabase, map: &mut TraitFpMapCollector, def_map: &DefMap) {
|
||||||
for (_module_id, module_data) in def_map.modules() {
|
for (_module_id, module_data) in def_map.modules() {
|
||||||
for impl_id in module_data.scope.impls() {
|
for impl_id in module_data.scope.impls() {
|
||||||
// Reservation impls should be ignored during trait resolution, so we never need
|
// Reservation impls should be ignored during trait resolution, so we never need
|
||||||
@ -200,20 +206,15 @@ impl TraitImpls {
|
|||||||
};
|
};
|
||||||
let self_ty = db.impl_self_ty(impl_id);
|
let self_ty = db.impl_self_ty(impl_id);
|
||||||
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
|
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
|
||||||
self.map
|
map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id);
|
||||||
.entry(target_trait)
|
|
||||||
.or_default()
|
|
||||||
.entry(self_ty_fp)
|
|
||||||
.or_default()
|
|
||||||
.push(impl_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// To better support custom derives, collect impls in all unnamed const items.
|
// To better support custom derives, collect impls in all unnamed const items.
|
||||||
// const _: () = { ... };
|
// const _: () = { ... };
|
||||||
for konst in collect_unnamed_consts(db, &module_data.scope) {
|
for konst in module_data.scope.unnamed_consts(db.upcast()) {
|
||||||
let body = db.body(konst.into());
|
let body = db.body(konst.into());
|
||||||
for (_, block_def_map) in body.blocks(db.upcast()) {
|
for (_, block_def_map) in body.blocks(db.upcast()) {
|
||||||
self.collect_def_map(db, &block_def_map);
|
Self::collect_def_map(db, map, &block_def_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +282,10 @@ impl InherentImpls {
|
|||||||
Arc::new(impls)
|
Arc::new(impls)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn inherent_impls_in_block_query(db: &dyn HirDatabase, block: BlockId) -> Arc<Self> {
|
pub(crate) fn inherent_impls_in_block_query(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
block: BlockId,
|
||||||
|
) -> Option<Arc<Self>> {
|
||||||
let _p = profile::span("inherent_impls_in_block_query");
|
let _p = profile::span("inherent_impls_in_block_query");
|
||||||
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
||||||
|
|
||||||
@ -289,7 +293,11 @@ impl InherentImpls {
|
|||||||
impls.collect_def_map(db, &block_def_map);
|
impls.collect_def_map(db, &block_def_map);
|
||||||
impls.shrink_to_fit();
|
impls.shrink_to_fit();
|
||||||
|
|
||||||
Arc::new(impls)
|
if impls.map.is_empty() && impls.invalid_impls.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Arc::new(impls))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shrink_to_fit(&mut self) {
|
fn shrink_to_fit(&mut self) {
|
||||||
@ -321,7 +329,7 @@ impl InherentImpls {
|
|||||||
|
|
||||||
// To better support custom derives, collect impls in all unnamed const items.
|
// To better support custom derives, collect impls in all unnamed const items.
|
||||||
// const _: () = { ... };
|
// const _: () = { ... };
|
||||||
for konst in collect_unnamed_consts(db, &module_data.scope) {
|
for konst in module_data.scope.unnamed_consts(db.upcast()) {
|
||||||
let body = db.body(konst.into());
|
let body = db.body(konst.into());
|
||||||
for (_, block_def_map) in body.blocks(db.upcast()) {
|
for (_, block_def_map) in body.blocks(db.upcast()) {
|
||||||
self.collect_def_map(db, &block_def_map);
|
self.collect_def_map(db, &block_def_map);
|
||||||
@ -367,34 +375,6 @@ pub(crate) fn incoherent_inherent_impl_crates(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_unnamed_consts<'a>(
|
|
||||||
db: &'a dyn HirDatabase,
|
|
||||||
scope: &'a ItemScope,
|
|
||||||
) -> impl Iterator<Item = ConstId> + 'a {
|
|
||||||
let unnamed_consts = scope.unnamed_consts();
|
|
||||||
|
|
||||||
// FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
|
|
||||||
// Should be removed once synstructure stops doing that.
|
|
||||||
let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
|
|
||||||
ModuleDefId::ConstId(id) => {
|
|
||||||
let loc = id.lookup(db.upcast());
|
|
||||||
let item_tree = loc.id.item_tree(db.upcast());
|
|
||||||
if item_tree[loc.id.value]
|
|
||||||
.name
|
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
|
|
||||||
{
|
|
||||||
Some(id)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
unnamed_consts.chain(synstructure_hack_consts)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn def_crates(
|
pub fn def_crates(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
ty: &Ty,
|
ty: &Ty,
|
||||||
@ -737,7 +717,7 @@ fn lookup_impl_assoc_item_for_trait_ref(
|
|||||||
let impls = db.trait_impls_in_deps(env.krate);
|
let impls = db.trait_impls_in_deps(env.krate);
|
||||||
let self_impls = match self_ty.kind(Interner) {
|
let self_impls = match self_ty.kind(Interner) {
|
||||||
TyKind::Adt(id, _) => {
|
TyKind::Adt(id, _) => {
|
||||||
id.0.module(db.upcast()).containing_block().map(|it| db.trait_impls_in_block(it))
|
id.0.module(db.upcast()).containing_block().and_then(|it| db.trait_impls_in_block(it))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -1254,17 +1234,18 @@ fn iterate_inherent_methods(
|
|||||||
};
|
};
|
||||||
|
|
||||||
while let Some(block_id) = block {
|
while let Some(block_id) = block {
|
||||||
let impls = db.inherent_impls_in_block(block_id);
|
if let Some(impls) = db.inherent_impls_in_block(block_id) {
|
||||||
impls_for_self_ty(
|
impls_for_self_ty(
|
||||||
&impls,
|
&impls,
|
||||||
self_ty,
|
self_ty,
|
||||||
table,
|
table,
|
||||||
name,
|
name,
|
||||||
receiver_ty,
|
receiver_ty,
|
||||||
receiver_adjustments.clone(),
|
receiver_adjustments.clone(),
|
||||||
module,
|
module,
|
||||||
callback,
|
callback,
|
||||||
)?;
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
|
block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use base_db::{
|
|||||||
use hir_def::{db::DefDatabase, ModuleId};
|
use hir_def::{db::DefDatabase, ModuleId};
|
||||||
use hir_expand::db::ExpandDatabase;
|
use hir_expand::db::ExpandDatabase;
|
||||||
use nohash_hasher::IntMap;
|
use nohash_hasher::IntMap;
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use syntax::TextRange;
|
use syntax::TextRange;
|
||||||
use test_utils::extract_annotations;
|
use test_utils::extract_annotations;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
@ -81,7 +80,7 @@ impl FileLoader for TestDB {
|
|||||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -987,15 +987,12 @@ fn infer_builtin_macros_env() {
|
|||||||
fn infer_builtin_macros_option_env() {
|
fn infer_builtin_macros_option_env() {
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: option
|
//- minicore: env
|
||||||
//- /main.rs env:foo=bar
|
//- /main.rs env:foo=bar
|
||||||
#[rustc_builtin_macro]
|
fn main() {
|
||||||
macro_rules! option_env {() => {}}
|
let x = option_env!("foo");
|
||||||
|
//^ Option<&str>
|
||||||
fn main() {
|
}
|
||||||
let x = option_env!("foo");
|
|
||||||
//^ Option<&str>
|
|
||||||
}
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1014,6 +1011,21 @@ fn test() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_builtin_derive_resolves_with_core_module() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
//- minicore: derive, clone
|
||||||
|
mod core {}
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct S;
|
||||||
|
fn test() {
|
||||||
|
S.clone();
|
||||||
|
} //^^^^^^^^^ S
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_derive_clone_with_params() {
|
fn infer_derive_clone_with_params() {
|
||||||
check_types(
|
check_types(
|
||||||
|
@ -35,7 +35,7 @@ macro_rules! impl_has_attrs {
|
|||||||
impl HasAttrs for $def {
|
impl HasAttrs for $def {
|
||||||
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
|
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
|
||||||
let def = AttrDefId::$def_id(self.into());
|
let def = AttrDefId::$def_id(self.into());
|
||||||
db.attrs_with_owner(def)
|
AttrsWithOwner::attrs_with_owner(db.upcast(), def)
|
||||||
}
|
}
|
||||||
fn attr_id(self) -> AttrDefId {
|
fn attr_id(self) -> AttrDefId {
|
||||||
AttrDefId::$def_id(self.into())
|
AttrDefId::$def_id(self.into())
|
||||||
|
@ -15,8 +15,8 @@ pub use hir_def::db::{
|
|||||||
InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery,
|
InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery,
|
||||||
InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery,
|
InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery,
|
||||||
InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery,
|
InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery,
|
||||||
InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangAttrQuery, LangItemQuery,
|
InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery,
|
||||||
Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
|
MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
|
||||||
StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery,
|
StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery,
|
||||||
TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery,
|
TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery,
|
||||||
UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery,
|
UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery,
|
||||||
|
@ -754,7 +754,7 @@ impl Module {
|
|||||||
scope
|
scope
|
||||||
.declarations()
|
.declarations()
|
||||||
.map(ModuleDef::from)
|
.map(ModuleDef::from)
|
||||||
.chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id))))
|
.chain(scope.unnamed_consts(db.upcast()).map(|id| ModuleDef::Const(Const::from(id))))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> {
|
|||||||
// Record renamed imports.
|
// Record renamed imports.
|
||||||
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
|
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
|
||||||
// for now.
|
// for now.
|
||||||
|
// FIXME: This parses!
|
||||||
for id in scope.imports() {
|
for id in scope.imports() {
|
||||||
let source = id.import.child_source(self.db.upcast());
|
let source = id.import.child_source(self.db.upcast());
|
||||||
let Some(use_tree_src) = source.value.get(id.idx) else { continue };
|
let Some(use_tree_src) = source.value.get(id.idx) else { continue };
|
||||||
@ -195,7 +196,7 @@ impl<'a> SymbolCollector<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for const_id in scope.unnamed_consts() {
|
for const_id in scope.unnamed_consts(self.db.upcast()) {
|
||||||
self.collect_from_body(const_id);
|
self.collect_from_body(const_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,4 +1551,39 @@ use foo::Foo$0;
|
|||||||
",
|
",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn considers_pub_crate() {
|
||||||
|
check_assist(
|
||||||
|
auto_import,
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use self::foo::*;
|
||||||
|
|
||||||
|
mod bar {
|
||||||
|
fn main() {
|
||||||
|
Foo$0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub struct Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use self::foo::*;
|
||||||
|
|
||||||
|
mod bar {
|
||||||
|
use crate::Foo;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Foo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ use syntax::{
|
|||||||
edit::{AstNodeEdit, IndentLevel},
|
edit::{AstNodeEdit, IndentLevel},
|
||||||
AstNode, HasGenericParams,
|
AstNode, HasGenericParams,
|
||||||
},
|
},
|
||||||
match_ast, ted, SyntaxElement,
|
match_ast, ted, AstToken, SyntaxElement,
|
||||||
SyntaxKind::{self, COMMENT},
|
SyntaxKind::{self, COMMENT},
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
|
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
|
||||||
};
|
};
|
||||||
@ -1733,8 +1733,23 @@ fn make_body(
|
|||||||
ast::Expr::BlockExpr(block) => {
|
ast::Expr::BlockExpr(block) => {
|
||||||
// If the extracted expression is itself a block, there is no need to wrap it inside another block.
|
// If the extracted expression is itself a block, there is no need to wrap it inside another block.
|
||||||
let block = block.dedent(old_indent);
|
let block = block.dedent(old_indent);
|
||||||
// Recreate the block for formatting consistency with other extracted functions.
|
let elements = block.stmt_list().map_or_else(
|
||||||
make::block_expr(block.statements(), block.tail_expr())
|
|| Either::Left(iter::empty()),
|
||||||
|
|stmt_list| {
|
||||||
|
let elements = stmt_list.syntax().children_with_tokens().filter_map(
|
||||||
|
|node_or_token| match &node_or_token {
|
||||||
|
syntax::NodeOrToken::Node(node) => {
|
||||||
|
ast::Stmt::cast(node.clone()).map(|_| node_or_token)
|
||||||
|
}
|
||||||
|
syntax::NodeOrToken::Token(token) => {
|
||||||
|
ast::Comment::cast(token.clone()).map(|_| node_or_token)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Either::Right(elements)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
make::hacky_block_expr(elements, block.tail_expr())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let expr = expr.dedent(old_indent).indent(IndentLevel(1));
|
let expr = expr.dedent(old_indent).indent(IndentLevel(1));
|
||||||
@ -5961,6 +5976,37 @@ fn $0fun_name() -> ControlFlow<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn comments_in_block_expr() {
|
||||||
|
check_assist(
|
||||||
|
extract_function,
|
||||||
|
r#"
|
||||||
|
fn f() {
|
||||||
|
let c = $0{
|
||||||
|
// comment 1
|
||||||
|
let a = 2 + 3;
|
||||||
|
// comment 2
|
||||||
|
let b = 5;
|
||||||
|
a + b
|
||||||
|
}$0;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn f() {
|
||||||
|
let c = fun_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn $0fun_name() -> i32 {
|
||||||
|
// comment 1
|
||||||
|
let a = 2 + 3;
|
||||||
|
// comment 2
|
||||||
|
let b = 5;
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn in_left_curly_is_not_applicable() {
|
fn in_left_curly_is_not_applicable() {
|
||||||
cov_mark::check!(extract_function_in_braces_is_not_applicable);
|
cov_mark::check!(extract_function_in_braces_is_not_applicable);
|
||||||
|
@ -50,6 +50,10 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
|||||||
ty.original().display_source_code(ctx.db(), constant_module.into(), false).ok()?;
|
ty.original().display_source_code(ctx.db(), constant_module.into(), false).ok()?;
|
||||||
let target = statement.syntax().parent()?.text_range();
|
let target = statement.syntax().parent()?.text_range();
|
||||||
let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?;
|
let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?;
|
||||||
|
if path.parent_path().is_some() {
|
||||||
|
cov_mark::hit!(not_last_path_segment);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let name_refs = path.segments().map(|s| s.name_ref());
|
let name_refs = path.segments().map(|s| s.name_ref());
|
||||||
let mut outer_exists = false;
|
let mut outer_exists = false;
|
||||||
@ -250,6 +254,18 @@ fn bar() -> i32 {
|
|||||||
}
|
}
|
||||||
fn bar() -> i32 {
|
fn bar() -> i32 {
|
||||||
foo::goo::A_CONSTANT
|
foo::goo::A_CONSTANT
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wont_apply_when_not_last_path_segment() {
|
||||||
|
cov_mark::check!(not_last_path_segment);
|
||||||
|
check_assist_not_applicable(
|
||||||
|
generate_constant,
|
||||||
|
r#"mod foo {}
|
||||||
|
fn bar() -> i32 {
|
||||||
|
foo::A_CON$0STANT::invalid_segment
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -107,31 +107,48 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|
|||||||
|edit| {
|
|edit| {
|
||||||
// Create the function
|
// Create the function
|
||||||
let method_source = match ctx.sema.source(method) {
|
let method_source = match ctx.sema.source(method) {
|
||||||
Some(source) => source.value,
|
Some(source) => {
|
||||||
|
let v = source.value.clone_for_update();
|
||||||
|
let source_scope = ctx.sema.scope(v.syntax());
|
||||||
|
let target_scope = ctx.sema.scope(strukt.syntax());
|
||||||
|
if let (Some(s), Some(t)) = (source_scope, target_scope) {
|
||||||
|
PathTransform::generic_transformation(&t, &s).apply(v.syntax());
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vis = method_source.visibility();
|
let vis = method_source.visibility();
|
||||||
let fn_name = make::name(&name);
|
|
||||||
let params =
|
|
||||||
method_source.param_list().unwrap_or_else(|| make::param_list(None, []));
|
|
||||||
let type_params = method_source.generic_param_list();
|
|
||||||
let arg_list = match method_source.param_list() {
|
|
||||||
Some(list) => convert_param_list_to_arg_list(list),
|
|
||||||
None => make::arg_list([]),
|
|
||||||
};
|
|
||||||
let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list);
|
|
||||||
let ret_type = method_source.ret_type();
|
|
||||||
let is_async = method_source.async_token().is_some();
|
let is_async = method_source.async_token().is_some();
|
||||||
let is_const = method_source.const_token().is_some();
|
let is_const = method_source.const_token().is_some();
|
||||||
let is_unsafe = method_source.unsafe_token().is_some();
|
let is_unsafe = method_source.unsafe_token().is_some();
|
||||||
|
|
||||||
|
let fn_name = make::name(&name);
|
||||||
|
|
||||||
|
let type_params = method_source.generic_param_list();
|
||||||
|
let where_clause = method_source.where_clause();
|
||||||
|
let params =
|
||||||
|
method_source.param_list().unwrap_or_else(|| make::param_list(None, []));
|
||||||
|
|
||||||
|
// compute the `body`
|
||||||
|
let arg_list = method_source
|
||||||
|
.param_list()
|
||||||
|
.map(|list| convert_param_list_to_arg_list(list))
|
||||||
|
.unwrap_or_else(|| make::arg_list([]));
|
||||||
|
|
||||||
|
let tail_expr = make::expr_method_call(field, make::name_ref(&name), arg_list);
|
||||||
let tail_expr_finished =
|
let tail_expr_finished =
|
||||||
if is_async { make::expr_await(tail_expr) } else { tail_expr };
|
if is_async { make::expr_await(tail_expr) } else { tail_expr };
|
||||||
let body = make::block_expr([], Some(tail_expr_finished));
|
let body = make::block_expr([], Some(tail_expr_finished));
|
||||||
|
|
||||||
|
let ret_type = method_source.ret_type();
|
||||||
|
|
||||||
let f = make::fn_(
|
let f = make::fn_(
|
||||||
vis,
|
vis,
|
||||||
fn_name,
|
fn_name,
|
||||||
type_params,
|
type_params,
|
||||||
method_source.where_clause(),
|
where_clause,
|
||||||
params,
|
params,
|
||||||
body,
|
body,
|
||||||
ret_type,
|
ret_type,
|
||||||
@ -184,12 +201,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
|
|||||||
let assoc_items = impl_def.get_or_create_assoc_item_list();
|
let assoc_items = impl_def.get_or_create_assoc_item_list();
|
||||||
assoc_items.add_item(f.clone().into());
|
assoc_items.add_item(f.clone().into());
|
||||||
|
|
||||||
if let Some((target, source)) =
|
|
||||||
ctx.sema.scope(strukt.syntax()).zip(ctx.sema.scope(method_source.syntax()))
|
|
||||||
{
|
|
||||||
PathTransform::generic_transformation(&target, &source).apply(f.syntax());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(cap) = ctx.config.snippet_cap {
|
if let Some(cap) = ctx.config.snippet_cap {
|
||||||
edit.add_tabstop_before(cap, f)
|
edit.add_tabstop_before(cap, f)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,246 @@
|
|||||||
|
use ide_db::syntax_helpers::node_ext::is_pattern_cond;
|
||||||
|
use syntax::{
|
||||||
|
ast::{self, AstNode, BinaryOp},
|
||||||
|
T,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
assist_context::{AssistContext, Assists},
|
||||||
|
AssistId, AssistKind,
|
||||||
|
};
|
||||||
|
// Assist: merge_nested_if
|
||||||
|
//
|
||||||
|
// This transforms if expressions of the form `if x { if y {A} }` into `if x && y {A}`
|
||||||
|
// This assist can only be applied with the cursor on `if`.
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// fn main() {
|
||||||
|
// i$0f x == 3 { if y == 4 { 1 } }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// ->
|
||||||
|
// ```
|
||||||
|
// fn main() {
|
||||||
|
// if x == 3 && y == 4 { 1 }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
pub(crate) fn merge_nested_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||||
|
let if_keyword = ctx.find_token_syntax_at_offset(T![if])?;
|
||||||
|
let expr = ast::IfExpr::cast(if_keyword.parent()?)?;
|
||||||
|
let if_range = if_keyword.text_range();
|
||||||
|
let cursor_in_range = if_range.contains_range(ctx.selection_trimmed());
|
||||||
|
if !cursor_in_range {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
//should not apply to if with else branch.
|
||||||
|
if expr.else_branch().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cond = expr.condition()?;
|
||||||
|
//should not apply for if-let
|
||||||
|
if is_pattern_cond(cond.clone()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cond_range = cond.syntax().text_range();
|
||||||
|
|
||||||
|
//check if the then branch is a nested if
|
||||||
|
let then_branch = expr.then_branch()?;
|
||||||
|
let stmt = then_branch.stmt_list()?;
|
||||||
|
if stmt.statements().count() != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nested_if_to_merge = then_branch.tail_expr().and_then(|e| match e {
|
||||||
|
ast::Expr::IfExpr(e) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
})?;
|
||||||
|
// should not apply to nested if with else branch.
|
||||||
|
if nested_if_to_merge.else_branch().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let nested_if_cond = nested_if_to_merge.condition()?;
|
||||||
|
if is_pattern_cond(nested_if_cond.clone()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nested_if_then_branch = nested_if_to_merge.then_branch()?;
|
||||||
|
let then_branch_range = then_branch.syntax().text_range();
|
||||||
|
|
||||||
|
acc.add(
|
||||||
|
AssistId("merge_nested_if", AssistKind::RefactorRewrite),
|
||||||
|
"Merge nested if",
|
||||||
|
if_range,
|
||||||
|
|edit| {
|
||||||
|
let cond_text = if has_logic_op_or(&cond) {
|
||||||
|
format!("({})", cond.syntax().text())
|
||||||
|
} else {
|
||||||
|
cond.syntax().text().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let nested_if_cond_text = if has_logic_op_or(&nested_if_cond) {
|
||||||
|
format!("({})", nested_if_cond.syntax().text())
|
||||||
|
} else {
|
||||||
|
nested_if_cond.syntax().text().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let replace_cond = format!("{} && {}", cond_text, nested_if_cond_text);
|
||||||
|
|
||||||
|
edit.replace(cond_range, replace_cond);
|
||||||
|
edit.replace(then_branch_range, nested_if_then_branch.syntax().text());
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the given if condition has logical operators.
|
||||||
|
fn has_logic_op_or(expr: &ast::Expr) -> bool {
|
||||||
|
match expr {
|
||||||
|
ast::Expr::BinExpr(bin_expr) => {
|
||||||
|
if let Some(kind) = bin_expr.op_kind() {
|
||||||
|
matches!(kind, BinaryOp::LogicOp(ast::LogicOp::Or))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test1() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 { if y == 4 { 1 } } }",
|
||||||
|
"fn f() { if x == 3 && y == 4 { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test2() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 || y == 1 { if z == 4 { 1 } } }",
|
||||||
|
"fn f() { if (x == 3 || y == 1) && z == 4 { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test3() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 && y == 1 { if z == 4 { 1 } } }",
|
||||||
|
"fn f() { if x == 3 && y == 1 && z == 4 { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test4() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 && y == 1 { if z == 4 && q == 3 { 1 } } }",
|
||||||
|
"fn f() { if x == 3 && y == 1 && z == 4 && q == 3 { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test5() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 && y == 1 { if z == 4 || q == 3 { 1 } } }",
|
||||||
|
"fn f() { if x == 3 && y == 1 && (z == 4 || q == 3) { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test6() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 || y == 1 { if z == 4 || q == 3 { 1 } } }",
|
||||||
|
"fn f() { if (x == 3 || y == 1) && (z == 4 || q == 3) { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_test7() {
|
||||||
|
check_assist(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 || y == 1 { if z == 4 && q == 3 { 1 } } }",
|
||||||
|
"fn f() { if (x == 3 || y == 1) && z == 4 && q == 3 { 1 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_to_if_with_else_branch() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 { if y == 4 { 1 } } else { 2 } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_to_nested_if_with_else_branch() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 { if y == 4 { 1 } else { 2 } } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_to_if_let() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f let Some(x) = y { if x == 4 { 1 } } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_to_nested_if_let() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f y == 0 { if let Some(x) = y { 1 } } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_to_if_with_else_branch_and_nested_if() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 3 { if y == 4 { 1 } } else { if z == 5 { 2 } } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_with_cursor_not_on_if() {
|
||||||
|
check_assist_not_applicable(merge_nested_if, "fn f() { if $0x==0 { if y == 3 { 1 } } }")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_with_mulpiple_if() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 0 { if y == 3 { 1 } else if y == 4 { 2 } } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_with_not_only_has_nested_if() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 0 { if y == 3 { foo(); } foo(); } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_nested_if_do_not_apply_with_multiply_nested_if() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
merge_nested_if,
|
||||||
|
"fn f() { i$0f x == 0 { if y == 3 { foo(); } if z == 3 { 2 } } }",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -217,6 +217,7 @@ mod handlers {
|
|||||||
mod unqualify_method_call;
|
mod unqualify_method_call;
|
||||||
mod wrap_return_type_in_result;
|
mod wrap_return_type_in_result;
|
||||||
mod into_to_qualified_from;
|
mod into_to_qualified_from;
|
||||||
|
mod merge_nested_if;
|
||||||
|
|
||||||
pub(crate) fn all() -> &'static [Handler] {
|
pub(crate) fn all() -> &'static [Handler] {
|
||||||
&[
|
&[
|
||||||
@ -291,6 +292,7 @@ mod handlers {
|
|||||||
invert_if::invert_if,
|
invert_if::invert_if,
|
||||||
merge_imports::merge_imports,
|
merge_imports::merge_imports,
|
||||||
merge_match_arms::merge_match_arms,
|
merge_match_arms::merge_match_arms,
|
||||||
|
merge_nested_if::merge_nested_if,
|
||||||
move_bounds::move_bounds_to_where_clause,
|
move_bounds::move_bounds_to_where_clause,
|
||||||
move_const_to_impl::move_const_to_impl,
|
move_const_to_impl::move_const_to_impl,
|
||||||
move_guard::move_arm_cond_to_match_guard,
|
move_guard::move_arm_cond_to_match_guard,
|
||||||
|
@ -2051,6 +2051,23 @@ fn handle(action: Action) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doctest_merge_nested_if() {
|
||||||
|
check_doc_test(
|
||||||
|
"merge_nested_if",
|
||||||
|
r#####"
|
||||||
|
fn main() {
|
||||||
|
i$0f x == 3 { if y == 4 { 1 } }
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
r#####"
|
||||||
|
fn main() {
|
||||||
|
if x == 3 && y == 4 { 1 }
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doctest_move_arm_cond_to_match_guard() {
|
fn doctest_move_arm_cond_to_match_guard() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
|
@ -529,6 +529,11 @@ impl CompletionContext<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the given trait has `#[doc(notable_trait)]`
|
||||||
|
pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool {
|
||||||
|
trait_.attrs(self.db).has_doc_notable_trait()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the traits in scope, with the [`Drop`] trait removed.
|
/// Returns the traits in scope, with the [`Drop`] trait removed.
|
||||||
pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
|
pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
|
||||||
let mut traits_in_scope = self.scope.visible_traits();
|
let mut traits_in_scope = self.scope.visible_traits();
|
||||||
|
@ -152,6 +152,8 @@ pub struct CompletionRelevance {
|
|||||||
pub is_local: bool,
|
pub is_local: bool,
|
||||||
/// This is set when trait items are completed in an impl of that trait.
|
/// This is set when trait items are completed in an impl of that trait.
|
||||||
pub is_item_from_trait: bool,
|
pub is_item_from_trait: bool,
|
||||||
|
/// This is set for when trait items are from traits with `#[doc(notable_trait)]`
|
||||||
|
pub is_item_from_notable_trait: bool,
|
||||||
/// This is set when an import is suggested whose name is already imported.
|
/// This is set when an import is suggested whose name is already imported.
|
||||||
pub is_name_already_imported: bool,
|
pub is_name_already_imported: bool,
|
||||||
/// This is set for completions that will insert a `use` item.
|
/// This is set for completions that will insert a `use` item.
|
||||||
@ -228,6 +230,7 @@ impl CompletionRelevance {
|
|||||||
is_private_editable,
|
is_private_editable,
|
||||||
postfix_match,
|
postfix_match,
|
||||||
is_definite,
|
is_definite,
|
||||||
|
is_item_from_notable_trait,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
// lower rank private things
|
// lower rank private things
|
||||||
@ -266,6 +269,9 @@ impl CompletionRelevance {
|
|||||||
if is_item_from_trait {
|
if is_item_from_trait {
|
||||||
score += 1;
|
score += 1;
|
||||||
}
|
}
|
||||||
|
if is_item_from_notable_trait {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
if is_definite {
|
if is_definite {
|
||||||
score += 10;
|
score += 10;
|
||||||
}
|
}
|
||||||
|
@ -1170,6 +1170,7 @@ fn main() { let _: m::Spam = S$0 }
|
|||||||
),
|
),
|
||||||
is_local: false,
|
is_local: false,
|
||||||
is_item_from_trait: false,
|
is_item_from_trait: false,
|
||||||
|
is_item_from_notable_trait: false,
|
||||||
is_name_already_imported: false,
|
is_name_already_imported: false,
|
||||||
requires_import: false,
|
requires_import: false,
|
||||||
is_op_method: false,
|
is_op_method: false,
|
||||||
@ -1196,6 +1197,7 @@ fn main() { let _: m::Spam = S$0 }
|
|||||||
),
|
),
|
||||||
is_local: false,
|
is_local: false,
|
||||||
is_item_from_trait: false,
|
is_item_from_trait: false,
|
||||||
|
is_item_from_notable_trait: false,
|
||||||
is_name_already_imported: false,
|
is_name_already_imported: false,
|
||||||
requires_import: false,
|
requires_import: false,
|
||||||
is_op_method: false,
|
is_op_method: false,
|
||||||
@ -1274,6 +1276,7 @@ fn foo() { A { the$0 } }
|
|||||||
),
|
),
|
||||||
is_local: false,
|
is_local: false,
|
||||||
is_item_from_trait: false,
|
is_item_from_trait: false,
|
||||||
|
is_item_from_notable_trait: false,
|
||||||
is_name_already_imported: false,
|
is_name_already_imported: false,
|
||||||
requires_import: false,
|
requires_import: false,
|
||||||
is_op_method: false,
|
is_op_method: false,
|
||||||
@ -2089,6 +2092,7 @@ fn foo() {
|
|||||||
),
|
),
|
||||||
is_local: false,
|
is_local: false,
|
||||||
is_item_from_trait: false,
|
is_item_from_trait: false,
|
||||||
|
is_item_from_notable_trait: false,
|
||||||
is_name_already_imported: false,
|
is_name_already_imported: false,
|
||||||
requires_import: false,
|
requires_import: false,
|
||||||
is_op_method: false,
|
is_op_method: false,
|
||||||
@ -2439,4 +2443,81 @@ impl S {
|
|||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn notable_traits_method_relevance() {
|
||||||
|
check_kinds(
|
||||||
|
r#"
|
||||||
|
#[doc(notable_trait)]
|
||||||
|
trait Write {
|
||||||
|
fn write(&self);
|
||||||
|
fn flush(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Writer;
|
||||||
|
|
||||||
|
impl Write for Writer {
|
||||||
|
fn write(&self) {}
|
||||||
|
fn flush(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Writer.$0
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
&[
|
||||||
|
CompletionItemKind::Method,
|
||||||
|
CompletionItemKind::SymbolKind(SymbolKind::Field),
|
||||||
|
CompletionItemKind::SymbolKind(SymbolKind::Function),
|
||||||
|
],
|
||||||
|
expect![[r#"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "flush()",
|
||||||
|
source_range: 193..193,
|
||||||
|
delete: 193..193,
|
||||||
|
insert: "flush()$0",
|
||||||
|
kind: Method,
|
||||||
|
lookup: "flush",
|
||||||
|
detail: "fn(&self)",
|
||||||
|
relevance: CompletionRelevance {
|
||||||
|
exact_name_match: false,
|
||||||
|
type_match: None,
|
||||||
|
is_local: false,
|
||||||
|
is_item_from_trait: false,
|
||||||
|
is_item_from_notable_trait: true,
|
||||||
|
is_name_already_imported: false,
|
||||||
|
requires_import: false,
|
||||||
|
is_op_method: false,
|
||||||
|
is_private_editable: false,
|
||||||
|
postfix_match: None,
|
||||||
|
is_definite: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "write()",
|
||||||
|
source_range: 193..193,
|
||||||
|
delete: 193..193,
|
||||||
|
insert: "write()$0",
|
||||||
|
kind: Method,
|
||||||
|
lookup: "write",
|
||||||
|
detail: "fn(&self)",
|
||||||
|
relevance: CompletionRelevance {
|
||||||
|
exact_name_match: false,
|
||||||
|
type_match: None,
|
||||||
|
is_local: false,
|
||||||
|
is_item_from_trait: false,
|
||||||
|
is_item_from_notable_trait: true,
|
||||||
|
is_name_already_imported: false,
|
||||||
|
requires_import: false,
|
||||||
|
is_op_method: false,
|
||||||
|
is_private_editable: false,
|
||||||
|
postfix_match: None,
|
||||||
|
is_definite: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,13 @@ fn render(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let ret_type = func.ret_type(db);
|
let ret_type = func.ret_type(db);
|
||||||
let is_op_method = func
|
let assoc_item = func.as_assoc_item(db);
|
||||||
.as_assoc_item(ctx.db())
|
|
||||||
.and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db()))
|
let trait_ = assoc_item.and_then(|trait_| trait_.containing_trait_or_trait_impl(db));
|
||||||
.map_or(false, |trait_| completion.is_ops_trait(trait_));
|
let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_));
|
||||||
|
|
||||||
|
let is_item_from_notable_trait =
|
||||||
|
trait_.map_or(false, |trait_| completion.is_doc_notable_trait(trait_));
|
||||||
|
|
||||||
let (has_dot_receiver, has_call_parens, cap) = match func_kind {
|
let (has_dot_receiver, has_call_parens, cap) = match func_kind {
|
||||||
FuncKind::Function(&PathCompletionCtx {
|
FuncKind::Function(&PathCompletionCtx {
|
||||||
@ -105,6 +108,7 @@ fn render(
|
|||||||
},
|
},
|
||||||
exact_name_match: compute_exact_name_match(completion, &call),
|
exact_name_match: compute_exact_name_match(completion, &call),
|
||||||
is_op_method,
|
is_op_method,
|
||||||
|
is_item_from_notable_trait,
|
||||||
..ctx.completion_relevance()
|
..ctx.completion_relevance()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -141,7 +145,7 @@ fn render(
|
|||||||
item.add_import(import_to_add);
|
item.add_import(import_to_add);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Some(actm) = func.as_assoc_item(db) {
|
if let Some(actm) = assoc_item {
|
||||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||||
item.trait_name(trt.name(db).to_smol_str());
|
item.trait_name(trt.name(db).to_smol_str());
|
||||||
}
|
}
|
||||||
|
@ -84,73 +84,11 @@ impl RootDatabase {
|
|||||||
)*}
|
)*}
|
||||||
}
|
}
|
||||||
purge_each_query![
|
purge_each_query![
|
||||||
// SourceDatabase
|
// SymbolsDatabase
|
||||||
base_db::ParseQuery
|
crate::symbol_index::ModuleSymbolsQuery
|
||||||
base_db::CrateGraphQuery
|
crate::symbol_index::LibrarySymbolsQuery
|
||||||
|
crate::symbol_index::LocalRootsQuery
|
||||||
// SourceDatabaseExt
|
crate::symbol_index::LibraryRootsQuery
|
||||||
base_db::FileTextQuery
|
|
||||||
base_db::FileSourceRootQuery
|
|
||||||
base_db::SourceRootQuery
|
|
||||||
base_db::SourceRootCratesQuery
|
|
||||||
|
|
||||||
// ExpandDatabase
|
|
||||||
hir::db::AstIdMapQuery
|
|
||||||
hir::db::DeclMacroExpanderQuery
|
|
||||||
hir::db::ExpandProcMacroQuery
|
|
||||||
hir::db::InternMacroCallQuery
|
|
||||||
hir::db::InternSyntaxContextQuery
|
|
||||||
hir::db::MacroArgQuery
|
|
||||||
hir::db::ParseMacroExpansionQuery
|
|
||||||
hir::db::RealSpanMapQuery
|
|
||||||
hir::db::ProcMacrosQuery
|
|
||||||
|
|
||||||
// DefDatabase
|
|
||||||
hir::db::FileItemTreeQuery
|
|
||||||
hir::db::CrateDefMapQueryQuery
|
|
||||||
hir::db::BlockDefMapQuery
|
|
||||||
hir::db::StructDataQuery
|
|
||||||
hir::db::StructDataWithDiagnosticsQuery
|
|
||||||
hir::db::UnionDataQuery
|
|
||||||
hir::db::UnionDataWithDiagnosticsQuery
|
|
||||||
hir::db::EnumDataQuery
|
|
||||||
hir::db::EnumDataWithDiagnosticsQuery
|
|
||||||
hir::db::ImplDataQuery
|
|
||||||
hir::db::ImplDataWithDiagnosticsQuery
|
|
||||||
hir::db::TraitDataQuery
|
|
||||||
hir::db::TraitDataWithDiagnosticsQuery
|
|
||||||
hir::db::TraitAliasDataQuery
|
|
||||||
hir::db::TypeAliasDataQuery
|
|
||||||
hir::db::FunctionDataQuery
|
|
||||||
hir::db::ConstDataQuery
|
|
||||||
hir::db::StaticDataQuery
|
|
||||||
hir::db::Macro2DataQuery
|
|
||||||
hir::db::MacroRulesDataQuery
|
|
||||||
hir::db::ProcMacroDataQuery
|
|
||||||
hir::db::BodyWithSourceMapQuery
|
|
||||||
hir::db::BodyQuery
|
|
||||||
hir::db::ExprScopesQuery
|
|
||||||
hir::db::GenericParamsQuery
|
|
||||||
hir::db::VariantsAttrsQuery
|
|
||||||
hir::db::FieldsAttrsQuery
|
|
||||||
hir::db::VariantsAttrsSourceMapQuery
|
|
||||||
hir::db::FieldsAttrsSourceMapQuery
|
|
||||||
hir::db::AttrsQuery
|
|
||||||
hir::db::CrateLangItemsQuery
|
|
||||||
hir::db::LangItemQuery
|
|
||||||
hir::db::ImportMapQuery
|
|
||||||
hir::db::FieldVisibilitiesQuery
|
|
||||||
hir::db::FunctionVisibilityQuery
|
|
||||||
hir::db::ConstVisibilityQuery
|
|
||||||
hir::db::CrateSupportsNoStdQuery
|
|
||||||
hir::db::BlockItemTreeQueryQuery
|
|
||||||
hir::db::ExternCrateDeclDataQuery
|
|
||||||
hir::db::LangAttrQuery
|
|
||||||
hir::db::InternAnonymousConstQuery
|
|
||||||
hir::db::InternExternCrateQuery
|
|
||||||
hir::db::InternInTypeConstQuery
|
|
||||||
hir::db::InternUseQuery
|
|
||||||
|
|
||||||
// HirDatabase
|
// HirDatabase
|
||||||
hir::db::InferQueryQuery
|
hir::db::InferQueryQuery
|
||||||
hir::db::MirBodyQuery
|
hir::db::MirBodyQuery
|
||||||
@ -194,14 +132,50 @@ impl RootDatabase {
|
|||||||
hir::db::TraitSolveQueryQuery
|
hir::db::TraitSolveQueryQuery
|
||||||
hir::db::ProgramClausesForChalkEnvQuery
|
hir::db::ProgramClausesForChalkEnvQuery
|
||||||
|
|
||||||
// SymbolsDatabase
|
// DefDatabase
|
||||||
crate::symbol_index::ModuleSymbolsQuery
|
hir::db::FileItemTreeQuery
|
||||||
crate::symbol_index::LibrarySymbolsQuery
|
hir::db::CrateDefMapQueryQuery
|
||||||
crate::symbol_index::LocalRootsQuery
|
hir::db::BlockDefMapQuery
|
||||||
crate::symbol_index::LibraryRootsQuery
|
hir::db::StructDataQuery
|
||||||
|
hir::db::StructDataWithDiagnosticsQuery
|
||||||
// LineIndexDatabase
|
hir::db::UnionDataQuery
|
||||||
crate::LineIndexQuery
|
hir::db::UnionDataWithDiagnosticsQuery
|
||||||
|
hir::db::EnumDataQuery
|
||||||
|
hir::db::EnumDataWithDiagnosticsQuery
|
||||||
|
hir::db::ImplDataQuery
|
||||||
|
hir::db::ImplDataWithDiagnosticsQuery
|
||||||
|
hir::db::TraitDataQuery
|
||||||
|
hir::db::TraitDataWithDiagnosticsQuery
|
||||||
|
hir::db::TraitAliasDataQuery
|
||||||
|
hir::db::TypeAliasDataQuery
|
||||||
|
hir::db::FunctionDataQuery
|
||||||
|
hir::db::ConstDataQuery
|
||||||
|
hir::db::StaticDataQuery
|
||||||
|
hir::db::Macro2DataQuery
|
||||||
|
hir::db::MacroRulesDataQuery
|
||||||
|
hir::db::ProcMacroDataQuery
|
||||||
|
hir::db::BodyWithSourceMapQuery
|
||||||
|
hir::db::BodyQuery
|
||||||
|
hir::db::ExprScopesQuery
|
||||||
|
hir::db::GenericParamsQuery
|
||||||
|
hir::db::VariantsAttrsQuery
|
||||||
|
hir::db::FieldsAttrsQuery
|
||||||
|
hir::db::VariantsAttrsSourceMapQuery
|
||||||
|
hir::db::FieldsAttrsSourceMapQuery
|
||||||
|
hir::db::AttrsQuery
|
||||||
|
hir::db::CrateLangItemsQuery
|
||||||
|
hir::db::LangItemQuery
|
||||||
|
hir::db::ImportMapQuery
|
||||||
|
hir::db::FieldVisibilitiesQuery
|
||||||
|
hir::db::FunctionVisibilityQuery
|
||||||
|
hir::db::ConstVisibilityQuery
|
||||||
|
hir::db::CrateSupportsNoStdQuery
|
||||||
|
hir::db::BlockItemTreeQueryQuery
|
||||||
|
hir::db::ExternCrateDeclDataQuery
|
||||||
|
hir::db::InternAnonymousConstQuery
|
||||||
|
hir::db::InternExternCrateQuery
|
||||||
|
hir::db::InternInTypeConstQuery
|
||||||
|
hir::db::InternUseQuery
|
||||||
|
|
||||||
// InternDatabase
|
// InternDatabase
|
||||||
hir::db::InternFunctionQuery
|
hir::db::InternFunctionQuery
|
||||||
@ -219,6 +193,30 @@ impl RootDatabase {
|
|||||||
hir::db::InternMacro2Query
|
hir::db::InternMacro2Query
|
||||||
hir::db::InternProcMacroQuery
|
hir::db::InternProcMacroQuery
|
||||||
hir::db::InternMacroRulesQuery
|
hir::db::InternMacroRulesQuery
|
||||||
|
|
||||||
|
// ExpandDatabase
|
||||||
|
hir::db::AstIdMapQuery
|
||||||
|
hir::db::DeclMacroExpanderQuery
|
||||||
|
hir::db::ExpandProcMacroQuery
|
||||||
|
hir::db::InternMacroCallQuery
|
||||||
|
hir::db::InternSyntaxContextQuery
|
||||||
|
hir::db::MacroArgQuery
|
||||||
|
hir::db::ParseMacroExpansionQuery
|
||||||
|
hir::db::RealSpanMapQuery
|
||||||
|
hir::db::ProcMacrosQuery
|
||||||
|
|
||||||
|
// LineIndexDatabase
|
||||||
|
crate::LineIndexQuery
|
||||||
|
|
||||||
|
// SourceDatabase
|
||||||
|
base_db::ParseQuery
|
||||||
|
base_db::CrateGraphQuery
|
||||||
|
|
||||||
|
// SourceDatabaseExt
|
||||||
|
base_db::FileTextQuery
|
||||||
|
base_db::FileSourceRootQuery
|
||||||
|
base_db::SourceRootQuery
|
||||||
|
base_db::SourceRootCratesQuery
|
||||||
];
|
];
|
||||||
|
|
||||||
acc.sort_by_key(|it| std::cmp::Reverse(it.1));
|
acc.sort_by_key(|it| std::cmp::Reverse(it.1));
|
||||||
|
@ -681,11 +681,10 @@ fn path_import_candidate(
|
|||||||
Some(qualifier) => match sema.resolve_path(&qualifier) {
|
Some(qualifier) => match sema.resolve_path(&qualifier) {
|
||||||
None => {
|
None => {
|
||||||
if qualifier.first_qualifier().map_or(true, |it| sema.resolve_path(&it).is_none()) {
|
if qualifier.first_qualifier().map_or(true, |it| sema.resolve_path(&it).is_none()) {
|
||||||
let mut qualifier = qualifier
|
let qualifier = qualifier
|
||||||
.segments_of_this_path_only_rev()
|
.segments()
|
||||||
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
qualifier.reverse();
|
|
||||||
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
|
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
|
@ -124,7 +124,7 @@ impl FileLoader for RootDatabase {
|
|||||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ impl RootDatabase {
|
|||||||
db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
|
db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
|
||||||
db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
|
db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
|
||||||
db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
|
db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
|
||||||
db.update_parse_query_lru_capacity(lru_capacity);
|
db.update_base_query_lru_capacities(lru_capacity);
|
||||||
db.setup_syntax_context_root();
|
db.setup_syntax_context_root();
|
||||||
db
|
db
|
||||||
}
|
}
|
||||||
@ -154,11 +154,12 @@ impl RootDatabase {
|
|||||||
self.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
|
self.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_parse_query_lru_capacity(&mut self, lru_capacity: Option<usize>) {
|
pub fn update_base_query_lru_capacities(&mut self, lru_capacity: Option<usize>) {
|
||||||
let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP);
|
let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP);
|
||||||
base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
||||||
// macro expansions are usually rather small, so we can afford to keep more of them alive
|
// macro expansions are usually rather small, so we can afford to keep more of them alive
|
||||||
hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity);
|
hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity);
|
||||||
|
hir::db::BorrowckQuery.in_db_mut(self).set_lru_capacity(base_db::DEFAULT_BORROWCK_LRU_CAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
|
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
|
||||||
@ -176,6 +177,12 @@ impl RootDatabase {
|
|||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP),
|
.unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP),
|
||||||
);
|
);
|
||||||
|
hir_db::BorrowckQuery.in_db_mut(self).set_lru_capacity(
|
||||||
|
lru_capacities
|
||||||
|
.get(stringify!(BorrowckQuery))
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(base_db::DEFAULT_BORROWCK_LRU_CAP),
|
||||||
|
);
|
||||||
|
|
||||||
macro_rules! update_lru_capacity_per_query {
|
macro_rules! update_lru_capacity_per_query {
|
||||||
($( $module:ident :: $query:ident )*) => {$(
|
($( $module:ident :: $query:ident )*) => {$(
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use crate::helpers::mod_path_to_ast;
|
use crate::helpers::mod_path_to_ast;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope};
|
use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope};
|
||||||
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, AstNode},
|
ast::{self, make, AstNode},
|
||||||
@ -227,11 +228,15 @@ struct Ctx<'a> {
|
|||||||
same_self_type: bool,
|
same_self_type: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
||||||
item.preorder().filter_map(|event| match event {
|
let x = item
|
||||||
syntax::WalkEvent::Enter(_) => None,
|
.preorder()
|
||||||
syntax::WalkEvent::Leave(node) => Some(node),
|
.filter_map(|event| match event {
|
||||||
})
|
syntax::WalkEvent::Enter(node) => Some(node),
|
||||||
|
syntax::WalkEvent::Leave(_) => None,
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
x.into_iter().rev()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx<'_> {
|
impl Ctx<'_> {
|
||||||
@ -239,12 +244,12 @@ impl Ctx<'_> {
|
|||||||
// `transform_path` may update a node's parent and that would break the
|
// `transform_path` may update a node's parent and that would break the
|
||||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||||
// so that such operation is safe.
|
// so that such operation is safe.
|
||||||
let paths = postorder(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||||
for path in paths {
|
for path in paths {
|
||||||
self.transform_path(path);
|
self.transform_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
||||||
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
|
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
|
||||||
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
||||||
}
|
}
|
||||||
@ -263,7 +268,7 @@ impl Ctx<'_> {
|
|||||||
// `transform_path` may update a node's parent and that would break the
|
// `transform_path` may update a node's parent and that would break the
|
||||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||||
// so that such operation is safe.
|
// so that such operation is safe.
|
||||||
let paths = postorder(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||||
for path in paths {
|
for path in paths {
|
||||||
self.transform_path(path);
|
self.transform_path(path);
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ impl Definition {
|
|||||||
if let Some(Visibility::Public) = vis {
|
if let Some(Visibility::Public) = vis {
|
||||||
return SearchScope::reverse_dependencies(db, module.krate());
|
return SearchScope::reverse_dependencies(db, module.krate());
|
||||||
}
|
}
|
||||||
if let Some(Visibility::Module(module)) = vis {
|
if let Some(Visibility::Module(module, _)) = vis {
|
||||||
return SearchScope::module_and_children(db, module.into());
|
return SearchScope::module_and_children(db, module.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ pub(crate) fn unresolved_assoc_item(
|
|||||||
"no such associated item",
|
"no such associated item",
|
||||||
d.expr_or_pat.clone().map(Into::into),
|
d.expr_or_pat.clone().map(Into::into),
|
||||||
)
|
)
|
||||||
|
.experimental()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -481,7 +481,7 @@ struct Foo {}
|
|||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Clone
|
Clone
|
||||||
impl < >core::clone::Clone for Foo< >where {
|
impl < >$crate::clone::Clone for Foo< >where {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Foo{}
|
Foo{}
|
||||||
@ -507,7 +507,7 @@ struct Foo {}
|
|||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Copy
|
Copy
|
||||||
impl < >core::marker::Copy for Foo< >where{}"#]],
|
impl < >$crate::marker::Copy for Foo< >where{}"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,7 +522,7 @@ struct Foo {}
|
|||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Copy
|
Copy
|
||||||
impl < >core::marker::Copy for Foo< >where{}"#]],
|
impl < >$crate::marker::Copy for Foo< >where{}"#]],
|
||||||
);
|
);
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
@ -533,7 +533,7 @@ struct Foo {}
|
|||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Clone
|
Clone
|
||||||
impl < >core::clone::Clone for Foo< >where {
|
impl < >$crate::clone::Clone for Foo< >where {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Foo{}
|
Foo{}
|
||||||
|
@ -171,7 +171,7 @@ impl AnalysisHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
|
pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
|
||||||
self.db.update_parse_query_lru_capacity(lru_capacity);
|
self.db.update_base_query_lru_capacities(lru_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
|
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
|
||||||
|
@ -322,7 +322,7 @@ fn load_crate_graph(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vfs::loader::Message::Loaded { files } => {
|
vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => {
|
||||||
for (path, contents) in files {
|
for (path, contents) in files {
|
||||||
vfs.set_file_contents(path.into(), contents);
|
vfs.set_file_contents(path.into(), contents);
|
||||||
}
|
}
|
||||||
@ -331,9 +331,8 @@ fn load_crate_graph(
|
|||||||
}
|
}
|
||||||
let changes = vfs.take_changes();
|
let changes = vfs.take_changes();
|
||||||
for file in changes {
|
for file in changes {
|
||||||
if file.exists() {
|
if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
|
||||||
let contents = vfs.file_contents(file.file_id);
|
if let Ok(text) = std::str::from_utf8(&v) {
|
||||||
if let Ok(text) = std::str::from_utf8(contents) {
|
|
||||||
analysis_change.change_file(file.file_id, Some(text.into()))
|
analysis_change.change_file(file.file_id, Some(text.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,7 @@ doctest = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
drop_bomb = "0.1.5"
|
drop_bomb = "0.1.5"
|
||||||
rustc-dependencies.workspace = true
|
ra-ap-rustc_lexer.workspace = true
|
||||||
|
|
||||||
limit.workspace = true
|
limit.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@ -24,7 +23,7 @@ stdx.workspace = true
|
|||||||
sourcegen.workspace = true
|
sourcegen.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
in-rust-tree = []
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -371,7 +371,15 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik
|
|||||||
if p.at(op) {
|
if p.at(op) {
|
||||||
m = p.start();
|
m = p.start();
|
||||||
p.bump(op);
|
p.bump(op);
|
||||||
if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
|
|
||||||
|
// test closure_range_method_call
|
||||||
|
// fn foo() {
|
||||||
|
// || .. .method();
|
||||||
|
// || .. .field;
|
||||||
|
// }
|
||||||
|
let has_access_after = p.at(T![.]) && p.nth_at(1, SyntaxKind::IDENT);
|
||||||
|
let struct_forbidden = r.forbid_structs && p.at(T!['{']);
|
||||||
|
if p.at_ts(EXPR_FIRST) && !has_access_after && !struct_forbidden {
|
||||||
expr_bp(p, None, r, 2);
|
expr_bp(p, None, r, 2);
|
||||||
}
|
}
|
||||||
let cm = m.complete(p, RANGE_EXPR);
|
let cm = m.complete(p, RANGE_EXPR);
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
//! Note that these tokens, unlike the tokens we feed into the parser, do
|
//! Note that these tokens, unlike the tokens we feed into the parser, do
|
||||||
//! include info about comments and whitespace.
|
//! include info about comments and whitespace.
|
||||||
|
|
||||||
use rustc_dependencies::lexer as rustc_lexer;
|
|
||||||
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
use rustc_lexer::unescape::{EscapeError, Mode};
|
use rustc_lexer::unescape::{EscapeError, Mode};
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
#![allow(rustdoc::private_intra_doc_links)]
|
#![allow(rustdoc::private_intra_doc_links)]
|
||||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||||
|
|
||||||
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
|
extern crate ra_ap_rustc_lexer as rustc_lexer;
|
||||||
|
#[cfg(feature = "in-rust-tree")]
|
||||||
|
extern crate rustc_lexer;
|
||||||
|
|
||||||
mod lexed_str;
|
mod lexed_str;
|
||||||
mod token_set;
|
mod token_set;
|
||||||
mod syntax_kind;
|
mod syntax_kind;
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
SOURCE_FILE
|
||||||
|
FN
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "foo"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
EXPR_STMT
|
||||||
|
METHOD_CALL_EXPR
|
||||||
|
CLOSURE_EXPR
|
||||||
|
PARAM_LIST
|
||||||
|
PIPE "|"
|
||||||
|
PIPE "|"
|
||||||
|
WHITESPACE " "
|
||||||
|
RANGE_EXPR
|
||||||
|
DOT2 ".."
|
||||||
|
WHITESPACE " "
|
||||||
|
DOT "."
|
||||||
|
NAME_REF
|
||||||
|
IDENT "method"
|
||||||
|
ARG_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
R_PAREN ")"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
EXPR_STMT
|
||||||
|
FIELD_EXPR
|
||||||
|
CLOSURE_EXPR
|
||||||
|
PARAM_LIST
|
||||||
|
PIPE "|"
|
||||||
|
PIPE "|"
|
||||||
|
WHITESPACE " "
|
||||||
|
RANGE_EXPR
|
||||||
|
DOT2 ".."
|
||||||
|
WHITESPACE " "
|
||||||
|
DOT "."
|
||||||
|
NAME_REF
|
||||||
|
IDENT "field"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
@ -0,0 +1,4 @@
|
|||||||
|
fn foo() {
|
||||||
|
|| .. .method();
|
||||||
|
|| .. .field;
|
||||||
|
}
|
@ -14,8 +14,10 @@ mod version;
|
|||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use paths::AbsPathBuf;
|
use paths::AbsPathBuf;
|
||||||
use span::Span;
|
use span::Span;
|
||||||
use std::{fmt, io, sync::Mutex};
|
use std::{
|
||||||
use triomphe::Arc;
|
fmt, io,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -81,9 +83,11 @@ impl PartialEq for ProcMacro {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct ServerError {
|
pub struct ServerError {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub io: Option<io::Error>,
|
// io::Error isn't Clone for some reason
|
||||||
|
pub io: Option<Arc<io::Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ServerError {
|
impl fmt::Display for ServerError {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! Handle process life-time and message passing for proc-macro client
|
//! Handle process life-time and message passing for proc-macro client
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, BufRead, BufReader, Write},
|
io::{self, BufRead, BufReader, Read, Write},
|
||||||
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use paths::{AbsPath, AbsPathBuf};
|
use paths::{AbsPath, AbsPathBuf};
|
||||||
@ -15,9 +16,11 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ProcMacroProcessSrv {
|
pub(crate) struct ProcMacroProcessSrv {
|
||||||
_process: Process,
|
process: Process,
|
||||||
stdin: ChildStdin,
|
stdin: ChildStdin,
|
||||||
stdout: BufReader<ChildStdout>,
|
stdout: BufReader<ChildStdout>,
|
||||||
|
/// Populated when the server exits.
|
||||||
|
server_exited: Option<ServerError>,
|
||||||
version: u32,
|
version: u32,
|
||||||
mode: SpanMode,
|
mode: SpanMode,
|
||||||
}
|
}
|
||||||
@ -29,9 +32,10 @@ impl ProcMacroProcessSrv {
|
|||||||
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
|
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
|
||||||
|
|
||||||
io::Result::Ok(ProcMacroProcessSrv {
|
io::Result::Ok(ProcMacroProcessSrv {
|
||||||
_process: process,
|
process,
|
||||||
stdin,
|
stdin,
|
||||||
stdout,
|
stdout,
|
||||||
|
server_exited: None,
|
||||||
version: 0,
|
version: 0,
|
||||||
mode: SpanMode::Id,
|
mode: SpanMode::Id,
|
||||||
})
|
})
|
||||||
@ -105,8 +109,35 @@ impl ProcMacroProcessSrv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> {
|
pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> {
|
||||||
|
if let Some(server_error) = &self.server_exited {
|
||||||
|
return Err(server_error.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
send_request(&mut self.stdin, &mut self.stdout, req, &mut buf)
|
send_request(&mut self.stdin, &mut self.stdout, req, &mut buf).map_err(|e| {
|
||||||
|
if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) {
|
||||||
|
match self.process.child.try_wait() {
|
||||||
|
Ok(None) => e,
|
||||||
|
Ok(Some(status)) => {
|
||||||
|
let mut msg = String::new();
|
||||||
|
if !status.success() {
|
||||||
|
if let Some(stderr) = self.process.child.stderr.as_mut() {
|
||||||
|
_ = stderr.read_to_string(&mut msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let server_error = ServerError {
|
||||||
|
message: format!("server exited with {status}: {msg}"),
|
||||||
|
io: None,
|
||||||
|
};
|
||||||
|
self.server_exited = Some(server_error.clone());
|
||||||
|
server_error
|
||||||
|
}
|
||||||
|
Err(_) => e,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,12 +162,19 @@ impl Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result<Child> {
|
fn mk_child(path: &AbsPath, null_stderr: bool) -> io::Result<Child> {
|
||||||
Command::new(path.as_os_str())
|
let mut cmd = Command::new(path.as_os_str());
|
||||||
.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
|
cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() })
|
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });
|
||||||
.spawn()
|
if cfg!(windows) {
|
||||||
|
let mut path_var = std::ffi::OsString::new();
|
||||||
|
path_var.push(path.parent().unwrap().parent().unwrap().as_os_str());
|
||||||
|
path_var.push("\\bin;");
|
||||||
|
path_var.push(std::env::var_os("PATH").unwrap_or_default());
|
||||||
|
cmd.env("PATH", path_var);
|
||||||
|
}
|
||||||
|
cmd.spawn()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_request(
|
fn send_request(
|
||||||
@ -145,9 +183,13 @@ fn send_request(
|
|||||||
req: Request,
|
req: Request,
|
||||||
buf: &mut String,
|
buf: &mut String,
|
||||||
) -> Result<Response, ServerError> {
|
) -> Result<Response, ServerError> {
|
||||||
req.write(&mut writer)
|
req.write(&mut writer).map_err(|err| ServerError {
|
||||||
.map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?;
|
message: "failed to write request".into(),
|
||||||
let res = Response::read(&mut reader, buf)
|
io: Some(Arc::new(err)),
|
||||||
.map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?;
|
})?;
|
||||||
|
let res = Response::read(&mut reader, buf).map_err(|err| ServerError {
|
||||||
|
message: "failed to read response".into(),
|
||||||
|
io: Some(Arc::new(err)),
|
||||||
|
})?;
|
||||||
res.ok_or_else(|| ServerError { message: "server exited".into(), io: None })
|
res.ok_or_else(|| ServerError { message: "server exited".into(), io: None })
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ fn main() -> std::io::Result<()> {
|
|||||||
|
|
||||||
#[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))]
|
#[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))]
|
||||||
fn run() -> io::Result<()> {
|
fn run() -> io::Result<()> {
|
||||||
panic!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled");
|
eprintln!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled");
|
||||||
|
std::process::exit(70);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
||||||
|
@ -37,7 +37,7 @@ expect-test = "1.4.0"
|
|||||||
proc-macro-test.path = "./proc-macro-test"
|
proc-macro-test.path = "./proc-macro-test"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
sysroot-abi = ["proc-macro-test/sysroot-abi"]
|
sysroot-abi = []
|
||||||
in-rust-tree = ["mbe/in-rust-tree", "sysroot-abi"]
|
in-rust-tree = ["mbe/in-rust-tree", "sysroot-abi"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
@ -14,6 +14,3 @@ cargo_metadata = "0.18.1"
|
|||||||
|
|
||||||
# local deps
|
# local deps
|
||||||
toolchain.workspace = true
|
toolchain.workspace = true
|
||||||
|
|
||||||
[features]
|
|
||||||
sysroot-abi = []
|
|
||||||
|
@ -17,11 +17,24 @@ use cargo_metadata::Message;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-changed=imp");
|
println!("cargo:rerun-if-changed=imp");
|
||||||
println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN");
|
|
||||||
|
let has_features = env::var_os("RUSTC_BOOTSTRAP").is_some()
|
||||||
|
|| String::from_utf8(
|
||||||
|
Command::new(toolchain::cargo()).arg("--version").output().unwrap().stdout,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.contains("nightly");
|
||||||
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
let out_dir = Path::new(&out_dir);
|
let out_dir = Path::new(&out_dir);
|
||||||
|
|
||||||
|
if !has_features {
|
||||||
|
println!("proc-macro-test testing only works on nightly toolchains");
|
||||||
|
let info_path = out_dir.join("proc_macro_test_location.txt");
|
||||||
|
fs::File::create(info_path).unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let name = "proc-macro-test-impl";
|
let name = "proc-macro-test-impl";
|
||||||
let version = "0.0.0";
|
let version = "0.0.0";
|
||||||
|
|
||||||
@ -53,15 +66,7 @@ fn main() {
|
|||||||
|
|
||||||
let target_dir = out_dir.join("target");
|
let target_dir = out_dir.join("target");
|
||||||
|
|
||||||
let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") {
|
let mut cmd = Command::new(toolchain::cargo());
|
||||||
// leverage rustup to find user-specific toolchain
|
|
||||||
let mut cmd = Command::new("cargo");
|
|
||||||
cmd.arg(format!("+{toolchain}"));
|
|
||||||
cmd
|
|
||||||
} else {
|
|
||||||
Command::new(toolchain::cargo())
|
|
||||||
};
|
|
||||||
|
|
||||||
cmd.current_dir(&staging_dir)
|
cmd.current_dir(&staging_dir)
|
||||||
.args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
|
.args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
|
||||||
// Explicit override the target directory to avoid using the same one which the parent
|
// Explicit override the target directory to avoid using the same one which the parent
|
||||||
@ -70,9 +75,6 @@ fn main() {
|
|||||||
// instance to use the same target directory.
|
// instance to use the same target directory.
|
||||||
.arg("--target-dir")
|
.arg("--target-dir")
|
||||||
.arg(&target_dir);
|
.arg(&target_dir);
|
||||||
if cfg!(feature = "sysroot-abi") {
|
|
||||||
cmd.args(["--features", "sysroot-abi"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(target) = std::env::var("TARGET") {
|
if let Ok(target) = std::env::var("TARGET") {
|
||||||
cmd.args(["--target", &target]);
|
cmd.args(["--target", &target]);
|
||||||
|
@ -13,7 +13,4 @@ proc-macro = true
|
|||||||
# this crate should not have any dependencies, since it uses its own workspace,
|
# this crate should not have any dependencies, since it uses its own workspace,
|
||||||
# and its own `Cargo.lock`
|
# and its own `Cargo.lock`
|
||||||
|
|
||||||
[features]
|
|
||||||
sysroot-abi = []
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
//! Exports a few trivial procedural macros for testing.
|
//! Exports a few trivial procedural macros for testing.
|
||||||
|
|
||||||
#![allow(unexpected_cfgs)]
|
|
||||||
#![cfg(feature = "sysroot-abi")]
|
|
||||||
#![cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
|
||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
#![feature(proc_macro_span, proc_macro_def_site)]
|
#![feature(proc_macro_span, proc_macro_def_site)]
|
||||||
|
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
//! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)…
|
//! rustc rather than `unstable`. (Although in general ABI compatibility is still an issue)…
|
||||||
|
|
||||||
#![cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
#![cfg(any(feature = "sysroot-abi", rust_analyzer))]
|
||||||
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span, rustc_private)]
|
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||||
|
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)]
|
||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
#![allow(unreachable_pub, internal_features)]
|
#![allow(unreachable_pub, internal_features)]
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
#[cfg(feature = "in-rust-tree")]
|
||||||
extern crate rustc_driver as _;
|
extern crate rustc_driver as _;
|
||||||
|
|
||||||
mod dylib;
|
mod dylib;
|
||||||
|
@ -1398,7 +1398,7 @@ fn sysroot_to_crate_graph(
|
|||||||
let public_deps = SysrootPublicDeps {
|
let public_deps = SysrootPublicDeps {
|
||||||
deps: sysroot
|
deps: sysroot
|
||||||
.public_deps()
|
.public_deps()
|
||||||
.map(|(name, idx, prelude)| (name, sysroot_crates[&idx], prelude))
|
.filter_map(|(name, idx, prelude)| Some((name, *sysroot_crates.get(&idx)?, prelude)))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ flycheck.workspace = true
|
|||||||
hir-def.workspace = true
|
hir-def.workspace = true
|
||||||
hir-ty.workspace = true
|
hir-ty.workspace = true
|
||||||
hir.workspace = true
|
hir.workspace = true
|
||||||
rustc-dependencies.workspace = true
|
|
||||||
ide-db.workspace = true
|
ide-db.workspace = true
|
||||||
# This should only be used in CLI
|
# This should only be used in CLI
|
||||||
ide-ssr.workspace = true
|
ide-ssr.workspace = true
|
||||||
@ -89,11 +88,10 @@ in-rust-tree = [
|
|||||||
"ide/in-rust-tree",
|
"ide/in-rust-tree",
|
||||||
"syntax/in-rust-tree",
|
"syntax/in-rust-tree",
|
||||||
"parser/in-rust-tree",
|
"parser/in-rust-tree",
|
||||||
"rustc-dependencies/in-rust-tree",
|
|
||||||
"hir/in-rust-tree",
|
"hir/in-rust-tree",
|
||||||
"hir-def/in-rust-tree",
|
"hir-def/in-rust-tree",
|
||||||
"hir-ty/in-rust-tree",
|
"hir-ty/in-rust-tree",
|
||||||
]
|
]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//!
|
//!
|
||||||
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
|
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
|
||||||
|
|
||||||
use std::time::Instant;
|
use std::{collections::hash_map::Entry, time::Instant};
|
||||||
|
|
||||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||||
use flycheck::FlycheckHandle;
|
use flycheck::FlycheckHandle;
|
||||||
@ -21,7 +21,7 @@ use proc_macro_api::ProcMacroServer;
|
|||||||
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
|
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
use vfs::{AnchoredPathBuf, Vfs};
|
use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, ConfigError},
|
config::{Config, ConfigError},
|
||||||
@ -217,8 +217,8 @@ impl GlobalState {
|
|||||||
pub(crate) fn process_changes(&mut self) -> bool {
|
pub(crate) fn process_changes(&mut self) -> bool {
|
||||||
let _p = profile::span("GlobalState::process_changes");
|
let _p = profile::span("GlobalState::process_changes");
|
||||||
|
|
||||||
let mut file_changes = FxHashMap::default();
|
let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default();
|
||||||
let (change, changed_files, workspace_structure_change) = {
|
let (change, modified_rust_files, workspace_structure_change) = {
|
||||||
let mut change = Change::new();
|
let mut change = Change::new();
|
||||||
let mut guard = self.vfs.write();
|
let mut guard = self.vfs.write();
|
||||||
let changed_files = guard.0.take_changes();
|
let changed_files = guard.0.take_changes();
|
||||||
@ -233,64 +233,63 @@ impl GlobalState {
|
|||||||
// id that is followed by a delete we actually skip observing the file text from the
|
// id that is followed by a delete we actually skip observing the file text from the
|
||||||
// earlier event, to avoid problems later on.
|
// earlier event, to avoid problems later on.
|
||||||
for changed_file in changed_files {
|
for changed_file in changed_files {
|
||||||
use vfs::ChangeKind::*;
|
use vfs::Change::*;
|
||||||
|
match file_changes.entry(changed_file.file_id) {
|
||||||
file_changes
|
Entry::Occupied(mut o) => {
|
||||||
.entry(changed_file.file_id)
|
let (just_created, change) = o.get_mut();
|
||||||
.and_modify(|(change, just_created)| {
|
match (&mut change.change, just_created, changed_file.change) {
|
||||||
// None -> Delete => keep
|
|
||||||
// Create -> Delete => collapse
|
|
||||||
//
|
|
||||||
match (change, just_created, changed_file.change_kind) {
|
|
||||||
// latter `Delete` wins
|
// latter `Delete` wins
|
||||||
(change, _, Delete) => *change = Delete,
|
(change, _, Delete) => *change = Delete,
|
||||||
// merge `Create` with `Create` or `Modify`
|
// merge `Create` with `Create` or `Modify`
|
||||||
(Create, _, Create | Modify) => {}
|
(Create(prev), _, Create(new) | Modify(new)) => *prev = new,
|
||||||
// collapse identical `Modify`es
|
// collapse identical `Modify`es
|
||||||
(Modify, _, Modify) => {}
|
(Modify(prev), _, Modify(new)) => *prev = new,
|
||||||
// equivalent to `Modify`
|
// equivalent to `Modify`
|
||||||
(change @ Delete, just_created, Create) => {
|
(change @ Delete, just_created, Create(new)) => {
|
||||||
*change = Modify;
|
*change = Modify(new);
|
||||||
*just_created = true;
|
*just_created = true;
|
||||||
}
|
}
|
||||||
// shouldn't occur, but collapse into `Create`
|
// shouldn't occur, but collapse into `Create`
|
||||||
(change @ Delete, just_created, Modify) => {
|
(change @ Delete, just_created, Modify(new)) => {
|
||||||
*change = Create;
|
*change = Create(new);
|
||||||
*just_created = true;
|
*just_created = true;
|
||||||
}
|
}
|
||||||
// shouldn't occur, but collapse into `Modify`
|
// shouldn't occur, but keep the Create
|
||||||
(Modify, _, Create) => {}
|
(prev @ Modify(_), _, new @ Create(_)) => *prev = new,
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.or_insert((
|
Entry::Vacant(v) => {
|
||||||
changed_file.change_kind,
|
_ = v.insert((matches!(&changed_file.change, Create(_)), changed_file))
|
||||||
matches!(changed_file.change_kind, Create),
|
}
|
||||||
));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let changed_files: Vec<_> = file_changes
|
let changed_files: Vec<_> = file_changes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, (change_kind, just_created))| {
|
.filter(|(_, (just_created, change))| {
|
||||||
!matches!((change_kind, just_created), (vfs::ChangeKind::Delete, true))
|
!(*just_created && matches!(change.change, vfs::Change::Delete))
|
||||||
})
|
})
|
||||||
.map(|(file_id, (change_kind, _))| vfs::ChangedFile { file_id, change_kind })
|
.map(|(file_id, (_, change))| vfs::ChangedFile { file_id, ..change })
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut workspace_structure_change = None;
|
let mut workspace_structure_change = None;
|
||||||
// A file was added or deleted
|
// A file was added or deleted
|
||||||
let mut has_structure_changes = false;
|
let mut has_structure_changes = false;
|
||||||
let mut bytes = vec![];
|
let mut bytes = vec![];
|
||||||
for file in &changed_files {
|
let mut modified_rust_files = vec![];
|
||||||
|
for file in changed_files {
|
||||||
let vfs_path = &vfs.file_path(file.file_id);
|
let vfs_path = &vfs.file_path(file.file_id);
|
||||||
if let Some(path) = vfs_path.as_path() {
|
if let Some(path) = vfs_path.as_path() {
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
if reload::should_refresh_for_change(&path, file.change_kind) {
|
if reload::should_refresh_for_change(&path, file.kind()) {
|
||||||
workspace_structure_change = Some((path.clone(), false));
|
workspace_structure_change = Some((path.clone(), false));
|
||||||
}
|
}
|
||||||
if file.is_created_or_deleted() {
|
if file.is_created_or_deleted() {
|
||||||
has_structure_changes = true;
|
has_structure_changes = true;
|
||||||
workspace_structure_change =
|
workspace_structure_change =
|
||||||
Some((path, self.crate_graph_file_dependencies.contains(vfs_path)));
|
Some((path, self.crate_graph_file_dependencies.contains(vfs_path)));
|
||||||
|
} else if path.extension() == Some("rs".as_ref()) {
|
||||||
|
modified_rust_files.push(file.file_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,10 +298,8 @@ impl GlobalState {
|
|||||||
self.diagnostics.clear_native_for(file.file_id);
|
self.diagnostics.clear_native_for(file.file_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = if file.exists() {
|
let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
|
||||||
let bytes = vfs.file_contents(file.file_id).to_vec();
|
String::from_utf8(v).ok().and_then(|text| {
|
||||||
|
|
||||||
String::from_utf8(bytes).ok().and_then(|text| {
|
|
||||||
// FIXME: Consider doing normalization in the `vfs` instead? That allows
|
// FIXME: Consider doing normalization in the `vfs` instead? That allows
|
||||||
// getting rid of some locking
|
// getting rid of some locking
|
||||||
let (text, line_endings) = LineEndings::normalize(text);
|
let (text, line_endings) = LineEndings::normalize(text);
|
||||||
@ -327,11 +324,10 @@ impl GlobalState {
|
|||||||
let roots = self.source_root_config.partition(vfs);
|
let roots = self.source_root_config.partition(vfs);
|
||||||
change.set_roots(roots);
|
change.set_roots(roots);
|
||||||
}
|
}
|
||||||
(change, changed_files, workspace_structure_change)
|
(change, modified_rust_files, workspace_structure_change)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.analysis_host.apply_change(change);
|
self.analysis_host.apply_change(change);
|
||||||
|
|
||||||
{
|
{
|
||||||
let raw_database = self.analysis_host.raw_database();
|
let raw_database = self.analysis_host.raw_database();
|
||||||
// FIXME: ideally we should only trigger a workspace fetch for non-library changes
|
// FIXME: ideally we should only trigger a workspace fetch for non-library changes
|
||||||
@ -343,13 +339,12 @@ impl GlobalState {
|
|||||||
force_crate_graph_reload,
|
force_crate_graph_reload,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.proc_macro_changed =
|
self.proc_macro_changed = modified_rust_files.into_iter().any(|file_id| {
|
||||||
changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
|
let crates = raw_database.relevant_crates(file_id);
|
||||||
let crates = raw_database.relevant_crates(file.file_id);
|
let crate_graph = raw_database.crate_graph();
|
||||||
let crate_graph = raw_database.crate_graph();
|
|
||||||
|
|
||||||
crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
|
crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
@ -494,10 +489,6 @@ impl GlobalStateSnapshot {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn vfs_memory_usage(&self) -> usize {
|
|
||||||
self.vfs_read().memory_usage()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
|
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
|
||||||
self.vfs.read().0.exists(file_id)
|
self.vfs.read().0.exists(file_id)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,13 @@ pub(crate) fn handle_did_open_text_document(
|
|||||||
if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
||||||
let already_exists = state
|
let already_exists = state
|
||||||
.mem_docs
|
.mem_docs
|
||||||
.insert(path.clone(), DocumentData::new(params.text_document.version))
|
.insert(
|
||||||
|
path.clone(),
|
||||||
|
DocumentData::new(
|
||||||
|
params.text_document.version,
|
||||||
|
params.text_document.text.clone().into_bytes(),
|
||||||
|
),
|
||||||
|
)
|
||||||
.is_err();
|
.is_err();
|
||||||
if already_exists {
|
if already_exists {
|
||||||
tracing::error!("duplicate DidOpenTextDocument: {}", path);
|
tracing::error!("duplicate DidOpenTextDocument: {}", path);
|
||||||
@ -76,11 +82,12 @@ pub(crate) fn handle_did_change_text_document(
|
|||||||
let _p = profile::span("handle_did_change_text_document");
|
let _p = profile::span("handle_did_change_text_document");
|
||||||
|
|
||||||
if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
||||||
match state.mem_docs.get_mut(&path) {
|
let data = match state.mem_docs.get_mut(&path) {
|
||||||
Some(doc) => {
|
Some(doc) => {
|
||||||
// The version passed in DidChangeTextDocument is the version after all edits are applied
|
// The version passed in DidChangeTextDocument is the version after all edits are applied
|
||||||
// so we should apply it before the vfs is notified.
|
// so we should apply it before the vfs is notified.
|
||||||
doc.version = params.text_document.version;
|
doc.version = params.text_document.version;
|
||||||
|
&mut doc.data
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
tracing::error!("unexpected DidChangeTextDocument: {}", path);
|
tracing::error!("unexpected DidChangeTextDocument: {}", path);
|
||||||
@ -88,16 +95,16 @@ pub(crate) fn handle_did_change_text_document(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let text = apply_document_changes(
|
let new_contents = apply_document_changes(
|
||||||
state.config.position_encoding(),
|
state.config.position_encoding(),
|
||||||
|| {
|
std::str::from_utf8(data).unwrap(),
|
||||||
let vfs = &state.vfs.read().0;
|
|
||||||
let file_id = vfs.file_id(&path).unwrap();
|
|
||||||
std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into()
|
|
||||||
},
|
|
||||||
params.content_changes,
|
params.content_changes,
|
||||||
);
|
)
|
||||||
state.vfs.write().0.set_file_contents(path, Some(text.into_bytes()));
|
.into_bytes();
|
||||||
|
if *data != new_contents {
|
||||||
|
*data = new_contents.clone();
|
||||||
|
state.vfs.write().0.set_file_contents(path, Some(new_contents));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@ pub(crate) fn handle_analyzer_status(
|
|||||||
.collect::<Vec<&AbsPath>>()
|
.collect::<Vec<&AbsPath>>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
format_to!(buf, "\nVfs memory usage: {}\n", profile::Bytes::new(snap.vfs_memory_usage() as _));
|
|
||||||
buf.push_str("\nAnalysis:\n");
|
buf.push_str("\nAnalysis:\n");
|
||||||
buf.push_str(
|
buf.push_str(
|
||||||
&snap
|
&snap
|
||||||
|
@ -168,7 +168,7 @@ impl GlobalState {
|
|||||||
|
|
||||||
pub(crate) fn apply_document_changes(
|
pub(crate) fn apply_document_changes(
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
file_contents: impl FnOnce() -> String,
|
file_contents: &str,
|
||||||
mut content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
|
mut content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
|
||||||
) -> String {
|
) -> String {
|
||||||
// If at least one of the changes is a full document change, use the last
|
// If at least one of the changes is a full document change, use the last
|
||||||
@ -179,7 +179,7 @@ pub(crate) fn apply_document_changes(
|
|||||||
let text = mem::take(&mut content_changes[idx].text);
|
let text = mem::take(&mut content_changes[idx].text);
|
||||||
(text, &content_changes[idx + 1..])
|
(text, &content_changes[idx + 1..])
|
||||||
}
|
}
|
||||||
None => (file_contents(), &content_changes[..]),
|
None => (file_contents.to_owned(), &content_changes[..]),
|
||||||
};
|
};
|
||||||
if content_changes.is_empty() {
|
if content_changes.is_empty() {
|
||||||
return text;
|
return text;
|
||||||
@ -276,11 +276,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let encoding = PositionEncoding::Wide(WideEncoding::Utf16);
|
let encoding = PositionEncoding::Wide(WideEncoding::Utf16);
|
||||||
let text = apply_document_changes(encoding, || String::new(), vec![]);
|
let text = apply_document_changes(encoding, "", vec![]);
|
||||||
assert_eq!(text, "");
|
assert_eq!(text, "");
|
||||||
let text = apply_document_changes(
|
let text = apply_document_changes(
|
||||||
encoding,
|
encoding,
|
||||||
|| text,
|
&text,
|
||||||
vec![TextDocumentContentChangeEvent {
|
vec![TextDocumentContentChangeEvent {
|
||||||
range: None,
|
range: None,
|
||||||
range_length: None,
|
range_length: None,
|
||||||
@ -288,49 +288,46 @@ mod tests {
|
|||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
assert_eq!(text, "the");
|
assert_eq!(text, "the");
|
||||||
let text = apply_document_changes(encoding, || text, c![0, 3; 0, 3 => " quick"]);
|
let text = apply_document_changes(encoding, &text, c![0, 3; 0, 3 => " quick"]);
|
||||||
assert_eq!(text, "the quick");
|
assert_eq!(text, "the quick");
|
||||||
let text =
|
let text =
|
||||||
apply_document_changes(encoding, || text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
|
apply_document_changes(encoding, &text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
|
||||||
assert_eq!(text, "quick foxes");
|
assert_eq!(text, "quick foxes");
|
||||||
let text = apply_document_changes(encoding, || text, c![0, 11; 0, 11 => "\ndream"]);
|
let text = apply_document_changes(encoding, &text, c![0, 11; 0, 11 => "\ndream"]);
|
||||||
assert_eq!(text, "quick foxes\ndream");
|
assert_eq!(text, "quick foxes\ndream");
|
||||||
let text = apply_document_changes(encoding, || text, c![1, 0; 1, 0 => "have "]);
|
let text = apply_document_changes(encoding, &text, c![1, 0; 1, 0 => "have "]);
|
||||||
assert_eq!(text, "quick foxes\nhave dream");
|
assert_eq!(text, "quick foxes\nhave dream");
|
||||||
let text = apply_document_changes(
|
let text = apply_document_changes(
|
||||||
encoding,
|
encoding,
|
||||||
|| text,
|
&text,
|
||||||
c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
|
c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
|
||||||
);
|
);
|
||||||
assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
|
assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
|
||||||
let text = apply_document_changes(
|
let text =
|
||||||
encoding,
|
apply_document_changes(encoding, &text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
|
||||||
|| text,
|
|
||||||
c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"],
|
|
||||||
);
|
|
||||||
assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
|
assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
|
||||||
let text = apply_document_changes(
|
let text = apply_document_changes(
|
||||||
encoding,
|
encoding,
|
||||||
|| text,
|
&text,
|
||||||
c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
|
c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
|
||||||
);
|
);
|
||||||
assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
|
assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
|
||||||
let text =
|
let text =
|
||||||
apply_document_changes(encoding, || text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
|
apply_document_changes(encoding, &text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
|
||||||
assert_eq!(text, "the quick \nthey have quiet dreams\n");
|
assert_eq!(text, "the quick \nthey have quiet dreams\n");
|
||||||
|
|
||||||
let text = String::from("❤️");
|
let text = String::from("❤️");
|
||||||
let text = apply_document_changes(encoding, || text, c![0, 0; 0, 0 => "a"]);
|
let text = apply_document_changes(encoding, &text, c![0, 0; 0, 0 => "a"]);
|
||||||
assert_eq!(text, "a❤️");
|
assert_eq!(text, "a❤️");
|
||||||
|
|
||||||
let text = String::from("a\nb");
|
let text = String::from("a\nb");
|
||||||
let text =
|
let text =
|
||||||
apply_document_changes(encoding, || text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
|
apply_document_changes(encoding, &text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
|
||||||
assert_eq!(text, "adcb");
|
assert_eq!(text, "adcb");
|
||||||
|
|
||||||
let text = String::from("a\nb");
|
let text = String::from("a\nb");
|
||||||
let text =
|
let text =
|
||||||
apply_document_changes(encoding, || text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
|
apply_document_changes(encoding, &text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
|
||||||
assert_eq!(text, "ațc\ncb");
|
assert_eq!(text, "ațc\ncb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,13 +571,18 @@ impl GlobalState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
|
fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
|
||||||
|
let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
|
||||||
match message {
|
match message {
|
||||||
vfs::loader::Message::Loaded { files } => {
|
vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
|
||||||
let vfs = &mut self.vfs.write().0;
|
let vfs = &mut self.vfs.write().0;
|
||||||
for (path, contents) in files {
|
for (path, contents) in files {
|
||||||
let path = VfsPath::from(path);
|
let path = VfsPath::from(path);
|
||||||
|
// if the file is in mem docs, it's managed by the client via notifications
|
||||||
|
// so only set it if its not in there
|
||||||
if !self.mem_docs.contains(&path) {
|
if !self.mem_docs.contains(&path) {
|
||||||
vfs.set_file_contents(path, contents);
|
if is_changed || vfs.file_id(&path).is_none() {
|
||||||
|
vfs.set_file_contents(path, contents);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,10 +62,11 @@ impl MemDocs {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct DocumentData {
|
pub(crate) struct DocumentData {
|
||||||
pub(crate) version: i32,
|
pub(crate) version: i32,
|
||||||
|
pub(crate) data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentData {
|
impl DocumentData {
|
||||||
pub(crate) fn new(version: i32) -> Self {
|
pub(crate) fn new(version: i32, data: Vec<u8>) -> Self {
|
||||||
DocumentData { version }
|
DocumentData { version, data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -503,10 +503,9 @@ impl GlobalState {
|
|||||||
match vfs.file_id(&vfs_path) {
|
match vfs.file_id(&vfs_path) {
|
||||||
Some(file_id) => Some(file_id),
|
Some(file_id) => Some(file_id),
|
||||||
None => {
|
None => {
|
||||||
if !self.mem_docs.contains(&vfs_path) {
|
// FIXME: Consider not loading this here?
|
||||||
let contents = loader.handle.load_sync(path);
|
let contents = loader.handle.load_sync(path);
|
||||||
vfs.set_file_contents(vfs_path.clone(), contents);
|
vfs.set_file_contents(vfs_path.clone(), contents);
|
||||||
}
|
|
||||||
vfs.file_id(&vfs_path)
|
vfs.file_id(&vfs_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "rustc-dependencies"
|
|
||||||
version = "0.0.0"
|
|
||||||
description = "TBD"
|
|
||||||
|
|
||||||
rust-version.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
authors.workspace = true
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
ra-ap-rustc_lexer = { version = "0.21.0" }
|
|
||||||
ra-ap-rustc_parse_format = { version = "0.21.0", default-features = false }
|
|
||||||
ra-ap-rustc_index = { version = "0.21.0", default-features = false }
|
|
||||||
ra-ap-rustc_abi = { version = "0.21.0", default-features = false }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
in-rust-tree = []
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
@ -1,48 +0,0 @@
|
|||||||
//! A wrapper around rustc internal crates, which enables switching between compiler provided
|
|
||||||
//! ones and stable ones published in crates.io
|
|
||||||
|
|
||||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
extern crate rustc_lexer;
|
|
||||||
|
|
||||||
pub mod lexer {
|
|
||||||
#[cfg(not(feature = "in-rust-tree"))]
|
|
||||||
pub use ::ra_ap_rustc_lexer::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
pub use ::rustc_lexer::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
extern crate rustc_parse_format;
|
|
||||||
|
|
||||||
pub mod parse_format {
|
|
||||||
#[cfg(not(feature = "in-rust-tree"))]
|
|
||||||
pub use ::ra_ap_rustc_parse_format::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
pub use ::rustc_parse_format::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
extern crate rustc_abi;
|
|
||||||
|
|
||||||
pub mod abi {
|
|
||||||
#[cfg(not(feature = "in-rust-tree"))]
|
|
||||||
pub use ::ra_ap_rustc_abi::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
pub use ::rustc_abi::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
extern crate rustc_index;
|
|
||||||
|
|
||||||
pub mod index {
|
|
||||||
#[cfg(not(feature = "in-rust-tree"))]
|
|
||||||
pub use ::ra_ap_rustc_index::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "in-rust-tree")]
|
|
||||||
pub use ::rustc_index::*;
|
|
||||||
}
|
|
@ -23,7 +23,7 @@ indexmap.workspace = true
|
|||||||
smol_str.workspace = true
|
smol_str.workspace = true
|
||||||
triomphe.workspace = true
|
triomphe.workspace = true
|
||||||
|
|
||||||
rustc-dependencies.workspace = true
|
ra-ap-rustc_lexer.workspace = true
|
||||||
|
|
||||||
parser.workspace = true
|
parser.workspace = true
|
||||||
profile.workspace = true
|
profile.workspace = true
|
||||||
@ -41,7 +41,7 @@ test-utils.workspace = true
|
|||||||
sourcegen.workspace = true
|
sourcegen.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
in-rust-tree = []
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -285,14 +285,16 @@ impl ast::Path {
|
|||||||
self.first_qualifier_or_self().segment()
|
self.first_qualifier_or_self().segment()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Check usages of Self::segments, they might be wrong because of the logic of the bloew function
|
|
||||||
pub fn segments_of_this_path_only_rev(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
|
|
||||||
self.qualifiers_and_self().filter_map(|it| it.segment())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
|
pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
|
||||||
successors(self.first_segment(), |p| {
|
let path_range = self.syntax().text_range();
|
||||||
p.parent_path().parent_path().and_then(|p| p.segment())
|
successors(self.first_segment(), move |p| {
|
||||||
|
p.parent_path().parent_path().and_then(|p| {
|
||||||
|
if path_range.contains_range(p.syntax().text_range()) {
|
||||||
|
p.segment()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,10 +302,6 @@ impl ast::Path {
|
|||||||
successors(self.qualifier(), |p| p.qualifier())
|
successors(self.qualifier(), |p| p.qualifier())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn qualifiers_and_self(&self) -> impl Iterator<Item = ast::Path> + Clone {
|
|
||||||
successors(Some(self.clone()), |p| p.qualifier())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top_path(&self) -> ast::Path {
|
pub fn top_path(&self) -> ast::Path {
|
||||||
let mut this = self.clone();
|
let mut this = self.clone();
|
||||||
while let Some(path) = this.parent_path() {
|
while let Some(path) = this.parent_path() {
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc_dependencies::lexer as rustc_lexer;
|
|
||||||
|
|
||||||
use rustc_lexer::unescape::{
|
use rustc_lexer::unescape::{
|
||||||
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
||||||
};
|
};
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||||
|
|
||||||
|
#[cfg(not(feature = "in-rust-tree"))]
|
||||||
|
extern crate ra_ap_rustc_lexer as rustc_lexer;
|
||||||
|
#[cfg(feature = "in-rust-tree")]
|
||||||
|
extern crate rustc_lexer;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
macro_rules! eprintln {
|
macro_rules! eprintln {
|
||||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
mod block;
|
mod block;
|
||||||
|
|
||||||
use rowan::Direction;
|
use rowan::Direction;
|
||||||
use rustc_dependencies::lexer::unescape::{self, unescape_literal, Mode};
|
use rustc_lexer::unescape::{self, unescape_literal, Mode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algo,
|
algo,
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
//! derive:
|
//! derive:
|
||||||
//! discriminant:
|
//! discriminant:
|
||||||
//! drop:
|
//! drop:
|
||||||
|
//! env: option
|
||||||
//! eq: sized
|
//! eq: sized
|
||||||
//! error: fmt
|
//! error: fmt
|
||||||
//! fmt: result, transmute, coerce_unsized
|
//! fmt: result, transmute, coerce_unsized
|
||||||
@ -1450,6 +1451,15 @@ mod macros {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! concat {}
|
macro_rules! concat {}
|
||||||
// endregion:concat
|
// endregion:concat
|
||||||
|
|
||||||
|
// region:env
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! env {}
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! option_env {}
|
||||||
|
// endregion:env
|
||||||
}
|
}
|
||||||
|
|
||||||
// region:non_zero
|
// region:non_zero
|
||||||
|
@ -160,7 +160,7 @@ impl NotifyActor {
|
|||||||
Some((path, contents))
|
Some((path, contents))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.send(loader::Message::Loaded { files });
|
self.send(loader::Message::Changed { files });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user