mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +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",
|
||||
"once_cell",
|
||||
"profile",
|
||||
"rustc-dependencies",
|
||||
"ra-ap-rustc_abi",
|
||||
"ra-ap-rustc_parse_format",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
"span",
|
||||
@ -579,7 +580,8 @@ dependencies = [
|
||||
"oorandom",
|
||||
"profile",
|
||||
"project-model",
|
||||
"rustc-dependencies",
|
||||
"ra-ap-rustc_abi",
|
||||
"ra-ap-rustc_index",
|
||||
"rustc-hash",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
@ -1196,7 +1198,7 @@ dependencies = [
|
||||
"drop_bomb",
|
||||
"expect-test",
|
||||
"limit",
|
||||
"rustc-dependencies",
|
||||
"ra-ap-rustc_lexer",
|
||||
"sourcegen",
|
||||
"stdx",
|
||||
]
|
||||
@ -1540,7 +1542,6 @@ dependencies = [
|
||||
"profile",
|
||||
"project-model",
|
||||
"rayon",
|
||||
"rustc-dependencies",
|
||||
"rustc-hash",
|
||||
"scip",
|
||||
"serde",
|
||||
@ -1567,9 +1568,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
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"
|
||||
checksum = "16c42b8737c320578b441a82daf7cdf8d897468de64e8a774fa54b53a50b6cc0"
|
||||
checksum = "ca9d387a9801f4fb9b366789ad1bfc08448cafc49cf148d907cfcd88ab665d7f"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"lock_api",
|
||||
@ -1579,13 +1580,14 @@ dependencies = [
|
||||
"rust-analyzer-salsa-macros",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
"triomphe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
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"
|
||||
checksum = "db72b0883f3592ade2be15a10583c75e0b269ec26e1190800fda2e2ce5ae6634"
|
||||
checksum = "a2035f385d7fae31e9b086f40b272ee1d79c484472f31c9a10348a406e841eaf"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -1599,16 +1601,6 @@ version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@ -1751,6 +1743,12 @@ dependencies = [
|
||||
"vfs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@ -1808,9 +1806,9 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"profile",
|
||||
"quote",
|
||||
"ra-ap-rustc_lexer",
|
||||
"rayon",
|
||||
"rowan",
|
||||
"rustc-dependencies",
|
||||
"rustc-hash",
|
||||
"smol_str",
|
||||
"sourcegen",
|
||||
@ -2028,9 +2026,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "triomphe"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c5a71827ac326072b6405552093e2ad2accd25a32fd78d4edc82d98c7f2409"
|
||||
checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tt"
|
||||
|
@ -78,7 +78,11 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" }
|
||||
tt = { path = "./crates/tt", version = "0.0.0" }
|
||||
vfs-notify = { path = "./crates/vfs-notify", 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.
|
||||
sourcegen = { path = "./crates/sourcegen" }
|
||||
@ -108,7 +112,7 @@ itertools = "0.12.0"
|
||||
libc = "0.2.150"
|
||||
nohash-hasher = "0.2.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"
|
||||
semver = "1.0.14"
|
||||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
|
@ -7,7 +7,6 @@ mod change;
|
||||
|
||||
use std::panic;
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{ast, Parse, SourceFile};
|
||||
use triomphe::Arc;
|
||||
|
||||
@ -44,12 +43,13 @@ pub trait Upcast<T: ?Sized> {
|
||||
}
|
||||
|
||||
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
|
||||
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 256;
|
||||
|
||||
pub trait FileLoader {
|
||||
/// Text of the file.
|
||||
fn file_text(&self, file_id: FileId) -> Arc<str>;
|
||||
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
|
||||
@ -84,19 +84,21 @@ pub trait SourceDatabaseExt: SourceDatabase {
|
||||
#[salsa::input]
|
||||
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 res = graph
|
||||
let mut crates = graph
|
||||
.iter()
|
||||
.filter(|&krate| {
|
||||
let root_file = graph[krate].root_file_id;
|
||||
db.file_source_root(root_file) == id
|
||||
})
|
||||
.collect();
|
||||
Arc::new(res)
|
||||
.collect::<Vec<_>>();
|
||||
crates.sort();
|
||||
crates.dedup();
|
||||
crates.into_iter().collect()
|
||||
}
|
||||
|
||||
/// Silly workaround for cyclic deps between the traits
|
||||
@ -113,7 +115,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
|
||||
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 source_root = self.0.file_source_root(file_id);
|
||||
self.0.source_root_crates(source_root)
|
||||
|
@ -29,7 +29,8 @@ smallvec.workspace = true
|
||||
hashbrown.workspace = true
|
||||
triomphe.workspace = true
|
||||
|
||||
rustc-dependencies.workspace = true
|
||||
ra-ap-rustc_parse_format.workspace = true
|
||||
ra-ap-rustc_abi.workspace = true
|
||||
|
||||
# local deps
|
||||
stdx.workspace = true
|
||||
@ -53,7 +54,7 @@ test-utils.workspace = true
|
||||
test-fixture.workspace = true
|
||||
|
||||
[features]
|
||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
||||
in-rust-tree = []
|
||||
|
||||
[lints]
|
||||
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> + '_ {
|
||||
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 {
|
||||
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 }
|
||||
}
|
||||
|
||||
|
@ -965,11 +965,10 @@ impl ExprCollector<'_> {
|
||||
|
||||
let res = match self.def_map.modules[module]
|
||||
.scope
|
||||
.macro_invocations
|
||||
.get(&InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr)))
|
||||
.macro_invoc(InFile::new(outer_file, self.ast_id_map.ast_id_for_ptr(syntax_ptr)))
|
||||
{
|
||||
// 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| {
|
||||
self.def_map
|
||||
.resolve_path(
|
||||
|
@ -92,7 +92,7 @@ impl ChildBySource for ItemScope {
|
||||
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.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);
|
||||
if loc.id.file_id() == file_id {
|
||||
res[keys::CONST].insert(loc.source(db).value, konst);
|
||||
|
@ -11,7 +11,7 @@ use hir_expand::{
|
||||
};
|
||||
use intern::Interned;
|
||||
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 triomphe::Arc;
|
||||
|
||||
|
@ -210,13 +210,10 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
||||
#[salsa::invoke(AttrsWithOwner::attrs_query)]
|
||||
fn attrs(&self, def: AttrDefId) -> Attrs;
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(lang_item::lang_attr_query)]
|
||||
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
|
||||
|
||||
#[salsa::invoke(LangItems::lang_item_query)]
|
||||
@ -240,7 +237,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
||||
// endregion:visibilities
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
item_scope::ItemInNs,
|
||||
nameres::DefMap,
|
||||
path::{ModPath, PathKind},
|
||||
visibility::Visibility,
|
||||
visibility::{Visibility, VisibilityExplicity},
|
||||
CrateRootModuleId, ModuleDefId, ModuleId,
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@ pub fn find_path(
|
||||
prefer_prelude: bool,
|
||||
) -> Option<ModPath> {
|
||||
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(
|
||||
@ -36,7 +36,11 @@ pub fn find_path_prefixed(
|
||||
prefer_prelude: bool,
|
||||
) -> Option<ModPath> {
|
||||
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)]
|
||||
@ -83,64 +87,60 @@ impl PrefixKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
|
||||
fn find_path_inner(
|
||||
db: &dyn DefDatabase,
|
||||
item: ItemInNs,
|
||||
from: ModuleId,
|
||||
#[derive(Copy, Clone)]
|
||||
struct FindPathCtx<'db> {
|
||||
db: &'db dyn DefDatabase,
|
||||
prefixed: Option<PrefixKind>,
|
||||
prefer_no_std: 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 let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
|
||||
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();
|
||||
// - if the item is a module, jump straight to module search
|
||||
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
|
||||
let mut visited_modules = FxHashSet::default();
|
||||
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,
|
||||
&mut visited_modules,
|
||||
crate_root,
|
||||
from,
|
||||
module_id,
|
||||
MAX_PATH_LEN,
|
||||
prefixed,
|
||||
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
||||
prefer_prelude,
|
||||
)
|
||||
.map(|(item, _)| item);
|
||||
}
|
||||
|
||||
// - 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);
|
||||
if prefixed.is_none() {
|
||||
let scope_name = find_in_scope(ctx.db, &def_map, from, item);
|
||||
if ctx.prefixed.is_none() {
|
||||
if let Some(scope_name) = 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 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;
|
||||
}
|
||||
|
||||
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 let Some(mut path) = find_path_inner(
|
||||
db,
|
||||
ItemInNs::Types(variant.parent.into()),
|
||||
from,
|
||||
prefixed,
|
||||
prefer_no_std,
|
||||
prefer_prelude,
|
||||
) {
|
||||
let data = db.enum_data(variant.parent);
|
||||
if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(variant.parent.into()), from) {
|
||||
let data = ctx.db.enum_data(variant.parent);
|
||||
path.push_segment(data.variants[variant.local_id].name.clone());
|
||||
return Some(path);
|
||||
}
|
||||
@ -152,32 +152,29 @@ fn find_path_inner(
|
||||
let mut visited_modules = FxHashSet::default();
|
||||
|
||||
calculate_best_path(
|
||||
db,
|
||||
FindPathCtx {
|
||||
prefer_no_std: ctx.prefer_no_std || ctx.db.crate_supports_no_std(crate_root.krate),
|
||||
..ctx
|
||||
},
|
||||
&def_map,
|
||||
&mut visited_modules,
|
||||
crate_root,
|
||||
MAX_PATH_LEN,
|
||||
item,
|
||||
from,
|
||||
prefixed,
|
||||
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
|
||||
prefer_prelude,
|
||||
scope_name,
|
||||
)
|
||||
.map(|(item, _)| item)
|
||||
}
|
||||
|
||||
fn find_path_for_module(
|
||||
db: &dyn DefDatabase,
|
||||
ctx: FindPathCtx<'_>,
|
||||
def_map: &DefMap,
|
||||
visited_modules: &mut FxHashSet<ModuleId>,
|
||||
crate_root: CrateRootModuleId,
|
||||
from: ModuleId,
|
||||
module_id: ModuleId,
|
||||
max_len: usize,
|
||||
prefixed: Option<PrefixKind>,
|
||||
prefer_no_std: bool,
|
||||
prefer_prelude: bool,
|
||||
) -> Option<(ModPath, Stability)> {
|
||||
if max_len == 0 {
|
||||
return None;
|
||||
@ -185,8 +182,8 @@ fn find_path_for_module(
|
||||
|
||||
// Base cases:
|
||||
// - 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()));
|
||||
if prefixed.is_none() {
|
||||
let scope_name = find_in_scope(ctx.db, def_map, from, ItemInNs::Types(module_id.into()));
|
||||
if ctx.prefixed.is_none() {
|
||||
if let Some(scope_name) = scope_name {
|
||||
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 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) {
|
||||
return modpath.zip(Some(Stable));
|
||||
}
|
||||
}
|
||||
|
||||
// - 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() {
|
||||
if module_id == def_id {
|
||||
let name = scope_name.unwrap_or_else(|| name.clone());
|
||||
|
||||
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]
|
||||
.scope
|
||||
.type_(&name)
|
||||
@ -229,21 +226,18 @@ fn find_path_for_module(
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
calculate_best_path(
|
||||
db,
|
||||
ctx,
|
||||
def_map,
|
||||
visited_modules,
|
||||
crate_root,
|
||||
max_len,
|
||||
ItemInNs::Types(module_id.into()),
|
||||
from,
|
||||
prefixed,
|
||||
prefer_no_std,
|
||||
prefer_prelude,
|
||||
scope_name,
|
||||
)
|
||||
}
|
||||
@ -256,7 +250,7 @@ fn find_in_scope(
|
||||
item: ItemInNs,
|
||||
) -> Option<Name> {
|
||||
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
|
||||
let prelude_def_map = prelude_module.def_map(db);
|
||||
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) {
|
||||
return None;
|
||||
}
|
||||
@ -315,16 +309,13 @@ fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<M
|
||||
}
|
||||
|
||||
fn calculate_best_path(
|
||||
db: &dyn DefDatabase,
|
||||
ctx: FindPathCtx<'_>,
|
||||
def_map: &DefMap,
|
||||
visited_modules: &mut FxHashSet<ModuleId>,
|
||||
crate_root: CrateRootModuleId,
|
||||
max_len: usize,
|
||||
item: ItemInNs,
|
||||
from: ModuleId,
|
||||
mut prefixed: Option<PrefixKind>,
|
||||
prefer_no_std: bool,
|
||||
prefer_prelude: bool,
|
||||
scope_name: Option<Name>,
|
||||
) -> Option<(ModPath, Stability)> {
|
||||
if max_len <= 1 {
|
||||
@ -341,32 +332,29 @@ fn calculate_best_path(
|
||||
};
|
||||
// Recursive case:
|
||||
// - 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;
|
||||
// Item was defined in the same crate that wants to import it. It cannot be found in any
|
||||
// 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) {
|
||||
cov_mark::hit!(recursive_imports);
|
||||
continue;
|
||||
}
|
||||
if let Some(mut path) = find_path_for_module(
|
||||
db,
|
||||
ctx,
|
||||
def_map,
|
||||
visited_modules,
|
||||
crate_root,
|
||||
from,
|
||||
module_id,
|
||||
best_path_len - 1,
|
||||
prefixed,
|
||||
prefer_no_std,
|
||||
prefer_prelude,
|
||||
) {
|
||||
path.0.push_segment(name);
|
||||
|
||||
let new_path = match best_path.take() {
|
||||
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,
|
||||
};
|
||||
@ -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
|
||||
// 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 {
|
||||
let import_map = db.import_map(dep.crate_id);
|
||||
for dep in &ctx.db.crate_graph()[from.krate].dependencies {
|
||||
let import_map = ctx.db.import_map(dep.crate_id);
|
||||
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
|
||||
for info in import_info_for {
|
||||
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`.
|
||||
// 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(
|
||||
db,
|
||||
ctx,
|
||||
def_map,
|
||||
visited_modules,
|
||||
crate_root,
|
||||
from,
|
||||
info.container,
|
||||
max_len - 1,
|
||||
prefixed,
|
||||
prefer_no_std,
|
||||
prefer_prelude,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
@ -413,17 +398,21 @@ fn calculate_best_path(
|
||||
);
|
||||
|
||||
let new_path_with_stab = match best_path.take() {
|
||||
Some(best_path) => {
|
||||
select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude)
|
||||
}
|
||||
Some(best_path) => select_best_path(
|
||||
best_path,
|
||||
path_with_stab,
|
||||
ctx.prefer_no_std,
|
||||
ctx.prefer_prelude,
|
||||
),
|
||||
None => path_with_stab,
|
||||
};
|
||||
update_best_path(&mut best_path, new_path_with_stab);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(module) = item.module(db) {
|
||||
if module.containing_block().is_some() && prefixed.is_some() {
|
||||
let mut prefixed = ctx.prefixed;
|
||||
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);
|
||||
prefixed = Some(PrefixKind::Plain);
|
||||
}
|
||||
@ -548,34 +537,35 @@ fn find_local_import_locations(
|
||||
&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) {
|
||||
let is_private = match vis {
|
||||
Visibility::Module(private_to) => private_to.local_id == module.local_id,
|
||||
Visibility::Public => false,
|
||||
};
|
||||
let is_original_def = match item.as_module_def_id() {
|
||||
Some(module_def_id) => data.scope.declarations().any(|it| it == module_def_id),
|
||||
None => false,
|
||||
let is_pub_or_explicit = match vis {
|
||||
Visibility::Module(_, VisibilityExplicity::Explicit) => {
|
||||
cov_mark::hit!(explicit_private_imports);
|
||||
true
|
||||
}
|
||||
Visibility::Module(_, VisibilityExplicity::Implicit) => {
|
||||
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
|
||||
// what the user wants; and if this module can import
|
||||
// the item and we're a submodule of it, so can we.
|
||||
// Also this keeps the cached data smaller.
|
||||
if !is_private || is_original_def {
|
||||
if is_pub_or_explicit || declared {
|
||||
locations.push((module, name.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Descend into all modules visible from `from`.
|
||||
for (ty, vis) in data.scope.types() {
|
||||
if let ModuleDefId::ModuleId(module) = ty {
|
||||
if vis.is_visible_from(db, from) {
|
||||
worklist.push(module);
|
||||
}
|
||||
for (module, vis) in data.scope.modules_in_scope() {
|
||||
if vis.is_visible_from(db, from) {
|
||||
worklist.push(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -625,16 +615,14 @@ mod tests {
|
||||
.expect("path does not resolve to a type");
|
||||
|
||||
let found_path = find_path_inner(
|
||||
&db,
|
||||
FindPathCtx { prefer_no_std: false, db: &db, prefixed: prefix_kind, prefer_prelude },
|
||||
ItemInNs::Types(resolved),
|
||||
module,
|
||||
prefix_kind,
|
||||
false,
|
||||
prefer_prelude,
|
||||
);
|
||||
assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn check_found_path(
|
||||
ra_fixture: &str,
|
||||
unprefixed: &str,
|
||||
@ -1004,6 +992,7 @@ pub use crate::foo::bar::S;
|
||||
|
||||
#[test]
|
||||
fn discount_private_imports() {
|
||||
cov_mark::check!(discount_private_imports);
|
||||
check_found_path(
|
||||
r#"
|
||||
//- /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]
|
||||
fn import_cycle() {
|
||||
check_found_path(
|
||||
|
@ -107,11 +107,11 @@ impl TypeOrConstParamData {
|
||||
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
|
||||
|
||||
/// 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 type_or_consts: Arena<TypeOrConstParamData>,
|
||||
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
|
||||
@ -142,109 +142,14 @@ pub enum WherePredicateTypeTarget {
|
||||
TypeOrConstParam(LocalTypeOrConstParamId),
|
||||
}
|
||||
|
||||
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 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct GenericParamsCollector {
|
||||
pub(crate) type_or_consts: Arena<TypeOrConstParamData>,
|
||||
lifetimes: Arena<LifetimeParamData>,
|
||||
where_predicates: Vec<WherePredicate>,
|
||||
}
|
||||
|
||||
impl GenericParamsCollector {
|
||||
pub(crate) fn fill(
|
||||
&mut self,
|
||||
lower_ctx: &LowerCtx<'_>,
|
||||
@ -444,11 +349,131 @@ impl GenericParams {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn shrink_to_fit(&mut self) {
|
||||
let Self { lifetimes, type_or_consts: types, where_predicates } = self;
|
||||
pub(crate) fn finish(self) -> GenericParams {
|
||||
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
|
||||
lifetimes.shrink_to_fit();
|
||||
types.shrink_to_fit();
|
||||
where_predicates.shrink_to_fit();
|
||||
type_or_consts.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> {
|
||||
|
@ -2,7 +2,7 @@
|
||||
use std::mem;
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use rustc_dependencies::parse_format as parse;
|
||||
use rustc_parse_format as parse;
|
||||
use stdx::TupleExt;
|
||||
use syntax::{
|
||||
ast::{self, IsString},
|
||||
|
@ -116,8 +116,7 @@ pub enum TypeRef {
|
||||
Path(Path),
|
||||
RawPtr(Box<TypeRef>, Mutability),
|
||||
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
|
||||
// FIXME: for full const generics, the latter element (length) here is going to have to be an
|
||||
// expression that is further lowered later in hir_ty.
|
||||
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
|
||||
Array(Box<TypeRef>, ConstRef),
|
||||
Slice(Box<TypeRef>),
|
||||
/// A fn pointer. Last element of the vector is the return type.
|
||||
|
@ -15,9 +15,11 @@ use stdx::format_to;
|
||||
use syntax::ast;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
|
||||
ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId,
|
||||
TraitId, UseId,
|
||||
db::DefDatabase,
|
||||
per_ns::PerNs,
|
||||
visibility::{Visibility, VisibilityExplicity},
|
||||
AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId,
|
||||
ModuleDefId, ModuleId, TraitId, UseId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -105,7 +107,7 @@ pub struct ItemScope {
|
||||
/// The attribute macro invocations in this scope.
|
||||
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
|
||||
/// 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
|
||||
/// paired with the derive macro invocations for the specific attribute.
|
||||
derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
|
||||
@ -145,8 +147,8 @@ impl ItemScope {
|
||||
.chain(self.values.keys())
|
||||
.chain(self.macros.keys())
|
||||
.chain(self.unresolved.iter())
|
||||
.unique()
|
||||
.sorted()
|
||||
.dedup()
|
||||
.map(move |name| (name, self.get(name)))
|
||||
}
|
||||
|
||||
@ -157,8 +159,8 @@ impl ItemScope {
|
||||
.filter_map(ImportOrExternCrate::into_import)
|
||||
.chain(self.use_imports_values.keys().copied())
|
||||
.chain(self.use_imports_macros.keys().copied())
|
||||
.unique()
|
||||
.sorted()
|
||||
.dedup()
|
||||
}
|
||||
|
||||
pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
|
||||
@ -234,20 +236,37 @@ impl ItemScope {
|
||||
self.impls.iter().copied()
|
||||
}
|
||||
|
||||
pub fn values(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
|
||||
self.values.values().copied().map(|(a, b, _)| (a, b))
|
||||
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
|
||||
self.types.values().copied().filter_map(|(def, vis, _)| match def {
|
||||
ModuleDefId::ModuleId(module) => Some((module, vis)),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn types(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
|
||||
self.types.values().copied().map(|(def, vis, _)| (def, vis))
|
||||
}
|
||||
pub fn unnamed_consts<'a>(
|
||||
&'a self,
|
||||
db: &'a dyn DefDatabase,
|
||||
) -> 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()
|
||||
self.unnamed_consts.iter().copied().chain(synstructure_hack_consts)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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 {
|
||||
ItemInNs::Macros(def) => self
|
||||
.macros
|
||||
.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, _))| (other_def == def).then_some((name, vis))),
|
||||
ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
}),
|
||||
ItemInNs::Types(def) => self.types.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
}),
|
||||
|
||||
ItemInNs::Values(def) => self
|
||||
.values
|
||||
.iter()
|
||||
.find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
|
||||
ItemInNs::Values(def) => self.values.iter().find_map(|(name, &(other_def, vis, i))| {
|
||||
(other_def == def).then_some((name, vis, i.is_none()))
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
@ -624,18 +644,17 @@ impl ItemScope {
|
||||
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
|
||||
self.types
|
||||
.values_mut()
|
||||
.map(|(def, vis, _)| (def, vis))
|
||||
.chain(self.values.values_mut().map(|(def, vis, _)| (def, vis)))
|
||||
.map(|(_, v)| v)
|
||||
.map(|(_, vis, _)| vis)
|
||||
.chain(self.values.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() {
|
||||
if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*vis = Visibility::Module(this_module);
|
||||
*vis = Visibility::Module(this_module, VisibilityExplicity::Implicit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ use crate::{
|
||||
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
|
||||
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
||||
visibility::RawVisibility,
|
||||
visibility::{RawVisibility, VisibilityExplicity},
|
||||
BlockId, Lookup,
|
||||
};
|
||||
|
||||
@ -78,8 +78,9 @@ pub struct RawVisibilityId(u32);
|
||||
|
||||
impl RawVisibilityId {
|
||||
pub const PUB: Self = RawVisibilityId(u32::max_value());
|
||||
pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
|
||||
pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
|
||||
pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
|
||||
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 {
|
||||
@ -87,7 +88,7 @@ impl fmt::Debug for RawVisibilityId {
|
||||
let mut f = f.debug_tuple("RawVisibilityId");
|
||||
match *self {
|
||||
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)"),
|
||||
_ => f.field(&self.0),
|
||||
};
|
||||
@ -249,19 +250,30 @@ impl ItemVisibilities {
|
||||
fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
|
||||
match &vis {
|
||||
RawVisibility::Public => RawVisibilityId::PUB,
|
||||
RawVisibility::Module(path) if path.segments().is_empty() => match &path.kind {
|
||||
PathKind::Super(0) => RawVisibilityId::PRIV,
|
||||
PathKind::Crate => RawVisibilityId::PUB_CRATE,
|
||||
_ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
|
||||
},
|
||||
RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => {
|
||||
match (&path.kind, explicitiy) {
|
||||
(PathKind::Super(0), VisibilityExplicity::Explicit) => {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VIS_PUB: RawVisibility = RawVisibility::Public;
|
||||
static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)));
|
||||
static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
|
||||
static VIS_PRIV_IMPLICIT: RawVisibility =
|
||||
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)]
|
||||
struct ItemTreeData {
|
||||
@ -540,7 +552,8 @@ impl Index<RawVisibilityId> for ItemTree {
|
||||
type Output = RawVisibility;
|
||||
fn index(&self, index: RawVisibilityId) -> &Self::Output {
|
||||
match index {
|
||||
RawVisibilityId::PRIV => &VIS_PRIV,
|
||||
RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
|
||||
RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
|
||||
RawVisibilityId::PUB => &VIS_PUB,
|
||||
RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
|
||||
_ => &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 crate::{
|
||||
generics::{GenericParams, TypeParamData, TypeParamProvenance},
|
||||
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
|
||||
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
|
||||
LocalLifetimeParamId, LocalTypeOrConstParamId,
|
||||
};
|
||||
@ -386,17 +386,16 @@ impl<'a> Ctx<'a> {
|
||||
flags |= FnFlags::HAS_UNSAFE_KW;
|
||||
}
|
||||
|
||||
let mut res = Function {
|
||||
let res = Function {
|
||||
name,
|
||||
visibility,
|
||||
explicit_generic_params: Interned::new(GenericParams::default()),
|
||||
explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
|
||||
abi,
|
||||
params,
|
||||
ret_type: Interned::new(ret_type),
|
||||
ast_id,
|
||||
flags,
|
||||
};
|
||||
res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func);
|
||||
|
||||
Some(id(self.data().functions.alloc(res)))
|
||||
}
|
||||
@ -604,7 +603,7 @@ impl<'a> Ctx<'a> {
|
||||
has_implicit_self: HasImplicitSelf,
|
||||
node: &dyn ast::HasGenericParams,
|
||||
) -> Interned<GenericParams> {
|
||||
let mut generics = GenericParams::default();
|
||||
let mut generics = GenericParamsCollector::default();
|
||||
|
||||
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
|
||||
// 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.shrink_to_fit();
|
||||
Interned::new(generics)
|
||||
Interned::new(generics.finish())
|
||||
}
|
||||
|
||||
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) {
|
||||
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 "),
|
||||
};
|
||||
}
|
||||
|
@ -87,7 +87,10 @@ impl LangItems {
|
||||
}
|
||||
|
||||
/// 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 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
|
||||
@ -161,9 +168,9 @@ impl LangItems {
|
||||
item: LangItem,
|
||||
) -> Option<LangItemTarget> {
|
||||
let _p = profile::span("lang_item_query");
|
||||
let lang_items = db.crate_lang_items(start_crate);
|
||||
let start_crate_target = lang_items.items.get(&item);
|
||||
if let Some(&target) = start_crate_target {
|
||||
if let Some(target) =
|
||||
db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied())
|
||||
{
|
||||
return Some(target);
|
||||
}
|
||||
db.crate_graph()[start_crate]
|
||||
|
@ -10,10 +10,17 @@
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! eprintln {
|
||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
||||
}
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_parse_format;
|
||||
|
||||
#[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;
|
||||
|
||||
@ -49,7 +56,7 @@ pub mod visibility;
|
||||
pub mod find_path;
|
||||
pub mod import_map;
|
||||
|
||||
pub use rustc_dependencies::abi as layout;
|
||||
pub use rustc_abi as layout;
|
||||
use triomphe::Arc;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -16,13 +16,12 @@ struct Foo;
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
|
||||
impl < > core::marker::Copy for Foo< > where {}"#]],
|
||||
impl < > $crate::marker::Copy for Foo< > where {}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_in_core() {
|
||||
cov_mark::check!(test_copy_expand_in_core);
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs crate:core
|
||||
@ -41,7 +40,7 @@ macro Copy {}
|
||||
#[derive(Copy)]
|
||||
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)]
|
||||
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)]
|
||||
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,
|
||||
}
|
||||
|
||||
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 {
|
||||
match self {
|
||||
Command::Move {
|
||||
@ -158,7 +157,7 @@ where
|
||||
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 {
|
||||
match self {
|
||||
Foo {
|
||||
@ -186,7 +185,7 @@ struct Foo<const X: usize, T>(u32);
|
||||
#[derive(Clone)]
|
||||
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 {
|
||||
match self {
|
||||
Foo(f0, )=>Foo(f0.clone(), ),
|
||||
@ -226,14 +225,14 @@ enum Bar {
|
||||
Bar,
|
||||
}
|
||||
|
||||
impl < > core::default::Default for Foo< > where {
|
||||
impl < > $crate::default::Default for Foo< > where {
|
||||
fn default() -> Self {
|
||||
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 {
|
||||
Bar::Bar
|
||||
}
|
||||
@ -261,7 +260,7 @@ enum Command {
|
||||
Jump,
|
||||
}
|
||||
|
||||
impl < > core::cmp::PartialEq for Command< > where {
|
||||
impl < > $crate::cmp::PartialEq for Command< > where {
|
||||
fn eq(&self , other: &Self ) -> bool {
|
||||
match (self , other) {
|
||||
(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,
|
||||
}
|
||||
|
||||
impl < > core::cmp::PartialEq for Command< > where {
|
||||
impl < > $crate::cmp::PartialEq for Command< > where {
|
||||
fn eq(&self , other: &Self ) -> bool {
|
||||
match (self , other) {
|
||||
(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,
|
||||
}
|
||||
|
||||
impl < > core::cmp::PartialOrd for Command< > where {
|
||||
fn partial_cmp(&self , other: &Self ) -> core::option::Option::Option<core::cmp::Ordering> {
|
||||
match core::intrinsics::discriminant_value(self ).partial_cmp(&core::intrinsics::discriminant_value(other)) {
|
||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
||||
impl < > $crate::cmp::PartialOrd for Command< > where {
|
||||
fn partial_cmp(&self , other: &Self ) -> $crate::option::Option::Option<$crate::cmp::Ordering> {
|
||||
match $crate::intrinsics::discriminant_value(self ).partial_cmp(&$crate::intrinsics::discriminant_value(other)) {
|
||||
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||
match (self , other) {
|
||||
(Command::Move {
|
||||
x: x_self, y: y_self,
|
||||
@ -348,10 +347,10 @@ impl < > core::cmp::PartialOrd for Command< > where {
|
||||
x: x_other, y: y_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) {
|
||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
||||
core::option::Option::Some(core::cmp::Ordering::Equal)
|
||||
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||
$crate::option::Option::Some($crate::cmp::Ordering::Equal)
|
||||
}
|
||||
c=>return c,
|
||||
}
|
||||
@ -359,22 +358,22 @@ impl < > core::cmp::PartialOrd for Command< > where {
|
||||
c=>return c,
|
||||
}
|
||||
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.partial_cmp(&f0_other) {
|
||||
core::option::Option::Some(core::cmp::Ordering::Equal)=> {
|
||||
core::option::Option::Some(core::cmp::Ordering::Equal)
|
||||
$crate::option::Option::Some($crate::cmp::Ordering::Equal)=> {
|
||||
$crate::option::Option::Some($crate::cmp::Ordering::Equal)
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl < > core::cmp::Ord for Command< > where {
|
||||
fn cmp(&self , other: &Self ) -> core::cmp::Ordering {
|
||||
match core::intrinsics::discriminant_value(self ).cmp(&core::intrinsics::discriminant_value(other)) {
|
||||
core::cmp::Ordering::Equal=> {
|
||||
impl < > $crate::cmp::Ord for Command< > where {
|
||||
fn cmp(&self , other: &Self ) -> $crate::cmp::Ordering {
|
||||
match $crate::intrinsics::discriminant_value(self ).cmp(&$crate::intrinsics::discriminant_value(other)) {
|
||||
$crate::cmp::Ordering::Equal=> {
|
||||
match (self , other) {
|
||||
(Command::Move {
|
||||
x: x_self, y: y_self,
|
||||
@ -383,10 +382,10 @@ impl < > core::cmp::Ord for Command< > where {
|
||||
x: x_other, y: y_other,
|
||||
}
|
||||
)=>match x_self.cmp(&x_other) {
|
||||
core::cmp::Ordering::Equal=> {
|
||||
$crate::cmp::Ordering::Equal=> {
|
||||
match y_self.cmp(&y_other) {
|
||||
core::cmp::Ordering::Equal=> {
|
||||
core::cmp::Ordering::Equal
|
||||
$crate::cmp::Ordering::Equal=> {
|
||||
$crate::cmp::Ordering::Equal
|
||||
}
|
||||
c=>return c,
|
||||
}
|
||||
@ -394,12 +393,12 @@ impl < > core::cmp::Ord for Command< > where {
|
||||
c=>return c,
|
||||
}
|
||||
, (Command::Do(f0_self, ), Command::Do(f0_other, ))=>match f0_self.cmp(&f0_other) {
|
||||
core::cmp::Ordering::Equal=> {
|
||||
core::cmp::Ordering::Equal
|
||||
$crate::cmp::Ordering::Equal=> {
|
||||
$crate::cmp::Ordering::Equal
|
||||
}
|
||||
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,
|
||||
@ -433,8 +432,8 @@ struct Foo {
|
||||
z: (i32, u64),
|
||||
}
|
||||
|
||||
impl < > core::hash::Hash for Foo< > where {
|
||||
fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
||||
impl < > $crate::hash::Hash for Foo< > where {
|
||||
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
||||
match self {
|
||||
Foo {
|
||||
x: x, y: y, z: z,
|
||||
@ -471,9 +470,9 @@ enum Command {
|
||||
Jump,
|
||||
}
|
||||
|
||||
impl < > core::hash::Hash for Command< > where {
|
||||
fn hash<H: core::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
||||
core::mem::discriminant(self ).hash(ra_expand_state);
|
||||
impl < > $crate::hash::Hash for Command< > where {
|
||||
fn hash<H: $crate::hash::Hasher>(&self , ra_expand_state: &mut H) {
|
||||
$crate::mem::discriminant(self ).hash(ra_expand_state);
|
||||
match self {
|
||||
Command::Move {
|
||||
x: x, y: y,
|
||||
@ -517,8 +516,8 @@ enum Command {
|
||||
Jump,
|
||||
}
|
||||
|
||||
impl < > core::fmt::Debug for Command< > where {
|
||||
fn fmt(&self , f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
impl < > $crate::fmt::Debug for Command< > where {
|
||||
fn fmt(&self , f: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
|
||||
match self {
|
||||
Command::Move {
|
||||
x: x, y: y,
|
||||
|
@ -136,7 +136,7 @@ fn main() { option_env!("TEST_ENV_VAR"); }
|
||||
#[rustc_builtin_macro]
|
||||
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},
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
visibility::Visibility,
|
||||
visibility::{Visibility, VisibilityExplicity},
|
||||
AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
|
||||
MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||
};
|
||||
@ -332,7 +332,10 @@ impl DefMap {
|
||||
// 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
|
||||
// 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(
|
||||
ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
|
||||
visibility,
|
||||
|
@ -87,7 +87,7 @@ impl DefMap {
|
||||
within_impl: bool,
|
||||
) -> Option<Visibility> {
|
||||
let mut vis = match visibility {
|
||||
RawVisibility::Module(path) => {
|
||||
RawVisibility::Module(path, explicity) => {
|
||||
let (result, remaining) =
|
||||
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
|
||||
if remaining.is_some() {
|
||||
@ -95,7 +95,7 @@ impl DefMap {
|
||||
}
|
||||
let types = result.take_types()?;
|
||||
match types {
|
||||
ModuleDefId::ModuleId(m) => Visibility::Module(m),
|
||||
ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicity),
|
||||
// error: visibility needs to refer to module
|
||||
_ => {
|
||||
return None;
|
||||
@ -108,11 +108,11 @@ impl DefMap {
|
||||
// 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
|
||||
// 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.
|
||||
if self.block_id() != m.block && !within_impl {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
fn macro_use_imports_all_macro_types() {
|
||||
let db = TestDB::with_files(
|
||||
|
@ -242,7 +242,7 @@ impl Resolver {
|
||||
let within_impl =
|
||||
self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some();
|
||||
match visibility {
|
||||
RawVisibility::Module(_) => {
|
||||
RawVisibility::Module(_, _) => {
|
||||
let (item_map, module) = self.item_scope();
|
||||
item_map.resolve_visibility(db, module, visibility, within_impl)
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ use base_db::{
|
||||
Upcast,
|
||||
};
|
||||
use hir_expand::{db::ExpandDatabase, InFile};
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{algo, ast, AstNode};
|
||||
use triomphe::Arc;
|
||||
|
||||
@ -76,7 +75,7 @@ impl FileLoader for TestDB {
|
||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,14 @@ use crate::{
|
||||
pub enum RawVisibility {
|
||||
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
|
||||
/// equivalent to `pub(self)`.
|
||||
Module(ModPath),
|
||||
Module(ModPath, VisibilityExplicity),
|
||||
/// `pub`.
|
||||
Public,
|
||||
}
|
||||
|
||||
impl 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(
|
||||
@ -41,18 +41,9 @@ impl RawVisibility {
|
||||
db: &dyn DefDatabase,
|
||||
node: Option<ast::Visibility>,
|
||||
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 {
|
||||
let node = match node {
|
||||
None => return default,
|
||||
None => return RawVisibility::private(),
|
||||
Some(node) => node,
|
||||
};
|
||||
match node.kind() {
|
||||
@ -62,19 +53,19 @@ impl RawVisibility {
|
||||
None => return RawVisibility::private(),
|
||||
Some(path) => path,
|
||||
};
|
||||
RawVisibility::Module(path)
|
||||
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||
}
|
||||
ast::VisibilityKind::PubCrate => {
|
||||
let path = ModPath::from_kind(PathKind::Crate);
|
||||
RawVisibility::Module(path)
|
||||
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||
}
|
||||
ast::VisibilityKind::PubSuper => {
|
||||
let path = ModPath::from_kind(PathKind::Super(1));
|
||||
RawVisibility::Module(path)
|
||||
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||
}
|
||||
ast::VisibilityKind::PubSelf => {
|
||||
let path = ModPath::from_kind(PathKind::Super(0));
|
||||
RawVisibility::Module(path)
|
||||
RawVisibility::Module(path, VisibilityExplicity::Explicit)
|
||||
}
|
||||
ast::VisibilityKind::Pub => RawVisibility::Public,
|
||||
}
|
||||
@ -94,7 +85,7 @@ impl RawVisibility {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Visibility {
|
||||
/// Visibility is restricted to a certain module.
|
||||
Module(ModuleId),
|
||||
Module(ModuleId, VisibilityExplicity),
|
||||
/// Visibility is unrestricted.
|
||||
Public,
|
||||
}
|
||||
@ -102,7 +93,7 @@ pub enum Visibility {
|
||||
impl Visibility {
|
||||
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
|
||||
let to_module = match self {
|
||||
Visibility::Module(m) => m,
|
||||
Visibility::Module(m, _) => m,
|
||||
Visibility::Public => return true,
|
||||
};
|
||||
// if they're not in the same crate, it can't be visible
|
||||
@ -124,7 +115,7 @@ impl Visibility {
|
||||
mut from_module: LocalModuleId,
|
||||
) -> bool {
|
||||
let mut to_module = match self {
|
||||
Visibility::Module(m) => m,
|
||||
Visibility::Module(m, _) => m,
|
||||
Visibility::Public => return true,
|
||||
};
|
||||
|
||||
@ -181,9 +172,9 @@ impl Visibility {
|
||||
/// visible in unrelated modules).
|
||||
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
|
||||
match (self, other) {
|
||||
(Visibility::Module(_) | Visibility::Public, Visibility::Public)
|
||||
| (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public),
|
||||
(Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
|
||||
(Visibility::Module(_, _) | Visibility::Public, Visibility::Public)
|
||||
| (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public),
|
||||
(Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => {
|
||||
if mod_a.krate != mod_b.krate {
|
||||
return None;
|
||||
}
|
||||
@ -199,12 +190,12 @@ impl Visibility {
|
||||
|
||||
if a_ancestors.any(|m| m == mod_b.local_id) {
|
||||
// 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) {
|
||||
// A is above B
|
||||
return Some(Visibility::Module(mod_a));
|
||||
return Some(Visibility::Module(mod_a, vis_a));
|
||||
}
|
||||
|
||||
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.
|
||||
pub(crate) fn field_visibilities_query(
|
||||
db: &dyn DefDatabase,
|
||||
|
@ -1,6 +1,5 @@
|
||||
//! Builtin derives.
|
||||
|
||||
use base_db::{CrateOrigin, LangCrateOrigin};
|
||||
use itertools::izip;
|
||||
use rustc_hash::FxHashSet;
|
||||
use span::{MacroCallId, Span};
|
||||
@ -10,6 +9,7 @@ use tracing::debug;
|
||||
use crate::{
|
||||
hygiene::span_with_def_site_ctxt,
|
||||
name::{AsName, Name},
|
||||
quote::dollar_crate,
|
||||
span_map::SpanMapRef,
|
||||
tt,
|
||||
};
|
||||
@ -38,7 +38,7 @@ macro_rules! register_builtin {
|
||||
|
||||
let span = db.lookup_intern_macro_call(id).call_site;
|
||||
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> {
|
||||
@ -398,41 +398,13 @@ fn expand_simple_derive(
|
||||
ExpandResult::ok(expanded)
|
||||
}
|
||||
|
||||
fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId, span: Span) -> tt::TokenTree {
|
||||
// FIXME: make hygiene works for builtin derive macro
|
||||
// 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);
|
||||
fn copy_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
|
||||
}
|
||||
|
||||
fn clone_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = find_builtin_crate(db, id, span);
|
||||
fn clone_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| {
|
||||
if matches!(adt.shape, AdtShape::Union) {
|
||||
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
|
||||
@ -482,14 +454,8 @@ fn and_and(span: Span) -> tt::Subtree {
|
||||
quote! {span => #and& }
|
||||
}
|
||||
|
||||
fn default_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &find_builtin_crate(db, id, span);
|
||||
fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| {
|
||||
let body = match &adt.shape {
|
||||
AdtShape::Struct(fields) => {
|
||||
@ -527,14 +493,8 @@ fn default_expand(
|
||||
})
|
||||
}
|
||||
|
||||
fn debug_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &find_builtin_crate(db, id, span);
|
||||
fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| {
|
||||
let for_variant = |name: String, v: &VariantShape| match v {
|
||||
VariantShape::Struct(fields) => {
|
||||
@ -605,14 +565,8 @@ fn debug_expand(
|
||||
})
|
||||
}
|
||||
|
||||
fn hash_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &find_builtin_crate(db, id, span);
|
||||
fn hash_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| {
|
||||
if matches!(adt.shape, AdtShape::Union) {
|
||||
// FIXME: Return expand error here
|
||||
@ -658,25 +612,13 @@ fn hash_expand(
|
||||
})
|
||||
}
|
||||
|
||||
fn eq_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = find_builtin_crate(db, id, span);
|
||||
fn eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
|
||||
}
|
||||
|
||||
fn partial_eq_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = find_builtin_crate(db, id, span);
|
||||
fn partial_eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| {
|
||||
if matches!(adt.shape, AdtShape::Union) {
|
||||
// FIXME: Return expand error here
|
||||
@ -747,17 +689,11 @@ fn self_and_other_patterns(
|
||||
(self_patterns, other_patterns)
|
||||
}
|
||||
|
||||
fn ord_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &find_builtin_crate(db, id, span);
|
||||
fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| {
|
||||
fn compare(
|
||||
krate: &tt::TokenTree,
|
||||
krate: &tt::Ident,
|
||||
left: tt::Subtree,
|
||||
right: tt::Subtree,
|
||||
rest: tt::Subtree,
|
||||
@ -811,17 +747,11 @@ fn ord_expand(
|
||||
})
|
||||
}
|
||||
|
||||
fn partial_ord_expand(
|
||||
db: &dyn ExpandDatabase,
|
||||
id: MacroCallId,
|
||||
span: Span,
|
||||
tt: &ast::Adt,
|
||||
tm: SpanMapRef<'_>,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &find_builtin_crate(db, id, span);
|
||||
fn partial_ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
|
||||
let krate = &dollar_crate(span);
|
||||
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| {
|
||||
fn compare(
|
||||
krate: &tt::TokenTree,
|
||||
krate: &tt::Ident,
|
||||
left: tt::Subtree,
|
||||
right: tt::Subtree,
|
||||
rest: tt::Subtree,
|
||||
|
@ -6,18 +6,16 @@ use either::Either;
|
||||
use itertools::Itertools;
|
||||
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
|
||||
use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
|
||||
use syntax::{
|
||||
ast::{self, AstToken},
|
||||
SmolStr,
|
||||
};
|
||||
use syntax::ast::{self, AstToken};
|
||||
|
||||
use crate::{
|
||||
db::ExpandDatabase,
|
||||
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
|
||||
name::{self, known},
|
||||
quote,
|
||||
quote::dollar_crate,
|
||||
tt::{self, DelimSpan},
|
||||
ExpandError, ExpandResult, HirFileIdExt, MacroCallId,
|
||||
ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt,
|
||||
};
|
||||
|
||||
macro_rules! register_builtin {
|
||||
@ -205,7 +203,7 @@ fn assert_expand(
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let call_site_span = span_with_call_site_ctxt(db, span, id);
|
||||
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 {
|
||||
[cond, panic_args @ ..] => {
|
||||
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::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);));
|
||||
}
|
||||
_ => break,
|
||||
@ -345,7 +343,7 @@ fn panic_expand(
|
||||
tt: &tt::Subtree,
|
||||
span: Span,
|
||||
) -> 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 mac =
|
||||
@ -371,7 +369,7 @@ fn unreachable_expand(
|
||||
tt: &tt::Subtree,
|
||||
span: Span,
|
||||
) -> 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 mac = if use_panic_2021(db, call_site_span) {
|
||||
@ -611,7 +609,7 @@ fn relative_file(
|
||||
path_str: &str,
|
||||
allow_recursion: bool,
|
||||
) -> 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 res = db
|
||||
.resolve_path(path)
|
||||
@ -763,10 +761,10 @@ fn option_env_expand(
|
||||
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) {
|
||||
None => quote! {span => ::core::option::Option::None::<&str> },
|
||||
Some(s) => quote! {span => ::core::option::Option::Some(#s) },
|
||||
None => quote! {span => #dollar_crate::option::Option::None::<&str> },
|
||||
Some(s) => quote! {span => #dollar_crate::option::Option::Some(#s) },
|
||||
};
|
||||
|
||||
ExpandResult::ok(expanded)
|
||||
|
@ -318,6 +318,7 @@ pub trait MacroFileIdExt {
|
||||
fn expansion_level(self, db: &dyn ExpandDatabase) -> u32;
|
||||
/// If this is a macro call, returns the syntax node of the call.
|
||||
fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode>;
|
||||
fn parent(self, db: &dyn ExpandDatabase) -> HirFileId;
|
||||
|
||||
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
|
||||
fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo {
|
||||
|
@ -4,6 +4,10 @@ use span::Span;
|
||||
|
||||
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
|
||||
// FIXME:
|
||||
// 1. Not all puncts are handled
|
||||
|
@ -34,7 +34,9 @@ nohash-hasher.workspace = true
|
||||
typed-arena = "2.0.1"
|
||||
indexmap.workspace = true
|
||||
|
||||
rustc-dependencies.workspace = true
|
||||
ra-ap-rustc_abi.workspace = true
|
||||
ra-ap-rustc_index.workspace = true
|
||||
|
||||
|
||||
# local deps
|
||||
stdx.workspace = true
|
||||
@ -58,7 +60,7 @@ test-utils.workspace = true
|
||||
test-fixture.workspace = true
|
||||
|
||||
[features]
|
||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
||||
in-rust-tree = []
|
||||
|
||||
[lints]
|
||||
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 mut result = vec![];
|
||||
@ -183,7 +183,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||
def_blocks
|
||||
.into_iter()
|
||||
.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 => {
|
||||
let mut f =
|
||||
@ -198,7 +199,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||
def_blocks
|
||||
.into_iter()
|
||||
.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)]
|
||||
fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
|
||||
|
||||
// region:mir
|
||||
|
||||
#[salsa::invoke(crate::mir::mir_body_query)]
|
||||
#[salsa::cycle(crate::mir::mir_body_recover)]
|
||||
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)]
|
||||
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::cycle(crate::consteval::const_eval_recover)]
|
||||
fn const_eval(
|
||||
@ -92,6 +80,22 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
|
||||
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)]
|
||||
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>;
|
||||
|
||||
#[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
|
||||
/// 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>;
|
||||
|
||||
#[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)]
|
||||
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;
|
||||
|
@ -1629,7 +1629,7 @@ pub fn write_visibility(
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match vis {
|
||||
Visibility::Public => write!(f, "pub "),
|
||||
Visibility::Module(vis_id) => {
|
||||
Visibility::Module(vis_id, _) => {
|
||||
let def_map = module_id.def_map(f.db.upcast());
|
||||
let root_module_id = def_map.module_id(DefMap::ROOT);
|
||||
if vis_id == module_id {
|
||||
|
@ -12,10 +12,9 @@ use hir_def::{
|
||||
LocalEnumVariantId, LocalFieldId, StructId,
|
||||
};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use rustc_dependencies::{
|
||||
abi::AddressSpace,
|
||||
index::{IndexSlice, IndexVec},
|
||||
};
|
||||
use rustc_abi::AddressSpace;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
@ -35,7 +34,7 @@ mod target;
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
|
||||
|
||||
impl rustc_dependencies::index::Idx for RustcEnumVariantIdx {
|
||||
impl rustc_index::Idx for RustcEnumVariantIdx {
|
||||
fn new(idx: usize) -> Self {
|
||||
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 {
|
||||
RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use hir_def::{
|
||||
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
|
||||
};
|
||||
use la_arena::RawIdx;
|
||||
use rustc_dependencies::index::IndexVec;
|
||||
use rustc_index::IndexVec;
|
||||
use smallvec::SmallVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
|
@ -118,7 +118,7 @@ fn check_fail(ra_fixture: &str, e: LayoutError) {
|
||||
macro_rules! size_and_align {
|
||||
(minicore: $($x:tt),*;$($t:tt)*) => {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
#![allow(dead_code)]
|
||||
$($t)*
|
||||
check_size_and_align(
|
||||
stringify!($($t)*),
|
||||
@ -130,7 +130,7 @@ macro_rules! size_and_align {
|
||||
};
|
||||
($($t:tt)*) => {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
#![allow(dead_code)]
|
||||
$($t)*
|
||||
check_size_and_align(
|
||||
stringify!($($t)*),
|
||||
|
@ -3,10 +3,17 @@
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! eprintln {
|
||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
||||
}
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_index;
|
||||
|
||||
#[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 chalk_db;
|
||||
|
@ -1601,7 +1601,7 @@ fn implicitly_sized_clauses<'a>(
|
||||
pub(crate) fn generic_defaults_query(
|
||||
db: &dyn HirDatabase,
|
||||
def: GenericDefId,
|
||||
) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
|
||||
) -> Arc<[Binders<crate::GenericArg>]> {
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx = TyLoweringContext::new(db, &resolver, def.into())
|
||||
.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 hir_def::{
|
||||
data::{adt::StructFlags, ImplData},
|
||||
item_scope::ItemScope,
|
||||
nameres::DefMap,
|
||||
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
||||
ModuleDefId, ModuleId, TraitId,
|
||||
ModuleId, TraitId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@ -132,34 +131,40 @@ pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
|
||||
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.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct TraitImpls {
|
||||
// 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 {
|
||||
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 mut impls = Self { map: FxHashMap::default() };
|
||||
let mut impls = FxHashMap::default();
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
impls.collect_def_map(db, &crate_def_map);
|
||||
impls.shrink_to_fit();
|
||||
Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
|
||||
|
||||
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 mut impls = Self { map: FxHashMap::default() };
|
||||
let mut impls = FxHashMap::default();
|
||||
|
||||
let block_def_map = db.block_def_map(block);
|
||||
impls.collect_def_map(db, &block_def_map);
|
||||
impls.shrink_to_fit();
|
||||
Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
|
||||
|
||||
Arc::new(impls)
|
||||
if impls.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Arc::new(Self::finish(impls)))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trait_impls_in_deps_query(
|
||||
@ -174,15 +179,16 @@ impl TraitImpls {
|
||||
)
|
||||
}
|
||||
|
||||
fn shrink_to_fit(&mut self) {
|
||||
self.map.shrink_to_fit();
|
||||
self.map.values_mut().for_each(|map| {
|
||||
map.shrink_to_fit();
|
||||
map.values_mut().for_each(Vec::shrink_to_fit);
|
||||
});
|
||||
fn finish(map: TraitFpMapCollector) -> TraitImpls {
|
||||
TraitImpls {
|
||||
map: map
|
||||
.into_iter()
|
||||
.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 impl_id in module_data.scope.impls() {
|
||||
// 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_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
|
||||
self.map
|
||||
.entry(target_trait)
|
||||
.or_default()
|
||||
.entry(self_ty_fp)
|
||||
.or_default()
|
||||
.push(impl_id);
|
||||
map.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.
|
||||
// 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());
|
||||
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)
|
||||
}
|
||||
|
||||
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 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.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) {
|
||||
@ -321,7 +329,7 @@ impl InherentImpls {
|
||||
|
||||
// To better support custom derives, collect impls in all unnamed const items.
|
||||
// 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());
|
||||
for (_, block_def_map) in body.blocks(db.upcast()) {
|
||||
self.collect_def_map(db, &block_def_map);
|
||||
@ -367,34 +375,6 @@ pub(crate) fn incoherent_inherent_impl_crates(
|
||||
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(
|
||||
db: &dyn HirDatabase,
|
||||
ty: &Ty,
|
||||
@ -737,7 +717,7 @@ fn lookup_impl_assoc_item_for_trait_ref(
|
||||
let impls = db.trait_impls_in_deps(env.krate);
|
||||
let self_impls = match self_ty.kind(Interner) {
|
||||
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,
|
||||
};
|
||||
@ -1254,17 +1234,18 @@ fn iterate_inherent_methods(
|
||||
};
|
||||
|
||||
while let Some(block_id) = block {
|
||||
let impls = db.inherent_impls_in_block(block_id);
|
||||
impls_for_self_ty(
|
||||
&impls,
|
||||
self_ty,
|
||||
table,
|
||||
name,
|
||||
receiver_ty,
|
||||
receiver_adjustments.clone(),
|
||||
module,
|
||||
callback,
|
||||
)?;
|
||||
if let Some(impls) = db.inherent_impls_in_block(block_id) {
|
||||
impls_for_self_ty(
|
||||
&impls,
|
||||
self_ty,
|
||||
table,
|
||||
name,
|
||||
receiver_ty,
|
||||
receiver_adjustments.clone(),
|
||||
module,
|
||||
callback,
|
||||
)?;
|
||||
}
|
||||
|
||||
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_expand::db::ExpandDatabase;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::TextRange;
|
||||
use test_utils::extract_annotations;
|
||||
use triomphe::Arc;
|
||||
@ -81,7 +80,7 @@ impl FileLoader for TestDB {
|
||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -987,15 +987,12 @@ fn infer_builtin_macros_env() {
|
||||
fn infer_builtin_macros_option_env() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: option
|
||||
//- /main.rs env:foo=bar
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! option_env {() => {}}
|
||||
|
||||
fn main() {
|
||||
let x = option_env!("foo");
|
||||
//^ Option<&str>
|
||||
}
|
||||
//- minicore: env
|
||||
//- /main.rs env:foo=bar
|
||||
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]
|
||||
fn infer_derive_clone_with_params() {
|
||||
check_types(
|
||||
|
@ -35,7 +35,7 @@ macro_rules! impl_has_attrs {
|
||||
impl HasAttrs for $def {
|
||||
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
|
||||
let def = AttrDefId::$def_id(self.into());
|
||||
db.attrs_with_owner(def)
|
||||
AttrsWithOwner::attrs_with_owner(db.upcast(), def)
|
||||
}
|
||||
fn attr_id(self) -> AttrDefId {
|
||||
AttrDefId::$def_id(self.into())
|
||||
|
@ -15,8 +15,8 @@ pub use hir_def::db::{
|
||||
InternExternBlockQuery, InternExternCrateQuery, InternFunctionQuery, InternImplQuery,
|
||||
InternInTypeConstQuery, InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery,
|
||||
InternStaticQuery, InternStructQuery, InternTraitAliasQuery, InternTraitQuery,
|
||||
InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangAttrQuery, LangItemQuery,
|
||||
Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
|
||||
InternTypeAliasQuery, InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery,
|
||||
MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
|
||||
StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery,
|
||||
TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery,
|
||||
UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery,
|
||||
|
@ -754,7 +754,7 @@ impl Module {
|
||||
scope
|
||||
.declarations()
|
||||
.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()
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> {
|
||||
// Record renamed imports.
|
||||
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
|
||||
// for now.
|
||||
// FIXME: This parses!
|
||||
for id in scope.imports() {
|
||||
let source = id.import.child_source(self.db.upcast());
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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},
|
||||
AstNode, HasGenericParams,
|
||||
},
|
||||
match_ast, ted, SyntaxElement,
|
||||
match_ast, ted, AstToken, SyntaxElement,
|
||||
SyntaxKind::{self, COMMENT},
|
||||
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
|
||||
};
|
||||
@ -1733,8 +1733,23 @@ fn make_body(
|
||||
ast::Expr::BlockExpr(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);
|
||||
// Recreate the block for formatting consistency with other extracted functions.
|
||||
make::block_expr(block.statements(), block.tail_expr())
|
||||
let elements = block.stmt_list().map_or_else(
|
||||
|| 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));
|
||||
@ -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]
|
||||
fn in_left_curly_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()?;
|
||||
let target = statement.syntax().parent()?.text_range();
|
||||
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 mut outer_exists = false;
|
||||
@ -250,6 +254,18 @@ fn bar() -> i32 {
|
||||
}
|
||||
fn bar() -> i32 {
|
||||
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| {
|
||||
// Create the function
|
||||
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,
|
||||
};
|
||||
|
||||
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_const = method_source.const_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 =
|
||||
if is_async { make::expr_await(tail_expr) } else { tail_expr };
|
||||
let body = make::block_expr([], Some(tail_expr_finished));
|
||||
|
||||
let ret_type = method_source.ret_type();
|
||||
|
||||
let f = make::fn_(
|
||||
vis,
|
||||
fn_name,
|
||||
type_params,
|
||||
method_source.where_clause(),
|
||||
where_clause,
|
||||
params,
|
||||
body,
|
||||
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();
|
||||
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 {
|
||||
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 wrap_return_type_in_result;
|
||||
mod into_to_qualified_from;
|
||||
mod merge_nested_if;
|
||||
|
||||
pub(crate) fn all() -> &'static [Handler] {
|
||||
&[
|
||||
@ -291,6 +292,7 @@ mod handlers {
|
||||
invert_if::invert_if,
|
||||
merge_imports::merge_imports,
|
||||
merge_match_arms::merge_match_arms,
|
||||
merge_nested_if::merge_nested_if,
|
||||
move_bounds::move_bounds_to_where_clause,
|
||||
move_const_to_impl::move_const_to_impl,
|
||||
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]
|
||||
fn doctest_move_arm_cond_to_match_guard() {
|
||||
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.
|
||||
pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
|
||||
let mut traits_in_scope = self.scope.visible_traits();
|
||||
|
@ -152,6 +152,8 @@ pub struct CompletionRelevance {
|
||||
pub is_local: bool,
|
||||
/// This is set when trait items are completed in an impl of that trait.
|
||||
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.
|
||||
pub is_name_already_imported: bool,
|
||||
/// This is set for completions that will insert a `use` item.
|
||||
@ -228,6 +230,7 @@ impl CompletionRelevance {
|
||||
is_private_editable,
|
||||
postfix_match,
|
||||
is_definite,
|
||||
is_item_from_notable_trait,
|
||||
} = self;
|
||||
|
||||
// lower rank private things
|
||||
@ -266,6 +269,9 @@ impl CompletionRelevance {
|
||||
if is_item_from_trait {
|
||||
score += 1;
|
||||
}
|
||||
if is_item_from_notable_trait {
|
||||
score += 1;
|
||||
}
|
||||
if is_definite {
|
||||
score += 10;
|
||||
}
|
||||
|
@ -1170,6 +1170,7 @@ fn main() { let _: m::Spam = S$0 }
|
||||
),
|
||||
is_local: false,
|
||||
is_item_from_trait: false,
|
||||
is_item_from_notable_trait: false,
|
||||
is_name_already_imported: false,
|
||||
requires_import: false,
|
||||
is_op_method: false,
|
||||
@ -1196,6 +1197,7 @@ fn main() { let _: m::Spam = S$0 }
|
||||
),
|
||||
is_local: false,
|
||||
is_item_from_trait: false,
|
||||
is_item_from_notable_trait: false,
|
||||
is_name_already_imported: false,
|
||||
requires_import: false,
|
||||
is_op_method: false,
|
||||
@ -1274,6 +1276,7 @@ fn foo() { A { the$0 } }
|
||||
),
|
||||
is_local: false,
|
||||
is_item_from_trait: false,
|
||||
is_item_from_notable_trait: false,
|
||||
is_name_already_imported: false,
|
||||
requires_import: false,
|
||||
is_op_method: false,
|
||||
@ -2089,6 +2092,7 @@ fn foo() {
|
||||
),
|
||||
is_local: false,
|
||||
is_item_from_trait: false,
|
||||
is_item_from_notable_trait: false,
|
||||
is_name_already_imported: false,
|
||||
requires_import: 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 is_op_method = func
|
||||
.as_assoc_item(ctx.db())
|
||||
.and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db()))
|
||||
.map_or(false, |trait_| completion.is_ops_trait(trait_));
|
||||
let assoc_item = func.as_assoc_item(db);
|
||||
|
||||
let trait_ = assoc_item.and_then(|trait_| trait_.containing_trait_or_trait_impl(db));
|
||||
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 {
|
||||
FuncKind::Function(&PathCompletionCtx {
|
||||
@ -105,6 +108,7 @@ fn render(
|
||||
},
|
||||
exact_name_match: compute_exact_name_match(completion, &call),
|
||||
is_op_method,
|
||||
is_item_from_notable_trait,
|
||||
..ctx.completion_relevance()
|
||||
});
|
||||
|
||||
@ -141,7 +145,7 @@ fn render(
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
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) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
}
|
||||
|
@ -84,73 +84,11 @@ impl RootDatabase {
|
||||
)*}
|
||||
}
|
||||
purge_each_query![
|
||||
// SourceDatabase
|
||||
base_db::ParseQuery
|
||||
base_db::CrateGraphQuery
|
||||
|
||||
// SourceDatabaseExt
|
||||
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
|
||||
|
||||
// SymbolsDatabase
|
||||
crate::symbol_index::ModuleSymbolsQuery
|
||||
crate::symbol_index::LibrarySymbolsQuery
|
||||
crate::symbol_index::LocalRootsQuery
|
||||
crate::symbol_index::LibraryRootsQuery
|
||||
// HirDatabase
|
||||
hir::db::InferQueryQuery
|
||||
hir::db::MirBodyQuery
|
||||
@ -194,14 +132,50 @@ impl RootDatabase {
|
||||
hir::db::TraitSolveQueryQuery
|
||||
hir::db::ProgramClausesForChalkEnvQuery
|
||||
|
||||
// SymbolsDatabase
|
||||
crate::symbol_index::ModuleSymbolsQuery
|
||||
crate::symbol_index::LibrarySymbolsQuery
|
||||
crate::symbol_index::LocalRootsQuery
|
||||
crate::symbol_index::LibraryRootsQuery
|
||||
|
||||
// LineIndexDatabase
|
||||
crate::LineIndexQuery
|
||||
// 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::InternAnonymousConstQuery
|
||||
hir::db::InternExternCrateQuery
|
||||
hir::db::InternInTypeConstQuery
|
||||
hir::db::InternUseQuery
|
||||
|
||||
// InternDatabase
|
||||
hir::db::InternFunctionQuery
|
||||
@ -219,6 +193,30 @@ impl RootDatabase {
|
||||
hir::db::InternMacro2Query
|
||||
hir::db::InternProcMacroQuery
|
||||
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));
|
||||
|
@ -681,11 +681,10 @@ fn path_import_candidate(
|
||||
Some(qualifier) => match sema.resolve_path(&qualifier) {
|
||||
None => {
|
||||
if qualifier.first_qualifier().map_or(true, |it| sema.resolve_path(&it).is_none()) {
|
||||
let mut qualifier = qualifier
|
||||
.segments_of_this_path_only_rev()
|
||||
let qualifier = qualifier
|
||||
.segments()
|
||||
.map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
qualifier.reverse();
|
||||
ImportCandidate::Path(PathImportCandidate { qualifier: Some(qualifier), name })
|
||||
} else {
|
||||
return None;
|
||||
|
@ -124,7 +124,7 @@ impl FileLoader for RootDatabase {
|
||||
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -145,7 +145,7 @@ impl RootDatabase {
|
||||
db.set_local_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.update_parse_query_lru_capacity(lru_capacity);
|
||||
db.update_base_query_lru_capacities(lru_capacity);
|
||||
db.setup_syntax_context_root();
|
||||
db
|
||||
}
|
||||
@ -154,11 +154,12 @@ impl RootDatabase {
|
||||
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);
|
||||
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
|
||||
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>) {
|
||||
@ -176,6 +177,12 @@ impl RootDatabase {
|
||||
.copied()
|
||||
.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 {
|
||||
($( $module:ident :: $query:ident )*) => {$(
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::helpers::mod_path_to_ast;
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, HirDisplay, ModuleDef, SemanticsScope};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
use syntax::{
|
||||
ast::{self, make, AstNode},
|
||||
@ -227,11 +228,15 @@ struct Ctx<'a> {
|
||||
same_self_type: bool,
|
||||
}
|
||||
|
||||
fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
||||
item.preorder().filter_map(|event| match event {
|
||||
syntax::WalkEvent::Enter(_) => None,
|
||||
syntax::WalkEvent::Leave(node) => Some(node),
|
||||
})
|
||||
fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
||||
let x = item
|
||||
.preorder()
|
||||
.filter_map(|event| match event {
|
||||
syntax::WalkEvent::Enter(node) => Some(node),
|
||||
syntax::WalkEvent::Leave(_) => None,
|
||||
})
|
||||
.collect_vec();
|
||||
x.into_iter().rev()
|
||||
}
|
||||
|
||||
impl Ctx<'_> {
|
||||
@ -239,12 +244,12 @@ impl Ctx<'_> {
|
||||
// `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
|
||||
// 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 {
|
||||
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()) {
|
||||
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
|
||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||
// 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 {
|
||||
self.transform_path(path);
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ impl Definition {
|
||||
if let Some(Visibility::Public) = vis {
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ pub(crate) fn unresolved_assoc_item(
|
||||
"no such associated item",
|
||||
d.expr_or_pat.clone().map(Into::into),
|
||||
)
|
||||
.experimental()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -481,7 +481,7 @@ struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Clone
|
||||
impl < >core::clone::Clone for Foo< >where {
|
||||
impl < >$crate::clone::Clone for Foo< >where {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Foo{}
|
||||
@ -507,7 +507,7 @@ struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Copy
|
||||
impl < >core::marker::Copy for Foo< >where{}"#]],
|
||||
impl < >$crate::marker::Copy for Foo< >where{}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -522,7 +522,7 @@ struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Copy
|
||||
impl < >core::marker::Copy for Foo< >where{}"#]],
|
||||
impl < >$crate::marker::Copy for Foo< >where{}"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
@ -533,7 +533,7 @@ struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Clone
|
||||
impl < >core::clone::Clone for Foo< >where {
|
||||
impl < >$crate::clone::Clone for Foo< >where {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Foo{}
|
||||
|
@ -171,7 +171,7 @@ impl AnalysisHost {
|
||||
}
|
||||
|
||||
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>) {
|
||||
|
@ -322,7 +322,7 @@ fn load_crate_graph(
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfs::loader::Message::Loaded { files } => {
|
||||
vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => {
|
||||
for (path, contents) in files {
|
||||
vfs.set_file_contents(path.into(), contents);
|
||||
}
|
||||
@ -331,9 +331,8 @@ fn load_crate_graph(
|
||||
}
|
||||
let changes = vfs.take_changes();
|
||||
for file in changes {
|
||||
if file.exists() {
|
||||
let contents = vfs.file_contents(file.file_id);
|
||||
if let Ok(text) = std::str::from_utf8(contents) {
|
||||
if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
|
||||
if let Ok(text) = std::str::from_utf8(&v) {
|
||||
analysis_change.change_file(file.file_id, Some(text.into()))
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
drop_bomb = "0.1.5"
|
||||
rustc-dependencies.workspace = true
|
||||
|
||||
ra-ap-rustc_lexer.workspace = true
|
||||
limit.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
@ -24,7 +23,7 @@ stdx.workspace = true
|
||||
sourcegen.workspace = true
|
||||
|
||||
[features]
|
||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
||||
in-rust-tree = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
@ -371,7 +371,15 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik
|
||||
if p.at(op) {
|
||||
m = p.start();
|
||||
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);
|
||||
}
|
||||
let cm = m.complete(p, RANGE_EXPR);
|
||||
|
@ -8,8 +8,6 @@
|
||||
//! Note that these tokens, unlike the tokens we feed into the parser, do
|
||||
//! include info about comments and whitespace.
|
||||
|
||||
use rustc_dependencies::lexer as rustc_lexer;
|
||||
|
||||
use std::ops;
|
||||
|
||||
use rustc_lexer::unescape::{EscapeError, Mode};
|
||||
|
@ -21,6 +21,11 @@
|
||||
#![allow(rustdoc::private_intra_doc_links)]
|
||||
#![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 token_set;
|
||||
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 paths::AbsPathBuf;
|
||||
use span::Span;
|
||||
use std::{fmt, io, sync::Mutex};
|
||||
use triomphe::Arc;
|
||||
use std::{
|
||||
fmt, io,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -81,9 +83,11 @@ impl PartialEq for ProcMacro {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ServerError {
|
||||
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 {
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! Handle process life-time and message passing for proc-macro client
|
||||
|
||||
use std::{
|
||||
io::{self, BufRead, BufReader, Write},
|
||||
io::{self, BufRead, BufReader, Read, Write},
|
||||
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
@ -15,9 +16,11 @@ use crate::{
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ProcMacroProcessSrv {
|
||||
_process: Process,
|
||||
process: Process,
|
||||
stdin: ChildStdin,
|
||||
stdout: BufReader<ChildStdout>,
|
||||
/// Populated when the server exits.
|
||||
server_exited: Option<ServerError>,
|
||||
version: u32,
|
||||
mode: SpanMode,
|
||||
}
|
||||
@ -29,9 +32,10 @@ impl ProcMacroProcessSrv {
|
||||
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
|
||||
|
||||
io::Result::Ok(ProcMacroProcessSrv {
|
||||
_process: process,
|
||||
process,
|
||||
stdin,
|
||||
stdout,
|
||||
server_exited: None,
|
||||
version: 0,
|
||||
mode: SpanMode::Id,
|
||||
})
|
||||
@ -105,8 +109,35 @@ impl ProcMacroProcessSrv {
|
||||
}
|
||||
|
||||
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();
|
||||
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> {
|
||||
Command::new(path.as_os_str())
|
||||
.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
|
||||
let mut cmd = Command::new(path.as_os_str());
|
||||
cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() })
|
||||
.spawn()
|
||||
.stderr(if null_stderr { Stdio::null() } else { Stdio::inherit() });
|
||||
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(
|
||||
@ -145,9 +183,13 @@ fn send_request(
|
||||
req: Request,
|
||||
buf: &mut String,
|
||||
) -> Result<Response, ServerError> {
|
||||
req.write(&mut writer)
|
||||
.map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?;
|
||||
let res = Response::read(&mut reader, buf)
|
||||
.map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?;
|
||||
req.write(&mut writer).map_err(|err| ServerError {
|
||||
message: "failed to write request".into(),
|
||||
io: Some(Arc::new(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 })
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ fn main() -> std::io::Result<()> {
|
||||
|
||||
#[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))]
|
||||
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))]
|
||||
|
@ -37,7 +37,7 @@ expect-test = "1.4.0"
|
||||
proc-macro-test.path = "./proc-macro-test"
|
||||
|
||||
[features]
|
||||
sysroot-abi = ["proc-macro-test/sysroot-abi"]
|
||||
sysroot-abi = []
|
||||
in-rust-tree = ["mbe/in-rust-tree", "sysroot-abi"]
|
||||
|
||||
[lints]
|
||||
|
@ -14,6 +14,3 @@ cargo_metadata = "0.18.1"
|
||||
|
||||
# local deps
|
||||
toolchain.workspace = true
|
||||
|
||||
[features]
|
||||
sysroot-abi = []
|
||||
|
@ -17,11 +17,24 @@ use cargo_metadata::Message;
|
||||
|
||||
fn main() {
|
||||
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 = 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 version = "0.0.0";
|
||||
|
||||
@ -53,15 +66,7 @@ fn main() {
|
||||
|
||||
let target_dir = out_dir.join("target");
|
||||
|
||||
let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") {
|
||||
// leverage rustup to find user-specific toolchain
|
||||
let mut cmd = Command::new("cargo");
|
||||
cmd.arg(format!("+{toolchain}"));
|
||||
cmd
|
||||
} else {
|
||||
Command::new(toolchain::cargo())
|
||||
};
|
||||
|
||||
let mut cmd = Command::new(toolchain::cargo());
|
||||
cmd.current_dir(&staging_dir)
|
||||
.args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
|
||||
// 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.
|
||||
.arg("--target-dir")
|
||||
.arg(&target_dir);
|
||||
if cfg!(feature = "sysroot-abi") {
|
||||
cmd.args(["--features", "sysroot-abi"]);
|
||||
}
|
||||
|
||||
if let Ok(target) = std::env::var("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,
|
||||
# and its own `Cargo.lock`
|
||||
|
||||
[features]
|
||||
sysroot-abi = []
|
||||
|
||||
[workspace]
|
||||
|
@ -1,8 +1,5 @@
|
||||
//! 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)]
|
||||
#![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)…
|
||||
|
||||
#![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)]
|
||||
#![allow(unreachable_pub, internal_features)]
|
||||
|
||||
extern crate proc_macro;
|
||||
#[cfg(feature = "in-rust-tree")]
|
||||
extern crate rustc_driver as _;
|
||||
|
||||
mod dylib;
|
||||
|
@ -1398,7 +1398,7 @@ fn sysroot_to_crate_graph(
|
||||
let public_deps = SysrootPublicDeps {
|
||||
deps: sysroot
|
||||
.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<_>>(),
|
||||
};
|
||||
|
||||
|
@ -49,7 +49,6 @@ flycheck.workspace = true
|
||||
hir-def.workspace = true
|
||||
hir-ty.workspace = true
|
||||
hir.workspace = true
|
||||
rustc-dependencies.workspace = true
|
||||
ide-db.workspace = true
|
||||
# This should only be used in CLI
|
||||
ide-ssr.workspace = true
|
||||
@ -89,7 +88,6 @@ in-rust-tree = [
|
||||
"ide/in-rust-tree",
|
||||
"syntax/in-rust-tree",
|
||||
"parser/in-rust-tree",
|
||||
"rustc-dependencies/in-rust-tree",
|
||||
"hir/in-rust-tree",
|
||||
"hir-def/in-rust-tree",
|
||||
"hir-ty/in-rust-tree",
|
||||
|
@ -3,7 +3,7 @@
|
||||
//!
|
||||
//! 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 flycheck::FlycheckHandle;
|
||||
@ -21,7 +21,7 @@ use proc_macro_api::ProcMacroServer;
|
||||
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use triomphe::Arc;
|
||||
use vfs::{AnchoredPathBuf, Vfs};
|
||||
use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
|
||||
|
||||
use crate::{
|
||||
config::{Config, ConfigError},
|
||||
@ -217,8 +217,8 @@ impl GlobalState {
|
||||
pub(crate) fn process_changes(&mut self) -> bool {
|
||||
let _p = profile::span("GlobalState::process_changes");
|
||||
|
||||
let mut file_changes = FxHashMap::default();
|
||||
let (change, changed_files, workspace_structure_change) = {
|
||||
let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default();
|
||||
let (change, modified_rust_files, workspace_structure_change) = {
|
||||
let mut change = Change::new();
|
||||
let mut guard = self.vfs.write();
|
||||
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
|
||||
// earlier event, to avoid problems later on.
|
||||
for changed_file in changed_files {
|
||||
use vfs::ChangeKind::*;
|
||||
|
||||
file_changes
|
||||
.entry(changed_file.file_id)
|
||||
.and_modify(|(change, just_created)| {
|
||||
// None -> Delete => keep
|
||||
// Create -> Delete => collapse
|
||||
//
|
||||
match (change, just_created, changed_file.change_kind) {
|
||||
use vfs::Change::*;
|
||||
match file_changes.entry(changed_file.file_id) {
|
||||
Entry::Occupied(mut o) => {
|
||||
let (just_created, change) = o.get_mut();
|
||||
match (&mut change.change, just_created, changed_file.change) {
|
||||
// latter `Delete` wins
|
||||
(change, _, Delete) => *change = Delete,
|
||||
// merge `Create` with `Create` or `Modify`
|
||||
(Create, _, Create | Modify) => {}
|
||||
(Create(prev), _, Create(new) | Modify(new)) => *prev = new,
|
||||
// collapse identical `Modify`es
|
||||
(Modify, _, Modify) => {}
|
||||
(Modify(prev), _, Modify(new)) => *prev = new,
|
||||
// equivalent to `Modify`
|
||||
(change @ Delete, just_created, Create) => {
|
||||
*change = Modify;
|
||||
(change @ Delete, just_created, Create(new)) => {
|
||||
*change = Modify(new);
|
||||
*just_created = true;
|
||||
}
|
||||
// shouldn't occur, but collapse into `Create`
|
||||
(change @ Delete, just_created, Modify) => {
|
||||
*change = Create;
|
||||
(change @ Delete, just_created, Modify(new)) => {
|
||||
*change = Create(new);
|
||||
*just_created = true;
|
||||
}
|
||||
// shouldn't occur, but collapse into `Modify`
|
||||
(Modify, _, Create) => {}
|
||||
// shouldn't occur, but keep the Create
|
||||
(prev @ Modify(_), _, new @ Create(_)) => *prev = new,
|
||||
}
|
||||
})
|
||||
.or_insert((
|
||||
changed_file.change_kind,
|
||||
matches!(changed_file.change_kind, Create),
|
||||
));
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
_ = v.insert((matches!(&changed_file.change, Create(_)), changed_file))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let changed_files: Vec<_> = file_changes
|
||||
.into_iter()
|
||||
.filter(|(_, (change_kind, just_created))| {
|
||||
!matches!((change_kind, just_created), (vfs::ChangeKind::Delete, true))
|
||||
.filter(|(_, (just_created, change))| {
|
||||
!(*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();
|
||||
|
||||
let mut workspace_structure_change = None;
|
||||
// A file was added or deleted
|
||||
let mut has_structure_changes = false;
|
||||
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);
|
||||
if let Some(path) = vfs_path.as_path() {
|
||||
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));
|
||||
}
|
||||
if file.is_created_or_deleted() {
|
||||
has_structure_changes = true;
|
||||
workspace_structure_change =
|
||||
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);
|
||||
}
|
||||
|
||||
let text = if file.exists() {
|
||||
let bytes = vfs.file_contents(file.file_id).to_vec();
|
||||
|
||||
String::from_utf8(bytes).ok().and_then(|text| {
|
||||
let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
|
||||
String::from_utf8(v).ok().and_then(|text| {
|
||||
// FIXME: Consider doing normalization in the `vfs` instead? That allows
|
||||
// getting rid of some locking
|
||||
let (text, line_endings) = LineEndings::normalize(text);
|
||||
@ -327,11 +324,10 @@ impl GlobalState {
|
||||
let roots = self.source_root_config.partition(vfs);
|
||||
change.set_roots(roots);
|
||||
}
|
||||
(change, changed_files, workspace_structure_change)
|
||||
(change, modified_rust_files, workspace_structure_change)
|
||||
};
|
||||
|
||||
self.analysis_host.apply_change(change);
|
||||
|
||||
{
|
||||
let raw_database = self.analysis_host.raw_database();
|
||||
// FIXME: ideally we should only trigger a workspace fetch for non-library changes
|
||||
@ -343,13 +339,12 @@ impl GlobalState {
|
||||
force_crate_graph_reload,
|
||||
);
|
||||
}
|
||||
self.proc_macro_changed =
|
||||
changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
|
||||
let crates = raw_database.relevant_crates(file.file_id);
|
||||
let crate_graph = raw_database.crate_graph();
|
||||
self.proc_macro_changed = modified_rust_files.into_iter().any(|file_id| {
|
||||
let crates = raw_database.relevant_crates(file_id);
|
||||
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
|
||||
@ -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 {
|
||||
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) {
|
||||
let already_exists = state
|
||||
.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();
|
||||
if already_exists {
|
||||
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");
|
||||
|
||||
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) => {
|
||||
// The version passed in DidChangeTextDocument is the version after all edits are applied
|
||||
// so we should apply it before the vfs is notified.
|
||||
doc.version = params.text_document.version;
|
||||
&mut doc.data
|
||||
}
|
||||
None => {
|
||||
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(),
|
||||
|| {
|
||||
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()
|
||||
},
|
||||
std::str::from_utf8(data).unwrap(),
|
||||
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(())
|
||||
}
|
||||
|
@ -103,7 +103,6 @@ pub(crate) fn handle_analyzer_status(
|
||||
.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(
|
||||
&snap
|
||||
|
@ -168,7 +168,7 @@ impl GlobalState {
|
||||
|
||||
pub(crate) fn apply_document_changes(
|
||||
encoding: PositionEncoding,
|
||||
file_contents: impl FnOnce() -> String,
|
||||
file_contents: &str,
|
||||
mut content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
|
||||
) -> String {
|
||||
// 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);
|
||||
(text, &content_changes[idx + 1..])
|
||||
}
|
||||
None => (file_contents(), &content_changes[..]),
|
||||
None => (file_contents.to_owned(), &content_changes[..]),
|
||||
};
|
||||
if content_changes.is_empty() {
|
||||
return text;
|
||||
@ -276,11 +276,11 @@ mod tests {
|
||||
}
|
||||
|
||||
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, "");
|
||||
let text = apply_document_changes(
|
||||
encoding,
|
||||
|| text,
|
||||
&text,
|
||||
vec![TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
@ -288,49 +288,46 @@ mod tests {
|
||||
}],
|
||||
);
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
let text = apply_document_changes(
|
||||
encoding,
|
||||
|| text,
|
||||
&text,
|
||||
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");
|
||||
let text = apply_document_changes(
|
||||
encoding,
|
||||
|| text,
|
||||
c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"],
|
||||
);
|
||||
let text =
|
||||
apply_document_changes(encoding, &text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
|
||||
assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
|
||||
let text = apply_document_changes(
|
||||
encoding,
|
||||
|| text,
|
||||
&text,
|
||||
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");
|
||||
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");
|
||||
|
||||
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❤️");
|
||||
|
||||
let text = String::from("a\nb");
|
||||
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");
|
||||
|
||||
let text = String::from("a\nb");
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -571,13 +571,18 @@ impl GlobalState {
|
||||
}
|
||||
|
||||
fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
|
||||
let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
|
||||
match message {
|
||||
vfs::loader::Message::Loaded { files } => {
|
||||
vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
|
||||
let vfs = &mut self.vfs.write().0;
|
||||
for (path, contents) in files {
|
||||
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) {
|
||||
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)]
|
||||
pub(crate) struct DocumentData {
|
||||
pub(crate) version: i32,
|
||||
pub(crate) data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DocumentData {
|
||||
pub(crate) fn new(version: i32) -> Self {
|
||||
DocumentData { version }
|
||||
pub(crate) fn new(version: i32, data: Vec<u8>) -> Self {
|
||||
DocumentData { version, data }
|
||||
}
|
||||
}
|
||||
|
@ -503,10 +503,9 @@ impl GlobalState {
|
||||
match vfs.file_id(&vfs_path) {
|
||||
Some(file_id) => Some(file_id),
|
||||
None => {
|
||||
if !self.mem_docs.contains(&vfs_path) {
|
||||
let contents = loader.handle.load_sync(path);
|
||||
vfs.set_file_contents(vfs_path.clone(), contents);
|
||||
}
|
||||
// FIXME: Consider not loading this here?
|
||||
let contents = loader.handle.load_sync(path);
|
||||
vfs.set_file_contents(vfs_path.clone(), contents);
|
||||
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
|
||||
triomphe.workspace = true
|
||||
|
||||
rustc-dependencies.workspace = true
|
||||
ra-ap-rustc_lexer.workspace = true
|
||||
|
||||
parser.workspace = true
|
||||
profile.workspace = true
|
||||
@ -41,7 +41,7 @@ test-utils.workspace = true
|
||||
sourcegen.workspace = true
|
||||
|
||||
[features]
|
||||
in-rust-tree = ["rustc-dependencies/in-rust-tree"]
|
||||
in-rust-tree = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
@ -285,14 +285,16 @@ impl ast::Path {
|
||||
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 {
|
||||
successors(self.first_segment(), |p| {
|
||||
p.parent_path().parent_path().and_then(|p| p.segment())
|
||||
let path_range = self.syntax().text_range();
|
||||
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())
|
||||
}
|
||||
|
||||
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 {
|
||||
let mut this = self.clone();
|
||||
while let Some(path) = this.parent_path() {
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_dependencies::lexer as rustc_lexer;
|
||||
|
||||
use rustc_lexer::unescape::{
|
||||
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
||||
};
|
||||
|
@ -22,6 +22,11 @@
|
||||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||
#![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)]
|
||||
macro_rules! eprintln {
|
||||
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
|
||||
|
@ -5,7 +5,7 @@
|
||||
mod block;
|
||||
|
||||
use rowan::Direction;
|
||||
use rustc_dependencies::lexer::unescape::{self, unescape_literal, Mode};
|
||||
use rustc_lexer::unescape::{self, unescape_literal, Mode};
|
||||
|
||||
use crate::{
|
||||
algo,
|
||||
|
@ -25,6 +25,7 @@
|
||||
//! derive:
|
||||
//! discriminant:
|
||||
//! drop:
|
||||
//! env: option
|
||||
//! eq: sized
|
||||
//! error: fmt
|
||||
//! fmt: result, transmute, coerce_unsized
|
||||
@ -1450,6 +1451,15 @@ mod macros {
|
||||
#[macro_export]
|
||||
macro_rules! 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
|
||||
|
@ -160,7 +160,7 @@ impl NotifyActor {
|
||||
Some((path, contents))
|
||||
})
|
||||
.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