mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-27 07:03:45 +00:00
Merge #6243
6243: Clarify classification API r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
d8c6e192f7
@ -1,4 +1,4 @@
|
||||
use ide_db::defs::{classify_name_ref, Definition, NameRefClass};
|
||||
use ide_db::defs::{Definition, NameRefClass};
|
||||
use syntax::{ast, AstNode, SyntaxKind, T};
|
||||
use test_utils::mark;
|
||||
|
||||
@ -39,7 +39,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
|
||||
return None;
|
||||
}
|
||||
let name_ref = ast::NameRef::cast(ident.parent())?;
|
||||
let def = match classify_name_ref(&ctx.sema, &name_ref)? {
|
||||
let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
|
||||
NameRefClass::Definition(def) => def,
|
||||
NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use either::Either;
|
||||
use hir::{AssocItem, MacroDef, Module, ModuleDef, Name, PathResolution, ScopeDef};
|
||||
use ide_db::{
|
||||
defs::{classify_name_ref, Definition, NameRefClass},
|
||||
defs::{Definition, NameRefClass},
|
||||
search::SearchScope,
|
||||
};
|
||||
use syntax::{
|
||||
@ -217,7 +217,7 @@ fn find_imported_defs(ctx: &AssistContext, star: SyntaxToken) -> Option<Vec<Def>
|
||||
.flatten()
|
||||
.filter_map(|n| Some(n.descendants().filter_map(ast::NameRef::cast)))
|
||||
.flatten()
|
||||
.filter_map(|r| match classify_name_ref(&ctx.sema, &r)? {
|
||||
.filter_map(|r| match NameRefClass::classify(&ctx.sema, &r)? {
|
||||
NameRefClass::Definition(Definition::ModuleDef(def)) => Some(Def::ModuleDef(def)),
|
||||
NameRefClass::Definition(Definition::Macro(def)) => Some(Def::MacroDef(def)),
|
||||
_ => None,
|
||||
|
@ -14,7 +14,7 @@ use hir::{
|
||||
ModuleDef,
|
||||
};
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
RootDatabase,
|
||||
};
|
||||
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
|
||||
@ -232,8 +232,8 @@ pub(crate) fn external_docs(
|
||||
let node = token.parent();
|
||||
let definition = match_ast! {
|
||||
match node {
|
||||
ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)),
|
||||
ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition(sema.db)),
|
||||
ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
|
||||
ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use hir::Semantics;
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref},
|
||||
defs::{NameClass, NameRefClass},
|
||||
symbol_index, RootDatabase,
|
||||
};
|
||||
use syntax::{
|
||||
@ -40,7 +40,7 @@ pub(crate) fn goto_definition(
|
||||
reference_definition(&sema, &name_ref).to_vec()
|
||||
},
|
||||
ast::Name(name) => {
|
||||
let def = classify_name(&sema, &name)?.definition(sema.db);
|
||||
let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
|
||||
let nav = def.try_to_nav(sema.db)?;
|
||||
vec![nav]
|
||||
},
|
||||
@ -81,9 +81,9 @@ pub(crate) fn reference_definition(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
name_ref: &ast::NameRef,
|
||||
) -> ReferenceResult {
|
||||
let name_kind = classify_name_ref(sema, name_ref);
|
||||
let name_kind = NameRefClass::classify(sema, name_ref);
|
||||
if let Some(def) = name_kind {
|
||||
let def = def.definition(sema.db);
|
||||
let def = def.referenced(sema.db);
|
||||
return match def.try_to_nav(sema.db) {
|
||||
Some(nav) => ReferenceResult::Exact(nav),
|
||||
None => ReferenceResult::Approximate(Vec::new()),
|
||||
|
@ -4,7 +4,7 @@ use hir::{
|
||||
Module, ModuleDef, ModuleSource, Semantics,
|
||||
};
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
RootDatabase,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
@ -107,8 +107,8 @@ pub(crate) fn hover(
|
||||
let node = token.parent();
|
||||
let definition = match_ast! {
|
||||
match node {
|
||||
ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)),
|
||||
ast::Name(name) => classify_name(&sema, &name).and_then(|d| d.into_definition(sema.db)),
|
||||
ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)),
|
||||
ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
@ -13,7 +13,7 @@ pub(crate) mod rename;
|
||||
|
||||
use hir::Semantics;
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
search::SearchScope,
|
||||
RootDatabase,
|
||||
};
|
||||
@ -132,13 +132,13 @@ fn find_name(
|
||||
opt_name: Option<ast::Name>,
|
||||
) -> Option<RangeInfo<Definition>> {
|
||||
if let Some(name) = opt_name {
|
||||
let def = classify_name(sema, &name)?.definition(sema.db);
|
||||
let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db);
|
||||
let range = name.syntax().text_range();
|
||||
return Some(RangeInfo::new(range, def));
|
||||
}
|
||||
let name_ref =
|
||||
sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
|
||||
let def = classify_name_ref(sema, &name_ref)?.definition(sema.db);
|
||||
let def = NameRefClass::classify(sema, &name_ref)?.referenced(sema.db);
|
||||
let range = name_ref.syntax().text_range();
|
||||
Some(RangeInfo::new(range, def))
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
use base_db::SourceDatabaseExt;
|
||||
use hir::{Module, ModuleDef, ModuleSource, Semantics};
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
RootDatabase,
|
||||
};
|
||||
|
||||
@ -88,13 +88,13 @@ fn find_module_at_offset(
|
||||
let module = match_ast! {
|
||||
match (ident.parent()) {
|
||||
ast::NameRef(name_ref) => {
|
||||
match classify_name_ref(sema, &name_ref)? {
|
||||
match NameRefClass::classify(sema, &name_ref)? {
|
||||
NameRefClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
|
||||
_ => return None,
|
||||
}
|
||||
},
|
||||
ast::Name(name) => {
|
||||
match classify_name(&sema, &name)? {
|
||||
match NameClass::classify(&sema, &name)? {
|
||||
NameClass::Definition(Definition::ModuleDef(ModuleDef::Module(module))) => module,
|
||||
_ => return None,
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ mod tests;
|
||||
|
||||
use hir::{Local, Name, Semantics, VariantDef};
|
||||
use ide_db::{
|
||||
defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
|
||||
defs::{Definition, NameClass, NameRefClass},
|
||||
RootDatabase,
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
@ -443,7 +443,7 @@ fn highlight_element(
|
||||
// Highlight definitions depending on the "type" of the definition.
|
||||
NAME => {
|
||||
let name = element.into_node().and_then(ast::Name::cast).unwrap();
|
||||
let name_kind = classify_name(sema, &name);
|
||||
let name_kind = NameClass::classify(sema, &name);
|
||||
|
||||
if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
|
||||
if let Some(name) = local.name(db) {
|
||||
@ -459,9 +459,9 @@ fn highlight_element(
|
||||
highlight_def(db, def) | HighlightModifier::Definition
|
||||
}
|
||||
Some(NameClass::ConstReference(def)) => highlight_def(db, def),
|
||||
Some(NameClass::FieldShorthand { field, .. }) => {
|
||||
Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
|
||||
let mut h = HighlightTag::Field.into();
|
||||
if let Definition::Field(field) = field {
|
||||
if let Definition::Field(field) = field_ref {
|
||||
if let VariantDef::Union(_) = field.parent_def(db) {
|
||||
h |= HighlightModifier::Unsafe;
|
||||
}
|
||||
@ -480,7 +480,7 @@ fn highlight_element(
|
||||
NAME_REF => {
|
||||
let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
|
||||
highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
|
||||
match classify_name_ref(sema, &name_ref) {
|
||||
match NameRefClass::classify(sema, &name_ref) {
|
||||
Some(name_kind) => match name_kind {
|
||||
NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
|
||||
NameRefClass::Definition(def) => {
|
||||
|
@ -81,146 +81,152 @@ impl Definition {
|
||||
pub enum NameClass {
|
||||
ExternCrate(Crate),
|
||||
Definition(Definition),
|
||||
/// `None` in `if let None = Some(82) {}`
|
||||
/// `None` in `if let None = Some(82) {}`.
|
||||
ConstReference(Definition),
|
||||
FieldShorthand {
|
||||
local: Local,
|
||||
field: Definition,
|
||||
/// `field` in `if let Foo { field } = foo`.
|
||||
PatFieldShorthand {
|
||||
local_def: Local,
|
||||
field_ref: Definition,
|
||||
},
|
||||
}
|
||||
|
||||
impl NameClass {
|
||||
pub fn into_definition(self, db: &dyn HirDatabase) -> Option<Definition> {
|
||||
Some(match self {
|
||||
/// `Definition` defined by this name.
|
||||
pub fn defined(self, db: &dyn HirDatabase) -> Option<Definition> {
|
||||
let res = match self {
|
||||
NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
|
||||
NameClass::Definition(it) => it,
|
||||
NameClass::ConstReference(_) => return None,
|
||||
NameClass::FieldShorthand { local, field: _ } => Definition::Local(local),
|
||||
})
|
||||
NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
|
||||
Definition::Local(local_def)
|
||||
}
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn definition(self, db: &dyn HirDatabase) -> Definition {
|
||||
/// `Definition` referenced or defined by this name.
|
||||
pub fn referenced_or_defined(self, db: &dyn HirDatabase) -> Definition {
|
||||
match self {
|
||||
NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
|
||||
NameClass::Definition(it) | NameClass::ConstReference(it) => it,
|
||||
NameClass::FieldShorthand { local: _, field } => field,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
|
||||
let _p = profile::span("classify_name");
|
||||
|
||||
let parent = name.syntax().parent()?;
|
||||
|
||||
if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) {
|
||||
if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
|
||||
return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
|
||||
NameClass::PatFieldShorthand { local_def: _, field_ref } => field_ref,
|
||||
}
|
||||
}
|
||||
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::Rename(it) => {
|
||||
if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
|
||||
let path = use_tree.path()?;
|
||||
let path_segment = path.segment()?;
|
||||
let name_ref_class = path_segment
|
||||
.name_ref()
|
||||
// The rename might be from a `self` token, so fallback to the name higher
|
||||
// in the use tree.
|
||||
.or_else(||{
|
||||
if path_segment.self_token().is_none() {
|
||||
return None;
|
||||
pub fn classify(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
|
||||
let _p = profile::span("classify_name");
|
||||
|
||||
let parent = name.syntax().parent()?;
|
||||
|
||||
if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) {
|
||||
if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
|
||||
return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
|
||||
}
|
||||
}
|
||||
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::Rename(it) => {
|
||||
if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
|
||||
let path = use_tree.path()?;
|
||||
let path_segment = path.segment()?;
|
||||
let name_ref_class = path_segment
|
||||
.name_ref()
|
||||
// The rename might be from a `self` token, so fallback to the name higher
|
||||
// in the use tree.
|
||||
.or_else(||{
|
||||
if path_segment.self_token().is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let use_tree = use_tree
|
||||
.syntax()
|
||||
.parent()
|
||||
.as_ref()
|
||||
// Skip over UseTreeList
|
||||
.and_then(SyntaxNode::parent)
|
||||
.and_then(ast::UseTree::cast)?;
|
||||
let path = use_tree.path()?;
|
||||
let path_segment = path.segment()?;
|
||||
path_segment.name_ref()
|
||||
})
|
||||
.and_then(|name_ref| NameRefClass::classify(sema, &name_ref))?;
|
||||
|
||||
Some(NameClass::Definition(name_ref_class.referenced(sema.db)))
|
||||
} else {
|
||||
let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
|
||||
let resolved = sema.resolve_extern_crate(&extern_crate)?;
|
||||
Some(NameClass::ExternCrate(resolved))
|
||||
}
|
||||
},
|
||||
ast::IdentPat(it) => {
|
||||
let local = sema.to_def(&it)?;
|
||||
|
||||
if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
|
||||
if record_pat_field.name_ref().is_none() {
|
||||
if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
|
||||
let field = Definition::Field(field);
|
||||
return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field });
|
||||
}
|
||||
|
||||
let use_tree = use_tree
|
||||
.syntax()
|
||||
.parent()
|
||||
.as_ref()
|
||||
// Skip over UseTreeList
|
||||
.and_then(SyntaxNode::parent)
|
||||
.and_then(ast::UseTree::cast)?;
|
||||
let path = use_tree.path()?;
|
||||
let path_segment = path.segment()?;
|
||||
path_segment.name_ref()
|
||||
})
|
||||
.and_then(|name_ref| classify_name_ref(sema, &name_ref))?;
|
||||
|
||||
Some(NameClass::Definition(name_ref_class.definition(sema.db)))
|
||||
} else {
|
||||
let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
|
||||
let resolved = sema.resolve_extern_crate(&extern_crate)?;
|
||||
Some(NameClass::ExternCrate(resolved))
|
||||
}
|
||||
},
|
||||
ast::IdentPat(it) => {
|
||||
let local = sema.to_def(&it)?;
|
||||
|
||||
if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
|
||||
if record_pat_field.name_ref().is_none() {
|
||||
if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
|
||||
let field = Definition::Field(field);
|
||||
return Some(NameClass::FieldShorthand { local, field });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(NameClass::Definition(Definition::Local(local)))
|
||||
},
|
||||
ast::RecordField(it) => {
|
||||
let field: hir::Field = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::Field(field)))
|
||||
},
|
||||
ast::Module(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Struct(it) => {
|
||||
let def: hir::Struct = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Union(it) => {
|
||||
let def: hir::Union = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Enum(it) => {
|
||||
let def: hir::Enum = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Trait(it) => {
|
||||
let def: hir::Trait = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Static(it) => {
|
||||
let def: hir::Static = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Variant(it) => {
|
||||
let def: hir::EnumVariant = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Fn(it) => {
|
||||
let def: hir::Function = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Const(it) => {
|
||||
let def: hir::Const = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::TypeAlias(it) => {
|
||||
let def: hir::TypeAlias = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::Macro(def)))
|
||||
},
|
||||
ast::TypeParam(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::TypeParam(def)))
|
||||
},
|
||||
_ => None,
|
||||
Some(NameClass::Definition(Definition::Local(local)))
|
||||
},
|
||||
ast::RecordField(it) => {
|
||||
let field: hir::Field = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::Field(field)))
|
||||
},
|
||||
ast::Module(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Struct(it) => {
|
||||
let def: hir::Struct = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Union(it) => {
|
||||
let def: hir::Union = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Enum(it) => {
|
||||
let def: hir::Enum = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Trait(it) => {
|
||||
let def: hir::Trait = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Static(it) => {
|
||||
let def: hir::Static = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Variant(it) => {
|
||||
let def: hir::EnumVariant = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Fn(it) => {
|
||||
let def: hir::Function = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::Const(it) => {
|
||||
let def: hir::Const = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::TypeAlias(it) => {
|
||||
let def: hir::TypeAlias = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::ModuleDef(def.into())))
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::Macro(def)))
|
||||
},
|
||||
ast::TypeParam(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::TypeParam(def)))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,102 +235,109 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
|
||||
pub enum NameRefClass {
|
||||
ExternCrate(Crate),
|
||||
Definition(Definition),
|
||||
FieldShorthand { local: Local, field: Definition },
|
||||
FieldShorthand { local_ref: Local, field_ref: Definition },
|
||||
}
|
||||
|
||||
impl NameRefClass {
|
||||
pub fn definition(self, db: &dyn HirDatabase) -> Definition {
|
||||
/// `Definition`, which this name refers to.
|
||||
pub fn referenced(self, db: &dyn HirDatabase) -> Definition {
|
||||
match self {
|
||||
NameRefClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
|
||||
NameRefClass::Definition(def) => def,
|
||||
NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: we don't have unit-tests for this rather important function.
|
||||
// It is primarily exercised via goto definition tests in `ide`.
|
||||
pub fn classify_name_ref(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
name_ref: &ast::NameRef,
|
||||
) -> Option<NameRefClass> {
|
||||
let _p = profile::span("classify_name_ref");
|
||||
|
||||
let parent = name_ref.syntax().parent()?;
|
||||
|
||||
if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
|
||||
if let Some(func) = sema.resolve_method_call(&method_call) {
|
||||
return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
|
||||
if let Some(field) = sema.resolve_field(&field_expr) {
|
||||
return Some(NameRefClass::Definition(Definition::Field(field)));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
|
||||
if let Some((field, local)) = sema.resolve_record_field(&record_field) {
|
||||
let field = Definition::Field(field);
|
||||
let res = match local {
|
||||
None => NameRefClass::Definition(field),
|
||||
Some(local) => NameRefClass::FieldShorthand { field, local },
|
||||
};
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) {
|
||||
if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
|
||||
let field = Definition::Field(field);
|
||||
return Some(NameRefClass::Definition(field));
|
||||
}
|
||||
}
|
||||
|
||||
if ast::AssocTypeArg::cast(parent.clone()).is_some() {
|
||||
// `Trait<Assoc = Ty>`
|
||||
// ^^^^^
|
||||
let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
|
||||
let resolved = sema.resolve_path(&path)?;
|
||||
if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
|
||||
if let Some(ty) = tr
|
||||
.items(sema.db)
|
||||
.iter()
|
||||
.filter_map(|assoc| match assoc {
|
||||
hir::AssocItem::TypeAlias(it) => Some(*it),
|
||||
_ => None,
|
||||
})
|
||||
.find(|alias| alias.name(sema.db).to_string() == **name_ref.text())
|
||||
{
|
||||
return Some(NameRefClass::Definition(Definition::ModuleDef(
|
||||
ModuleDef::TypeAlias(ty),
|
||||
)));
|
||||
NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
|
||||
// FIXME: this is inherently ambiguous -- this name refers to
|
||||
// two different defs....
|
||||
Definition::Local(local_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
|
||||
if let Some(path) = macro_call.path() {
|
||||
if path.qualifier().is_none() {
|
||||
// Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
|
||||
// paths are handled below (allowing `log<|>::info!` to resolve to the log crate).
|
||||
if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
|
||||
return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
|
||||
// Note: we don't have unit-tests for this rather important function.
|
||||
// It is primarily exercised via goto definition tests in `ide`.
|
||||
pub fn classify(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
name_ref: &ast::NameRef,
|
||||
) -> Option<NameRefClass> {
|
||||
let _p = profile::span("classify_name_ref");
|
||||
|
||||
let parent = name_ref.syntax().parent()?;
|
||||
|
||||
if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
|
||||
if let Some(func) = sema.resolve_method_call(&method_call) {
|
||||
return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
|
||||
if let Some(field) = sema.resolve_field(&field_expr) {
|
||||
return Some(NameRefClass::Definition(Definition::Field(field)));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
|
||||
if let Some((field, local)) = sema.resolve_record_field(&record_field) {
|
||||
let field = Definition::Field(field);
|
||||
let res = match local {
|
||||
None => NameRefClass::Definition(field),
|
||||
Some(local) => {
|
||||
NameRefClass::FieldShorthand { field_ref: field, local_ref: local }
|
||||
}
|
||||
};
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) {
|
||||
if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
|
||||
let field = Definition::Field(field);
|
||||
return Some(NameRefClass::Definition(field));
|
||||
}
|
||||
}
|
||||
|
||||
if ast::AssocTypeArg::cast(parent.clone()).is_some() {
|
||||
// `Trait<Assoc = Ty>`
|
||||
// ^^^^^
|
||||
let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
|
||||
let resolved = sema.resolve_path(&path)?;
|
||||
if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
|
||||
if let Some(ty) = tr
|
||||
.items(sema.db)
|
||||
.iter()
|
||||
.filter_map(|assoc| match assoc {
|
||||
hir::AssocItem::TypeAlias(it) => Some(*it),
|
||||
_ => None,
|
||||
})
|
||||
.find(|alias| alias.name(sema.db).to_string() == **name_ref.text())
|
||||
{
|
||||
return Some(NameRefClass::Definition(Definition::ModuleDef(
|
||||
ModuleDef::TypeAlias(ty),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
|
||||
if let Some(resolved) = sema.resolve_path(&path) {
|
||||
return Some(NameRefClass::Definition(resolved.into()));
|
||||
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
|
||||
if let Some(path) = macro_call.path() {
|
||||
if path.qualifier().is_none() {
|
||||
// Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
|
||||
// paths are handled below (allowing `log<|>::info!` to resolve to the log crate).
|
||||
if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
|
||||
return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let extern_crate = ast::ExternCrate::cast(parent)?;
|
||||
let resolved = sema.resolve_extern_crate(&extern_crate)?;
|
||||
Some(NameRefClass::ExternCrate(resolved))
|
||||
if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
|
||||
if let Some(resolved) = sema.resolve_path(&path) {
|
||||
return Some(NameRefClass::Definition(resolved.into()));
|
||||
}
|
||||
}
|
||||
|
||||
let extern_crate = ast::ExternCrate::cast(parent)?;
|
||||
let resolved = sema.resolve_extern_crate(&extern_crate)?;
|
||||
Some(NameRefClass::ExternCrate(resolved))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PathResolution> for Definition {
|
||||
|
@ -5,7 +5,7 @@ use hir::{Crate, MacroDef, ModuleDef, Semantics};
|
||||
use syntax::{ast, AstNode, SyntaxKind::NAME};
|
||||
|
||||
use crate::{
|
||||
defs::{classify_name, Definition},
|
||||
defs::{Definition, NameClass},
|
||||
symbol_index::{self, FileSymbol, Query},
|
||||
RootDatabase,
|
||||
};
|
||||
@ -60,5 +60,5 @@ fn get_name_definition<'a>(
|
||||
candidate_node
|
||||
};
|
||||
let name = ast::Name::cast(candidate_name_node)?;
|
||||
classify_name(sema, &name)?.into_definition(sema.db)
|
||||
NameClass::classify(sema, &name)?.defined(sema.db)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
||||
|
||||
use crate::defs::NameClass;
|
||||
use crate::{
|
||||
defs::{classify_name, classify_name_ref, Definition, NameRefClass},
|
||||
defs::{Definition, NameRefClass},
|
||||
RootDatabase,
|
||||
};
|
||||
|
||||
@ -276,7 +276,7 @@ impl<'a> FindUsages<'a> {
|
||||
name_ref: &ast::NameRef,
|
||||
sink: &mut dyn FnMut(Reference) -> bool,
|
||||
) -> bool {
|
||||
match classify_name_ref(self.sema, &name_ref) {
|
||||
match NameRefClass::classify(self.sema, &name_ref) {
|
||||
Some(NameRefClass::Definition(def)) if &def == self.def => {
|
||||
let kind = if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref)
|
||||
{
|
||||
@ -292,7 +292,7 @@ impl<'a> FindUsages<'a> {
|
||||
};
|
||||
sink(reference)
|
||||
}
|
||||
Some(NameRefClass::FieldShorthand { local, field }) => {
|
||||
Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
|
||||
let reference = match self.def {
|
||||
Definition::Field(_) if &field == self.def => Reference {
|
||||
file_range: self.sema.original_range(name_ref.syntax()),
|
||||
@ -313,10 +313,10 @@ impl<'a> FindUsages<'a> {
|
||||
}
|
||||
|
||||
fn found_name(&self, name: &ast::Name, sink: &mut dyn FnMut(Reference) -> bool) -> bool {
|
||||
match classify_name(self.sema, name) {
|
||||
Some(NameClass::FieldShorthand { local: _, field }) => {
|
||||
match NameClass::classify(self.sema, name) {
|
||||
Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) => {
|
||||
let reference = match self.def {
|
||||
Definition::Field(_) if &field == self.def => Reference {
|
||||
Definition::Field(_) if &field_ref == self.def => Reference {
|
||||
file_range: self.sema.original_range(name.syntax()),
|
||||
kind: ReferenceKind::FieldShorthandForField,
|
||||
// FIXME: mutable patterns should have `Write` access
|
||||
|
Loading…
Reference in New Issue
Block a user