]> git.lizzy.rs Git - rust.git/blob - crates/ra_hir_def/src/visibility.rs
Make remaining item data queries use item tree
[rust.git] / crates / ra_hir_def / src / visibility.rs
1 //! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).
2
3 use hir_expand::{hygiene::Hygiene, InFile};
4 use ra_syntax::ast;
5
6 use crate::{
7     db::DefDatabase,
8     path::{ModPath, PathKind},
9     ModuleId,
10 };
11
12 /// Visibility of an item, not yet resolved.
13 #[derive(Debug, Clone, PartialEq, Eq)]
14 pub enum RawVisibility {
15     /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
16     /// equivalent to `pub(self)`.
17     Module(ModPath),
18     /// `pub`.
19     Public,
20 }
21
22 impl RawVisibility {
23     pub(crate) const fn private() -> RawVisibility {
24         let path = ModPath { kind: PathKind::Super(0), segments: Vec::new() };
25         RawVisibility::Module(path)
26     }
27
28     pub(crate) fn from_ast(
29         db: &dyn DefDatabase,
30         node: InFile<Option<ast::Visibility>>,
31     ) -> RawVisibility {
32         Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id))
33     }
34
35     pub(crate) fn from_ast_with_hygiene(
36         node: Option<ast::Visibility>,
37         hygiene: &Hygiene,
38     ) -> RawVisibility {
39         Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene)
40     }
41
42     pub(crate) fn from_ast_with_hygiene_and_default(
43         node: Option<ast::Visibility>,
44         default: RawVisibility,
45         hygiene: &Hygiene,
46     ) -> RawVisibility {
47         let node = match node {
48             None => return default,
49             Some(node) => node,
50         };
51         match node.kind() {
52             ast::VisibilityKind::In(path) => {
53                 let path = ModPath::from_src(path, hygiene);
54                 let path = match path {
55                     None => return RawVisibility::private(),
56                     Some(path) => path,
57                 };
58                 RawVisibility::Module(path)
59             }
60             ast::VisibilityKind::PubCrate => {
61                 let path = ModPath { kind: PathKind::Crate, segments: Vec::new() };
62                 RawVisibility::Module(path)
63             }
64             ast::VisibilityKind::PubSuper => {
65                 let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() };
66                 RawVisibility::Module(path)
67             }
68             ast::VisibilityKind::PubSelf => {
69                 let path = ModPath { kind: PathKind::Plain, segments: Vec::new() };
70                 RawVisibility::Module(path)
71             }
72             ast::VisibilityKind::Pub => RawVisibility::Public,
73         }
74     }
75
76     pub fn resolve(
77         &self,
78         db: &dyn DefDatabase,
79         resolver: &crate::resolver::Resolver,
80     ) -> Visibility {
81         // we fall back to public visibility (i.e. fail open) if the path can't be resolved
82         resolver.resolve_visibility(db, self).unwrap_or(Visibility::Public)
83     }
84 }
85
86 /// Visibility of an item, with the path resolved.
87 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
88 pub enum Visibility {
89     /// Visibility is restricted to a certain module.
90     Module(ModuleId),
91     /// Visibility is unrestricted.
92     Public,
93 }
94
95 impl Visibility {
96     pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
97         let to_module = match self {
98             Visibility::Module(m) => m,
99             Visibility::Public => return true,
100         };
101         // if they're not in the same crate, it can't be visible
102         if from_module.krate != to_module.krate {
103             return false;
104         }
105         let def_map = db.crate_def_map(from_module.krate);
106         self.is_visible_from_def_map(&def_map, from_module.local_id)
107     }
108
109     pub(crate) fn is_visible_from_other_crate(self) -> bool {
110         match self {
111             Visibility::Module(_) => false,
112             Visibility::Public => true,
113         }
114     }
115
116     pub(crate) fn is_visible_from_def_map(
117         self,
118         def_map: &crate::nameres::CrateDefMap,
119         from_module: crate::LocalModuleId,
120     ) -> bool {
121         let to_module = match self {
122             Visibility::Module(m) => m,
123             Visibility::Public => return true,
124         };
125         // from_module needs to be a descendant of to_module
126         let mut ancestors = std::iter::successors(Some(from_module), |m| {
127             let parent_id = def_map[*m].parent?;
128             Some(parent_id)
129         });
130         ancestors.any(|m| m == to_module.local_id)
131     }
132 }