mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Rudimentary name resolution for local items
This commit is contained in:
parent
7c405c0156
commit
e424545c0f
6 changed files with 145 additions and 49 deletions
|
@ -494,45 +494,57 @@ where
|
|||
fn collect_block_items(&mut self, block: &ast::Block) {
|
||||
let container = ContainerId::DefWithBodyId(self.def);
|
||||
for item in block.items() {
|
||||
let def: ModuleDefId = match item {
|
||||
let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
|
||||
ast::ModuleItem::FnDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
FunctionLoc { container: container.into(), ast_id }.intern(self.db).into()
|
||||
(
|
||||
FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(),
|
||||
def.name(),
|
||||
)
|
||||
}
|
||||
ast::ModuleItem::TypeAliasDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into()
|
||||
(
|
||||
TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(),
|
||||
def.name(),
|
||||
)
|
||||
}
|
||||
ast::ModuleItem::ConstDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
ConstLoc { container: container.into(), ast_id }.intern(self.db).into()
|
||||
(
|
||||
ConstLoc { container: container.into(), ast_id }.intern(self.db).into(),
|
||||
def.name(),
|
||||
)
|
||||
}
|
||||
ast::ModuleItem::StaticDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
StaticLoc { container, ast_id }.intern(self.db).into()
|
||||
(StaticLoc { container, ast_id }.intern(self.db).into(), def.name())
|
||||
}
|
||||
ast::ModuleItem::StructDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
StructLoc { container, ast_id }.intern(self.db).into()
|
||||
(StructLoc { container, ast_id }.intern(self.db).into(), def.name())
|
||||
}
|
||||
ast::ModuleItem::EnumDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
EnumLoc { container, ast_id }.intern(self.db).into()
|
||||
(EnumLoc { container, ast_id }.intern(self.db).into(), def.name())
|
||||
}
|
||||
ast::ModuleItem::UnionDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
UnionLoc { container, ast_id }.intern(self.db).into()
|
||||
(UnionLoc { container, ast_id }.intern(self.db).into(), def.name())
|
||||
}
|
||||
ast::ModuleItem::TraitDef(def) => {
|
||||
let ast_id = self.expander.ast_id(&def);
|
||||
TraitLoc { container, ast_id }.intern(self.db).into()
|
||||
(TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
|
||||
}
|
||||
ast::ModuleItem::ImplBlock(_)
|
||||
| ast::ModuleItem::UseItem(_)
|
||||
| ast::ModuleItem::ExternCrateItem(_)
|
||||
| ast::ModuleItem::Module(_) => continue,
|
||||
};
|
||||
self.body.item_scope.define_def(def)
|
||||
self.body.item_scope.define_def(def);
|
||||
if let Some(name) = name {
|
||||
self.body.item_scope.push_res(name.as_name(), def.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,12 @@ impl ItemScope {
|
|||
self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def))
|
||||
}
|
||||
|
||||
pub fn entries_without_primitives<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
|
||||
self.visible.iter().map(|(n, def)| (n, *def))
|
||||
}
|
||||
|
||||
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
|
||||
self.defs.iter().copied()
|
||||
}
|
||||
|
@ -118,7 +124,7 @@ impl ItemScope {
|
|||
self.legacy_macros.insert(name, mac);
|
||||
}
|
||||
|
||||
pub(crate) fn push_res(&mut self, name: Name, def: &PerNs) -> bool {
|
||||
pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
|
||||
let mut changed = false;
|
||||
let existing = self.visible.entry(name.clone()).or_default();
|
||||
|
||||
|
|
|
@ -446,7 +446,7 @@ where
|
|||
let scope = &mut self.def_map.modules[module_id].scope;
|
||||
let mut changed = false;
|
||||
for (name, res) in resolutions {
|
||||
changed |= scope.push_res(name.clone(), res);
|
||||
changed |= scope.push_res(name.clone(), *res);
|
||||
}
|
||||
|
||||
if !changed {
|
||||
|
|
|
@ -10,6 +10,7 @@ use rustc_hash::FxHashSet;
|
|||
|
||||
use crate::{
|
||||
body::scope::{ExprScopes, ScopeId},
|
||||
body::Body,
|
||||
builtin_type::BuiltinType,
|
||||
db::DefDatabase,
|
||||
expr::{ExprId, PatId},
|
||||
|
@ -55,6 +56,8 @@ enum Scope {
|
|||
AdtScope(AdtId),
|
||||
/// Local bindings
|
||||
ExprScope(ExprScope),
|
||||
/// Temporary hack to support local items.
|
||||
LocalItemsScope(Arc<Body>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -149,7 +152,13 @@ impl Resolver {
|
|||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
Scope::ExprScope(_) => continue,
|
||||
Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue,
|
||||
Scope::GenericParams { .. }
|
||||
| Scope::ImplBlockScope(_)
|
||||
| Scope::LocalItemsScope(_)
|
||||
if skip_to_mod =>
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
Scope::GenericParams { params, def } => {
|
||||
if let Some(local_id) = params.find_by_name(first_name) {
|
||||
|
@ -179,25 +188,35 @@ impl Resolver {
|
|||
&path,
|
||||
BuiltinShadowMode::Other,
|
||||
);
|
||||
let res = match module_def.take_types()? {
|
||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
|
||||
|
||||
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
|
||||
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
|
||||
|
||||
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
|
||||
|
||||
ModuleDefId::FunctionId(_)
|
||||
| ModuleDefId::ConstId(_)
|
||||
| ModuleDefId::StaticId(_)
|
||||
| ModuleDefId::ModuleId(_) => return None,
|
||||
};
|
||||
let res = to_type_ns(module_def)?;
|
||||
return Some((res, idx));
|
||||
}
|
||||
Scope::LocalItemsScope(body) => {
|
||||
let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
|
||||
if let Some(res) = to_type_ns(def) {
|
||||
return Some((res, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
return None;
|
||||
fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
|
||||
let res = match per_ns.take_types()? {
|
||||
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
|
||||
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
|
||||
|
||||
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
|
||||
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
|
||||
|
||||
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
|
||||
|
||||
ModuleDefId::FunctionId(_)
|
||||
| ModuleDefId::ConstId(_)
|
||||
| ModuleDefId::StaticId(_)
|
||||
| ModuleDefId::ModuleId(_) => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_path_in_type_ns_fully(
|
||||
|
@ -227,6 +246,7 @@ impl Resolver {
|
|||
| Scope::ExprScope(_)
|
||||
| Scope::GenericParams { .. }
|
||||
| Scope::ImplBlockScope(_)
|
||||
| Scope::LocalItemsScope(_)
|
||||
if skip_to_mod =>
|
||||
{
|
||||
continue
|
||||
|
@ -276,20 +296,7 @@ impl Resolver {
|
|||
);
|
||||
return match idx {
|
||||
None => {
|
||||
let value = match module_def.take_values()? {
|
||||
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
|
||||
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
|
||||
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
|
||||
ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
|
||||
ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
|
||||
|
||||
ModuleDefId::AdtId(AdtId::EnumId(_))
|
||||
| ModuleDefId::AdtId(AdtId::UnionId(_))
|
||||
| ModuleDefId::TraitId(_)
|
||||
| ModuleDefId::TypeAliasId(_)
|
||||
| ModuleDefId::BuiltinType(_)
|
||||
| ModuleDefId::ModuleId(_) => return None,
|
||||
};
|
||||
let value = to_value_ns(module_def)?;
|
||||
Some(ResolveValueResult::ValueNs(value))
|
||||
}
|
||||
Some(idx) => {
|
||||
|
@ -309,9 +316,33 @@ impl Resolver {
|
|||
}
|
||||
};
|
||||
}
|
||||
Scope::LocalItemsScope(body) => {
|
||||
let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
|
||||
if let Some(res) = to_value_ns(def) {
|
||||
return Some(ResolveValueResult::ValueNs(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
return None;
|
||||
|
||||
fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
|
||||
let res = match per_ns.take_values()? {
|
||||
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
|
||||
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
|
||||
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
|
||||
ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
|
||||
ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
|
||||
|
||||
ModuleDefId::AdtId(AdtId::EnumId(_))
|
||||
| ModuleDefId::AdtId(AdtId::UnionId(_))
|
||||
| ModuleDefId::TraitId(_)
|
||||
| ModuleDefId::TypeAliasId(_)
|
||||
| ModuleDefId::BuiltinType(_)
|
||||
| ModuleDefId::ModuleId(_) => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_path_in_value_ns_fully(
|
||||
|
@ -429,6 +460,11 @@ impl Scope {
|
|||
});
|
||||
}
|
||||
}
|
||||
Scope::LocalItemsScope(body) => {
|
||||
body.item_scope.entries_without_primitives().for_each(|(name, def)| {
|
||||
f(name.clone(), ScopeDef::PerNs(def));
|
||||
})
|
||||
}
|
||||
Scope::GenericParams { params, def } => {
|
||||
for (local_id, param) in params.types.iter() {
|
||||
f(
|
||||
|
@ -464,6 +500,7 @@ pub fn resolver_for_scope(
|
|||
scope_id: Option<ScopeId>,
|
||||
) -> Resolver {
|
||||
let mut r = owner.resolver(db);
|
||||
r = r.push_local_items_scope(db.body(owner));
|
||||
let scopes = db.expr_scopes(owner);
|
||||
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
|
||||
for scope in scope_chain.into_iter().rev() {
|
||||
|
@ -499,6 +536,10 @@ impl Resolver {
|
|||
self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
|
||||
}
|
||||
|
||||
fn push_local_items_scope(self, body: Arc<Body>) -> Resolver {
|
||||
self.push_scope(Scope::LocalItemsScope(body))
|
||||
}
|
||||
|
||||
fn push_expr_scope(
|
||||
self,
|
||||
owner: DefWithBodyId,
|
||||
|
|
|
@ -1512,8 +1512,8 @@ fn test() {
|
|||
[49; 50) '0': u32
|
||||
[80; 83) '101': u32
|
||||
[95; 213) '{ ...NST; }': ()
|
||||
[138; 139) 'x': {unknown}
|
||||
[142; 153) 'LOCAL_CONST': {unknown}
|
||||
[138; 139) 'x': u32
|
||||
[142; 153) 'LOCAL_CONST': u32
|
||||
[163; 164) 'z': u32
|
||||
[167; 179) 'GLOBAL_CONST': u32
|
||||
[189; 191) 'id': u32
|
||||
|
@ -1541,10 +1541,10 @@ fn test() {
|
|||
[29; 32) '101': u32
|
||||
[70; 73) '101': u32
|
||||
[85; 280) '{ ...MUT; }': ()
|
||||
[173; 174) 'x': {unknown}
|
||||
[177; 189) 'LOCAL_STATIC': {unknown}
|
||||
[199; 200) 'y': {unknown}
|
||||
[203; 219) 'LOCAL_...IC_MUT': {unknown}
|
||||
[173; 174) 'x': u32
|
||||
[177; 189) 'LOCAL_STATIC': u32
|
||||
[199; 200) 'y': u32
|
||||
[203; 219) 'LOCAL_...IC_MUT': u32
|
||||
[229; 230) 'z': u32
|
||||
[233; 246) 'GLOBAL_STATIC': u32
|
||||
[256; 257) 'w': u32
|
||||
|
|
|
@ -873,4 +873,41 @@ mod tests {
|
|||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_local_item() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
fn main() {
|
||||
return f<|>;
|
||||
fn frobnicate() {}
|
||||
}
|
||||
"
|
||||
),
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "frobnicate()",
|
||||
source_range: [23; 24),
|
||||
delete: [23; 24),
|
||||
insert: "frobnicate()$0",
|
||||
kind: Function,
|
||||
lookup: "frobnicate",
|
||||
detail: "fn frobnicate()",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "main()",
|
||||
source_range: [23; 24),
|
||||
delete: [23; 24),
|
||||
insert: "main()$0",
|
||||
kind: Function,
|
||||
lookup: "main",
|
||||
detail: "fn main()",
|
||||
},
|
||||
]
|
||||
"###
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue