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 /crates/ra_hir_def/src/visibility.rs | |
parent | 97f01396eda7eb3e6ec5056f3f72d98e5739f829 (diff) |
Add infrastructure for visibility on syntax and hir_def level
Diffstat (limited to 'crates/ra_hir_def/src/visibility.rs')
-rw-r--r-- | crates/ra_hir_def/src/visibility.rs | 101 |
1 files changed, 101 insertions, 0 deletions
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 | } | ||