diff options
author | Florian Diebold <[email protected]> | 2019-12-24 19:32:42 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-26 15:23:40 +0000 |
commit | 069bf55cca1e1be1f6cdd28b638f691e059858dc (patch) | |
tree | b929d8e84c26e00827a2f507a528ef31e651ecc8 | |
parent | 97f01396eda7eb3e6ec5056f3f72d98e5739f829 (diff) |
Add infrastructure for visibility on syntax and hir_def level
-rw-r--r-- | crates/ra_hir_def/src/db.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir_def/src/visibility.rs | 101 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 29 |
5 files changed, 163 insertions, 2 deletions
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index c55fd4111..1761e2187 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -14,9 +14,10 @@ use crate::{ | |||
14 | generics::GenericParams, | 14 | generics::GenericParams, |
15 | lang_item::{LangItemTarget, LangItems}, | 15 | lang_item::{LangItemTarget, LangItems}, |
16 | nameres::{raw::RawItems, CrateDefMap}, | 16 | nameres::{raw::RawItems, CrateDefMap}, |
17 | visibility::Visibility, | ||
17 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 18 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
18 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | 19 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
19 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | 20 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VisibilityDefId, |
20 | }; | 21 | }; |
21 | 22 | ||
22 | #[salsa::query_group(InternDatabaseStorage)] | 23 | #[salsa::query_group(InternDatabaseStorage)] |
@@ -90,6 +91,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase { | |||
90 | #[salsa::invoke(Attrs::attrs_query)] | 91 | #[salsa::invoke(Attrs::attrs_query)] |
91 | fn attrs(&self, def: AttrDefId) -> Attrs; | 92 | fn attrs(&self, def: AttrDefId) -> Attrs; |
92 | 93 | ||
94 | #[salsa::invoke(Visibility::visibility_query)] | ||
95 | fn visibility(&self, def: VisibilityDefId) -> Visibility; | ||
96 | |||
93 | #[salsa::invoke(LangItems::module_lang_items_query)] | 97 | #[salsa::invoke(LangItems::module_lang_items_query)] |
94 | fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>; | 98 | fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>; |
95 | 99 | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index f6c7f38d1..72a59d867 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -36,6 +36,8 @@ pub mod nameres; | |||
36 | pub mod src; | 36 | pub mod src; |
37 | pub mod child_by_source; | 37 | pub mod child_by_source; |
38 | 38 | ||
39 | pub mod visibility; | ||
40 | |||
39 | #[cfg(test)] | 41 | #[cfg(test)] |
40 | mod test_db; | 42 | mod test_db; |
41 | #[cfg(test)] | 43 | #[cfg(test)] |
@@ -323,6 +325,29 @@ impl_froms!( | |||
323 | ImplId | 325 | ImplId |
324 | ); | 326 | ); |
325 | 327 | ||
328 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
329 | pub enum VisibilityDefId { | ||
330 | ModuleId(ModuleId), | ||
331 | StructFieldId(StructFieldId), | ||
332 | AdtId(AdtId), | ||
333 | FunctionId(FunctionId), | ||
334 | StaticId(StaticId), | ||
335 | ConstId(ConstId), | ||
336 | TraitId(TraitId), | ||
337 | TypeAliasId(TypeAliasId), | ||
338 | } | ||
339 | |||
340 | impl_froms!( | ||
341 | VisibilityDefId: ModuleId, | ||
342 | StructFieldId, | ||
343 | AdtId(StructId, EnumId, UnionId), | ||
344 | StaticId, | ||
345 | ConstId, | ||
346 | FunctionId, | ||
347 | TraitId, | ||
348 | TypeAliasId | ||
349 | ); | ||
350 | |||
326 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 351 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
327 | pub enum VariantId { | 352 | pub enum VariantId { |
328 | EnumVariantId(EnumVariantId), | 353 | EnumVariantId(EnumVariantId), |
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs new file mode 100644 index 000000000..7d881911d --- /dev/null +++ b/crates/ra_hir_def/src/visibility.rs | |||
@@ -0,0 +1,101 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use either::Either; | ||
4 | |||
5 | use hir_expand::InFile; | ||
6 | use ra_syntax::ast::{self, VisibilityOwner}; | ||
7 | |||
8 | use crate::{ | ||
9 | db::DefDatabase, | ||
10 | path::{ModPath, PathKind}, | ||
11 | src::{HasChildSource, HasSource}, | ||
12 | AdtId, Lookup, VisibilityDefId, | ||
13 | }; | ||
14 | |||
15 | /// Visibility of an item, not yet resolved. | ||
16 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
17 | pub enum Visibility { | ||
18 | // FIXME: We could avoid the allocation in many cases by special-casing | ||
19 | // pub(crate), pub(super) and private. Alternatively, `ModPath` could be | ||
20 | // made to contain an Arc<[Segment]> instead of a Vec? | ||
21 | /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is | ||
22 | /// equivalent to `pub(self)`. | ||
23 | Module(Arc<ModPath>), | ||
24 | /// `pub`. | ||
25 | Public, | ||
26 | } | ||
27 | |||
28 | impl Visibility { | ||
29 | pub(crate) fn visibility_query(db: &impl DefDatabase, def: VisibilityDefId) -> Visibility { | ||
30 | match def { | ||
31 | VisibilityDefId::ModuleId(module) => { | ||
32 | let def_map = db.crate_def_map(module.krate); | ||
33 | let src = match def_map[module.local_id].declaration_source(db) { | ||
34 | Some(it) => it, | ||
35 | None => return Visibility::private(), | ||
36 | }; | ||
37 | Visibility::from_ast(db, src.map(|it| it.visibility())) | ||
38 | } | ||
39 | VisibilityDefId::StructFieldId(it) => { | ||
40 | let src = it.parent.child_source(db); | ||
41 | // TODO: enum variant fields should be public by default | ||
42 | let vis_node = src.map(|m| match &m[it.local_id] { | ||
43 | Either::Left(tuple) => tuple.visibility(), | ||
44 | Either::Right(record) => record.visibility(), | ||
45 | }); | ||
46 | Visibility::from_ast(db, vis_node) | ||
47 | } | ||
48 | VisibilityDefId::AdtId(it) => match it { | ||
49 | AdtId::StructId(it) => visibility_from_loc(it.lookup(db), db), | ||
50 | AdtId::EnumId(it) => visibility_from_loc(it.lookup(db), db), | ||
51 | AdtId::UnionId(it) => visibility_from_loc(it.lookup(db), db), | ||
52 | }, | ||
53 | VisibilityDefId::TraitId(it) => visibility_from_loc(it.lookup(db), db), | ||
54 | VisibilityDefId::ConstId(it) => visibility_from_loc(it.lookup(db), db), | ||
55 | VisibilityDefId::StaticId(it) => visibility_from_loc(it.lookup(db), db), | ||
56 | VisibilityDefId::FunctionId(it) => visibility_from_loc(it.lookup(db), db), | ||
57 | VisibilityDefId::TypeAliasId(it) => visibility_from_loc(it.lookup(db), db), | ||
58 | } | ||
59 | } | ||
60 | |||
61 | fn private() -> Visibility { | ||
62 | let path = ModPath { kind: PathKind::Super(0), segments: Vec::new() }; | ||
63 | Visibility::Module(Arc::new(path)) | ||
64 | } | ||
65 | |||
66 | fn from_ast(db: &impl DefDatabase, node: InFile<Option<ast::Visibility>>) -> Visibility { | ||
67 | let file_id = node.file_id; | ||
68 | let node = match node.value { | ||
69 | None => return Visibility::private(), | ||
70 | Some(node) => node, | ||
71 | }; | ||
72 | match node.kind() { | ||
73 | ast::VisibilityKind::In(path) => { | ||
74 | let path = ModPath::from_src(path, &hir_expand::hygiene::Hygiene::new(db, file_id)); | ||
75 | let path = match path { | ||
76 | None => return Visibility::private(), | ||
77 | Some(path) => path, | ||
78 | }; | ||
79 | Visibility::Module(Arc::new(path)) | ||
80 | } | ||
81 | ast::VisibilityKind::PubCrate => { | ||
82 | let path = ModPath { kind: PathKind::Crate, segments: Vec::new() }; | ||
83 | Visibility::Module(Arc::new(path)) | ||
84 | } | ||
85 | ast::VisibilityKind::PubSuper => { | ||
86 | let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() }; | ||
87 | Visibility::Module(Arc::new(path)) | ||
88 | } | ||
89 | ast::VisibilityKind::Pub => Visibility::Public, | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | fn visibility_from_loc<T>(node: T, db: &impl DefDatabase) -> Visibility | ||
95 | where | ||
96 | T: HasSource, | ||
97 | T::Value: ast::VisibilityOwner, | ||
98 | { | ||
99 | let src = node.source(db); | ||
100 | Visibility::from_ast(db, src.map(|n| n.visibility())) | ||
101 | } | ||
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 277532a8c..89cb9a9f3 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -17,7 +17,9 @@ use crate::{ | |||
17 | 17 | ||
18 | pub use self::{ | 18 | pub use self::{ |
19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, | 19 | expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, |
20 | extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind}, | 20 | extensions::{ |
21 | FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind, VisibilityKind, | ||
22 | }, | ||
21 | generated::*, | 23 | generated::*, |
22 | tokens::*, | 24 | tokens::*, |
23 | traits::*, | 25 | traits::*, |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index baaef3023..d9666cdca 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -413,3 +413,32 @@ impl ast::TraitDef { | |||
413 | self.syntax().children_with_tokens().any(|t| t.kind() == T![auto]) | 413 | self.syntax().children_with_tokens().any(|t| t.kind() == T![auto]) |
414 | } | 414 | } |
415 | } | 415 | } |
416 | |||
417 | pub enum VisibilityKind { | ||
418 | In(ast::Path), | ||
419 | PubCrate, | ||
420 | PubSuper, | ||
421 | Pub, | ||
422 | } | ||
423 | |||
424 | impl ast::Visibility { | ||
425 | pub fn kind(&self) -> VisibilityKind { | ||
426 | if let Some(path) = children(self).next() { | ||
427 | VisibilityKind::In(path) | ||
428 | } else if self.is_pub_crate() { | ||
429 | VisibilityKind::PubCrate | ||
430 | } else if self.is_pub_super() { | ||
431 | VisibilityKind::PubSuper | ||
432 | } else { | ||
433 | VisibilityKind::Pub | ||
434 | } | ||
435 | } | ||
436 | |||
437 | fn is_pub_crate(&self) -> bool { | ||
438 | self.syntax().children_with_tokens().any(|it| it.kind() == T![crate]) | ||
439 | } | ||
440 | |||
441 | fn is_pub_super(&self) -> bool { | ||
442 | self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) | ||
443 | } | ||
444 | } | ||