diff options
Diffstat (limited to 'crates/ra_ide_db/src/defs.rs')
-rw-r--r-- | crates/ra_ide_db/src/defs.rs | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs new file mode 100644 index 000000000..030f44f86 --- /dev/null +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -0,0 +1,172 @@ | |||
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. | ||
5 | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | ||
7 | |||
8 | use hir::{ | ||
9 | Adt, HasSource, ImplBlock, InFile, Local, MacroDef, Module, ModuleDef, SourceBinder, | ||
10 | StructField, TypeParam, VariantDef, | ||
11 | }; | ||
12 | use ra_prof::profile; | ||
13 | use ra_syntax::{ | ||
14 | ast::{self, AstNode, VisibilityOwner}, | ||
15 | match_ast, | ||
16 | }; | ||
17 | |||
18 | use crate::RootDatabase; | ||
19 | |||
20 | #[derive(Debug, PartialEq, Eq)] | ||
21 | pub enum NameKind { | ||
22 | Macro(MacroDef), | ||
23 | StructField(StructField), | ||
24 | ModuleDef(ModuleDef), | ||
25 | SelfType(ImplBlock), | ||
26 | Local(Local), | ||
27 | TypeParam(TypeParam), | ||
28 | } | ||
29 | |||
30 | #[derive(PartialEq, Eq)] | ||
31 | pub struct NameDefinition { | ||
32 | pub visibility: Option<ast::Visibility>, | ||
33 | /// FIXME: this doesn't really make sense. For example, builtin types don't | ||
34 | /// really have a module. | ||
35 | pub container: Module, | ||
36 | pub kind: NameKind, | ||
37 | } | ||
38 | |||
39 | pub fn classify_name( | ||
40 | sb: &mut SourceBinder<RootDatabase>, | ||
41 | name: InFile<&ast::Name>, | ||
42 | ) -> Option<NameDefinition> { | ||
43 | let _p = profile("classify_name"); | ||
44 | let parent = name.value.syntax().parent()?; | ||
45 | |||
46 | match_ast! { | ||
47 | match parent { | ||
48 | ast::BindPat(it) => { | ||
49 | let src = name.with_value(it); | ||
50 | let local = sb.to_def(src)?; | ||
51 | Some(NameDefinition { | ||
52 | visibility: None, | ||
53 | container: local.module(sb.db), | ||
54 | kind: NameKind::Local(local), | ||
55 | }) | ||
56 | }, | ||
57 | ast::RecordFieldDef(it) => { | ||
58 | let src = name.with_value(it); | ||
59 | let field: hir::StructField = sb.to_def(src)?; | ||
60 | Some(from_struct_field(sb.db, field)) | ||
61 | }, | ||
62 | ast::Module(it) => { | ||
63 | let def = sb.to_def(name.with_value(it))?; | ||
64 | Some(from_module_def(sb.db, def.into(), None)) | ||
65 | }, | ||
66 | ast::StructDef(it) => { | ||
67 | let src = name.with_value(it); | ||
68 | let def: hir::Struct = sb.to_def(src)?; | ||
69 | Some(from_module_def(sb.db, def.into(), None)) | ||
70 | }, | ||
71 | ast::EnumDef(it) => { | ||
72 | let src = name.with_value(it); | ||
73 | let def: hir::Enum = sb.to_def(src)?; | ||
74 | Some(from_module_def(sb.db, def.into(), None)) | ||
75 | }, | ||
76 | ast::TraitDef(it) => { | ||
77 | let src = name.with_value(it); | ||
78 | let def: hir::Trait = sb.to_def(src)?; | ||
79 | Some(from_module_def(sb.db, def.into(), None)) | ||
80 | }, | ||
81 | ast::StaticDef(it) => { | ||
82 | let src = name.with_value(it); | ||
83 | let def: hir::Static = sb.to_def(src)?; | ||
84 | Some(from_module_def(sb.db, def.into(), None)) | ||
85 | }, | ||
86 | ast::EnumVariant(it) => { | ||
87 | let src = name.with_value(it); | ||
88 | let def: hir::EnumVariant = sb.to_def(src)?; | ||
89 | Some(from_module_def(sb.db, def.into(), None)) | ||
90 | }, | ||
91 | ast::FnDef(it) => { | ||
92 | let src = name.with_value(it); | ||
93 | let def: hir::Function = sb.to_def(src)?; | ||
94 | Some(from_module_def(sb.db, def.into(), None)) | ||
95 | }, | ||
96 | ast::ConstDef(it) => { | ||
97 | let src = name.with_value(it); | ||
98 | let def: hir::Const = sb.to_def(src)?; | ||
99 | Some(from_module_def(sb.db, def.into(), None)) | ||
100 | }, | ||
101 | ast::TypeAliasDef(it) => { | ||
102 | let src = name.with_value(it); | ||
103 | let def: hir::TypeAlias = sb.to_def(src)?; | ||
104 | Some(from_module_def(sb.db, def.into(), None)) | ||
105 | }, | ||
106 | ast::MacroCall(it) => { | ||
107 | let src = name.with_value(it); | ||
108 | let def = sb.to_def(src.clone())?; | ||
109 | |||
110 | let module = sb.to_module_def(src.file_id.original_file(sb.db))?; | ||
111 | |||
112 | Some(NameDefinition { | ||
113 | visibility: None, | ||
114 | container: module, | ||
115 | kind: NameKind::Macro(def), | ||
116 | }) | ||
117 | }, | ||
118 | ast::TypeParam(it) => { | ||
119 | let src = name.with_value(it); | ||
120 | let def = sb.to_def(src)?; | ||
121 | Some(NameDefinition { | ||
122 | visibility: None, | ||
123 | container: def.module(sb.db), | ||
124 | kind: NameKind::TypeParam(def), | ||
125 | }) | ||
126 | }, | ||
127 | _ => None, | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | pub fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition { | ||
133 | let kind = NameKind::StructField(field); | ||
134 | let parent = field.parent_def(db); | ||
135 | let container = parent.module(db); | ||
136 | let visibility = match parent { | ||
137 | VariantDef::Struct(s) => s.source(db).value.visibility(), | ||
138 | VariantDef::Union(e) => e.source(db).value.visibility(), | ||
139 | VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(), | ||
140 | }; | ||
141 | NameDefinition { kind, container, visibility } | ||
142 | } | ||
143 | |||
144 | pub fn from_module_def( | ||
145 | db: &RootDatabase, | ||
146 | def: ModuleDef, | ||
147 | module: Option<Module>, | ||
148 | ) -> NameDefinition { | ||
149 | let kind = NameKind::ModuleDef(def); | ||
150 | let (container, visibility) = match def { | ||
151 | ModuleDef::Module(it) => { | ||
152 | let container = it.parent(db).or_else(|| Some(it)).unwrap(); | ||
153 | let visibility = it.declaration_source(db).and_then(|s| s.value.visibility()); | ||
154 | (container, visibility) | ||
155 | } | ||
156 | ModuleDef::EnumVariant(it) => { | ||
157 | let container = it.module(db); | ||
158 | let visibility = it.source(db).value.parent_enum().visibility(); | ||
159 | (container, visibility) | ||
160 | } | ||
161 | ModuleDef::Function(it) => (it.module(db), it.source(db).value.visibility()), | ||
162 | ModuleDef::Const(it) => (it.module(db), it.source(db).value.visibility()), | ||
163 | ModuleDef::Static(it) => (it.module(db), it.source(db).value.visibility()), | ||
164 | ModuleDef::Trait(it) => (it.module(db), it.source(db).value.visibility()), | ||
165 | ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).value.visibility()), | ||
166 | ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).value.visibility()), | ||
167 | ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).value.visibility()), | ||
168 | ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).value.visibility()), | ||
169 | ModuleDef::BuiltinType(..) => (module.unwrap(), None), | ||
170 | }; | ||
171 | NameDefinition { kind, container, visibility } | ||
172 | } | ||