1 //! `NameDefinition` keeps information about the element we want to search references for.
2 //! The element is represented by `NameKind`. It's located inside some `container` and
3 //! has a `visibility`, which defines a search scope.
4 //! Note that the reference search is possible for not all of the classified items.
6 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
9 Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution,
10 Semantics, TypeParam, Visibility,
17 use test_utils::tested_by;
19 use crate::RootDatabase;
21 // FIXME: a more precise name would probably be `Symbol`?
22 #[derive(Debug, PartialEq, Eq)]
33 pub fn module(&self, db: &RootDatabase) -> Option<Module> {
35 Definition::Macro(it) => it.module(db),
36 Definition::Field(it) => Some(it.parent_def(db).module(db)),
37 Definition::ModuleDef(it) => it.module(db),
38 Definition::SelfType(it) => Some(it.module(db)),
39 Definition::Local(it) => Some(it.module(db)),
40 Definition::TypeParam(it) => Some(it.module(db)),
44 pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> {
45 let module = self.module(db);
48 Definition::Macro(_) => None,
49 Definition::Field(sf) => Some(sf.visibility(db)),
50 Definition::ModuleDef(def) => module?.visibility_of(db, def),
51 Definition::SelfType(_) => None,
52 Definition::Local(_) => None,
53 Definition::TypeParam(_) => None,
57 pub fn name(&self, db: &RootDatabase) -> Option<Name> {
58 let name = match self {
59 Definition::Macro(it) => it.name(db)?,
60 Definition::Field(it) => it.name(db),
61 Definition::ModuleDef(def) => match def {
62 hir::ModuleDef::Module(it) => it.name(db)?,
63 hir::ModuleDef::Function(it) => it.name(db),
64 hir::ModuleDef::Adt(def) => match def {
65 hir::Adt::Struct(it) => it.name(db),
66 hir::Adt::Union(it) => it.name(db),
67 hir::Adt::Enum(it) => it.name(db),
69 hir::ModuleDef::EnumVariant(it) => it.name(db),
70 hir::ModuleDef::Const(it) => it.name(db)?,
71 hir::ModuleDef::Static(it) => it.name(db)?,
72 hir::ModuleDef::Trait(it) => it.name(db),
73 hir::ModuleDef::TypeAlias(it) => it.name(db),
74 hir::ModuleDef::BuiltinType(_) => return None,
76 Definition::SelfType(_) => return None,
77 Definition::Local(it) => it.name(db)?,
78 Definition::TypeParam(it) => it.name(db),
85 Definition(Definition),
86 /// `None` in `if let None = Some(82) {}`
87 ConstReference(Definition),
91 pub fn into_definition(self) -> Option<Definition> {
93 NameClass::Definition(it) => Some(it),
94 NameClass::ConstReference(_) => None,
98 pub fn definition(self) -> Definition {
100 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
105 pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> {
106 let _p = profile("classify_name");
108 if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) {
109 if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) {
110 return Some(NameClass::ConstReference(Definition::ModuleDef(def)));
114 classify_name_inner(sema, name).map(NameClass::Definition)
117 fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> {
118 let parent = name.syntax().parent()?;
123 tested_by!(goto_def_for_use_alias; force);
124 let use_tree = it.syntax().ancestors().find_map(ast::UseTree::cast)?;
125 let path = use_tree.path()?;
126 let path_segment = path.segment()?;
127 let name_ref = path_segment.name_ref()?;
128 let name_ref_class = classify_name_ref(sema, &name_ref)?;
130 Some(name_ref_class.definition())
132 ast::BindPat(it) => {
133 let local = sema.to_def(&it)?;
134 Some(Definition::Local(local))
136 ast::RecordFieldDef(it) => {
137 let field: hir::Field = sema.to_def(&it)?;
138 Some(Definition::Field(field))
141 let def = sema.to_def(&it)?;
142 Some(Definition::ModuleDef(def.into()))
144 ast::StructDef(it) => {
145 let def: hir::Struct = sema.to_def(&it)?;
146 Some(Definition::ModuleDef(def.into()))
148 ast::UnionDef(it) => {
149 let def: hir::Union = sema.to_def(&it)?;
150 Some(Definition::ModuleDef(def.into()))
152 ast::EnumDef(it) => {
153 let def: hir::Enum = sema.to_def(&it)?;
154 Some(Definition::ModuleDef(def.into()))
156 ast::TraitDef(it) => {
157 let def: hir::Trait = sema.to_def(&it)?;
158 Some(Definition::ModuleDef(def.into()))
160 ast::StaticDef(it) => {
161 let def: hir::Static = sema.to_def(&it)?;
162 Some(Definition::ModuleDef(def.into()))
164 ast::EnumVariant(it) => {
165 let def: hir::EnumVariant = sema.to_def(&it)?;
166 Some(Definition::ModuleDef(def.into()))
169 let def: hir::Function = sema.to_def(&it)?;
170 Some(Definition::ModuleDef(def.into()))
172 ast::ConstDef(it) => {
173 let def: hir::Const = sema.to_def(&it)?;
174 Some(Definition::ModuleDef(def.into()))
176 ast::TypeAliasDef(it) => {
177 let def: hir::TypeAlias = sema.to_def(&it)?;
178 Some(Definition::ModuleDef(def.into()))
180 ast::MacroCall(it) => {
181 let def = sema.to_def(&it)?;
182 Some(Definition::Macro(def))
184 ast::TypeParam(it) => {
185 let def = sema.to_def(&it)?;
186 Some(Definition::TypeParam(def))
194 pub enum NameRefClass {
195 Definition(Definition),
196 FieldShorthand { local: Local, field: Definition },
200 pub fn definition(self) -> Definition {
202 NameRefClass::Definition(def) => def,
203 NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
208 pub fn classify_name_ref(
209 sema: &Semantics<RootDatabase>,
210 name_ref: &ast::NameRef,
211 ) -> Option<NameRefClass> {
212 let _p = profile("classify_name_ref");
214 let parent = name_ref.syntax().parent()?;
216 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
217 tested_by!(goto_def_for_methods; force);
218 if let Some(func) = sema.resolve_method_call(&method_call) {
219 return Some(NameRefClass::Definition(Definition::ModuleDef(func.into())));
223 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
224 tested_by!(goto_def_for_fields; force);
225 if let Some(field) = sema.resolve_field(&field_expr) {
226 return Some(NameRefClass::Definition(Definition::Field(field)));
230 if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
231 tested_by!(goto_def_for_record_fields; force);
232 tested_by!(goto_def_for_field_init_shorthand; force);
233 if let Some((field, local)) = sema.resolve_record_field(&record_field) {
234 let field = Definition::Field(field);
235 let res = match local {
236 None => NameRefClass::Definition(field),
237 Some(local) => NameRefClass::FieldShorthand { field, local },
243 if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) {
244 tested_by!(goto_def_for_record_field_pats; force);
245 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
246 let field = Definition::Field(field);
247 return Some(NameRefClass::Definition(field));
251 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
252 tested_by!(goto_def_for_macros; force);
253 if let Some(macro_def) = sema.resolve_macro_call(¯o_call) {
254 return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
258 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
259 let resolved = sema.resolve_path(&path)?;
260 let res = match resolved {
261 PathResolution::Def(def) => Definition::ModuleDef(def),
262 PathResolution::AssocItem(item) => {
263 let def = match item {
264 hir::AssocItem::Function(it) => it.into(),
265 hir::AssocItem::Const(it) => it.into(),
266 hir::AssocItem::TypeAlias(it) => it.into(),
268 Definition::ModuleDef(def)
270 PathResolution::Local(local) => Definition::Local(local),
271 PathResolution::TypeParam(par) => Definition::TypeParam(par),
272 PathResolution::Macro(def) => Definition::Macro(def),
273 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
275 Some(NameRefClass::Definition(res))