aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-29 12:24:19 +0000
committerGitHub <[email protected]>2019-12-29 12:24:19 +0000
commitcdcb3d3833d3d5b37b2cd4dac91a6e9366f20aea (patch)
treec9750e1ef8079a691caed3dc941392c99fda1524 /crates
parentc5a48bea1218afb63d7932a6816f34c810bbab6b (diff)
parent9fd2c813ca355c3a1f10f54993c16e81778b867b (diff)
Merge #2667
2667: Visibility r=matklad a=flodiebold This adds the infrastructure for handling visibility (for fields and methods, not in name resolution) in the HIR and code model, and as a first application hides struct fields from completions if they're not visible from the current module. (We might want to relax this again later, but I think it's ok for now?) Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/code_model.rs19
-rw-r--r--crates/ra_hir/src/lib.rs4
-rw-r--r--crates/ra_hir_def/src/adt.rs44
-rw-r--r--crates/ra_hir_def/src/body/lower.rs5
-rw-r--r--crates/ra_hir_def/src/item_scope.rs33
-rw-r--r--crates/ra_hir_def/src/lib.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs109
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs72
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs35
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs6
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs97
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs4
-rw-r--r--crates/ra_hir_def/src/per_ns.rs50
-rw-r--r--crates/ra_hir_def/src/resolver.rs22
-rw-r--r--crates/ra_hir_def/src/visibility.rs120
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs57
-rw-r--r--crates/ra_syntax/src/ast.rs4
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs29
-rw-r--r--crates/ra_syntax/src/ast/generated.rs3
-rw-r--r--crates/ra_syntax/src/grammar.ron6
20 files changed, 608 insertions, 113 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 76d8f85f1..488f74cfb 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -118,7 +118,7 @@ impl_froms!(
118 BuiltinType 118 BuiltinType
119); 119);
120 120
121pub use hir_def::attr::Attrs; 121pub use hir_def::{attr::Attrs, visibility::Visibility};
122 122
123impl Module { 123impl Module {
124 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { 124 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
@@ -255,6 +255,15 @@ impl StructField {
255 } 255 }
256} 256}
257 257
258impl HasVisibility for StructField {
259 fn visibility(&self, db: &impl HirDatabase) -> Visibility {
260 let variant_data = self.parent.variant_data(db);
261 let visibility = &variant_data.fields()[self.id].visibility;
262 let parent_id: hir_def::VariantId = self.parent.into();
263 visibility.resolve(db, &parent_id.resolver(db))
264 }
265}
266
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct Struct { 268pub struct Struct {
260 pub(crate) id: StructId, 269 pub(crate) id: StructId,
@@ -1041,3 +1050,11 @@ impl<T: Into<AttrDef> + Copy> Docs for T {
1041 db.documentation(def.into()) 1050 db.documentation(def.into())
1042 } 1051 }
1043} 1052}
1053
1054pub trait HasVisibility {
1055 fn visibility(&self, db: &impl HirDatabase) -> Visibility;
1056 fn is_visible_from(&self, db: &impl HirDatabase, module: Module) -> bool {
1057 let vis = self.visibility(db);
1058 vis.is_visible_from(db, module.id)
1059 }
1060}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 0008a8858..3d13978d4 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -40,8 +40,8 @@ mod from_source;
40pub use crate::{ 40pub use crate::{
41 code_model::{ 41 code_model::{
42 Adt, AssocItem, AttrDef, Const, Crate, CrateDependency, DefWithBody, Docs, Enum, 42 Adt, AssocItem, AttrDef, Const, Crate, CrateDependency, DefWithBody, Docs, Enum,
43 EnumVariant, FieldSource, Function, GenericDef, HasAttrs, ImplBlock, Local, MacroDef, 43 EnumVariant, FieldSource, Function, GenericDef, HasAttrs, HasVisibility, ImplBlock, Local,
44 Module, ModuleDef, ScopeDef, Static, Struct, StructField, Trait, Type, TypeAlias, 44 MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, StructField, Trait, Type, TypeAlias,
45 TypeParam, Union, VariantDef, 45 TypeParam, Union, VariantDef,
46 }, 46 },
47 from_source::FromSource, 47 from_source::FromSource,
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index d9ea693e3..aac5f3e15 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -9,11 +9,12 @@ use hir_expand::{
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_prof::profile; 11use ra_prof::profile;
12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
13 13
14use crate::{ 14use crate::{
15 db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, EnumId, 15 db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef,
16 LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, VariantId, 16 visibility::RawVisibility, EnumId, LocalEnumVariantId, LocalStructFieldId, Lookup, StructId,
17 UnionId, VariantId,
17}; 18};
18 19
19/// Note that we use `StructData` for unions as well! 20/// Note that we use `StructData` for unions as well!
@@ -47,13 +48,14 @@ pub enum VariantData {
47pub struct StructFieldData { 48pub struct StructFieldData {
48 pub name: Name, 49 pub name: Name,
49 pub type_ref: TypeRef, 50 pub type_ref: TypeRef,
51 pub visibility: RawVisibility,
50} 52}
51 53
52impl StructData { 54impl StructData {
53 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> { 55 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> {
54 let src = id.lookup(db).source(db); 56 let src = id.lookup(db).source(db);
55 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 57 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
56 let variant_data = VariantData::new(src.value.kind()); 58 let variant_data = VariantData::new(db, src.map(|s| s.kind()));
57 let variant_data = Arc::new(variant_data); 59 let variant_data = Arc::new(variant_data);
58 Arc::new(StructData { name, variant_data }) 60 Arc::new(StructData { name, variant_data })
59 } 61 }
@@ -61,10 +63,12 @@ impl StructData {
61 let src = id.lookup(db).source(db); 63 let src = id.lookup(db).source(db);
62 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 64 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
63 let variant_data = VariantData::new( 65 let variant_data = VariantData::new(
64 src.value 66 db,
65 .record_field_def_list() 67 src.map(|s| {
66 .map(ast::StructKind::Record) 68 s.record_field_def_list()
67 .unwrap_or(ast::StructKind::Unit), 69 .map(ast::StructKind::Record)
70 .unwrap_or(ast::StructKind::Unit)
71 }),
68 ); 72 );
69 let variant_data = Arc::new(variant_data); 73 let variant_data = Arc::new(variant_data);
70 Arc::new(StructData { name, variant_data }) 74 Arc::new(StructData { name, variant_data })
@@ -77,7 +81,7 @@ impl EnumData {
77 let src = e.lookup(db).source(db); 81 let src = e.lookup(db).source(db);
78 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 82 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
79 let mut trace = Trace::new_for_arena(); 83 let mut trace = Trace::new_for_arena();
80 lower_enum(&mut trace, &src.value); 84 lower_enum(db, &mut trace, &src);
81 Arc::new(EnumData { name, variants: trace.into_arena() }) 85 Arc::new(EnumData { name, variants: trace.into_arena() })
82 } 86 }
83 87
@@ -93,30 +97,31 @@ impl HasChildSource for EnumId {
93 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 97 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
94 let src = self.lookup(db).source(db); 98 let src = self.lookup(db).source(db);
95 let mut trace = Trace::new_for_map(); 99 let mut trace = Trace::new_for_map();
96 lower_enum(&mut trace, &src.value); 100 lower_enum(db, &mut trace, &src);
97 src.with_value(trace.into_map()) 101 src.with_value(trace.into_map())
98 } 102 }
99} 103}
100 104
101fn lower_enum( 105fn lower_enum(
106 db: &impl DefDatabase,
102 trace: &mut Trace<LocalEnumVariantId, EnumVariantData, ast::EnumVariant>, 107 trace: &mut Trace<LocalEnumVariantId, EnumVariantData, ast::EnumVariant>,
103 ast: &ast::EnumDef, 108 ast: &InFile<ast::EnumDef>,
104) { 109) {
105 for var in ast.variant_list().into_iter().flat_map(|it| it.variants()) { 110 for var in ast.value.variant_list().into_iter().flat_map(|it| it.variants()) {
106 trace.alloc( 111 trace.alloc(
107 || var.clone(), 112 || var.clone(),
108 || EnumVariantData { 113 || EnumVariantData {
109 name: var.name().map_or_else(Name::missing, |it| it.as_name()), 114 name: var.name().map_or_else(Name::missing, |it| it.as_name()),
110 variant_data: Arc::new(VariantData::new(var.kind())), 115 variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()))),
111 }, 116 },
112 ); 117 );
113 } 118 }
114} 119}
115 120
116impl VariantData { 121impl VariantData {
117 fn new(flavor: ast::StructKind) -> Self { 122 fn new(db: &impl DefDatabase, flavor: InFile<ast::StructKind>) -> Self {
118 let mut trace = Trace::new_for_arena(); 123 let mut trace = Trace::new_for_arena();
119 match lower_struct(&mut trace, &flavor) { 124 match lower_struct(db, &mut trace, &flavor) {
120 StructKind::Tuple => VariantData::Tuple(trace.into_arena()), 125 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
121 StructKind::Record => VariantData::Record(trace.into_arena()), 126 StructKind::Record => VariantData::Record(trace.into_arena()),
122 StructKind::Unit => VariantData::Unit, 127 StructKind::Unit => VariantData::Unit,
@@ -163,7 +168,7 @@ impl HasChildSource for VariantId {
163 }), 168 }),
164 }; 169 };
165 let mut trace = Trace::new_for_map(); 170 let mut trace = Trace::new_for_map();
166 lower_struct(&mut trace, &src.value); 171 lower_struct(db, &mut trace, &src);
167 src.with_value(trace.into_map()) 172 src.with_value(trace.into_map())
168 } 173 }
169} 174}
@@ -175,14 +180,15 @@ enum StructKind {
175} 180}
176 181
177fn lower_struct( 182fn lower_struct(
183 db: &impl DefDatabase,
178 trace: &mut Trace< 184 trace: &mut Trace<
179 LocalStructFieldId, 185 LocalStructFieldId,
180 StructFieldData, 186 StructFieldData,
181 Either<ast::TupleFieldDef, ast::RecordFieldDef>, 187 Either<ast::TupleFieldDef, ast::RecordFieldDef>,
182 >, 188 >,
183 ast: &ast::StructKind, 189 ast: &InFile<ast::StructKind>,
184) -> StructKind { 190) -> StructKind {
185 match ast { 191 match &ast.value {
186 ast::StructKind::Tuple(fl) => { 192 ast::StructKind::Tuple(fl) => {
187 for (i, fd) in fl.fields().enumerate() { 193 for (i, fd) in fl.fields().enumerate() {
188 trace.alloc( 194 trace.alloc(
@@ -190,6 +196,7 @@ fn lower_struct(
190 || StructFieldData { 196 || StructFieldData {
191 name: Name::new_tuple_field(i), 197 name: Name::new_tuple_field(i),
192 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 198 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
199 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
193 }, 200 },
194 ); 201 );
195 } 202 }
@@ -202,6 +209,7 @@ fn lower_struct(
202 || StructFieldData { 209 || StructFieldData {
203 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 210 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
204 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), 211 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
212 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
205 }, 213 },
206 ); 214 );
207 } 215 }
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 5323af097..fc3a028e0 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -543,7 +543,10 @@ where
543 }; 543 };
544 self.body.item_scope.define_def(def); 544 self.body.item_scope.define_def(def);
545 if let Some(name) = name { 545 if let Some(name) = name {
546 self.body.item_scope.push_res(name.as_name(), def.into()); 546 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
547 self.body
548 .item_scope
549 .push_res(name.as_name(), crate::per_ns::PerNs::from_def(def, vis));
547 } 550 }
548 } 551 }
549 } 552 }
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index b0288ee8d..fe7bb9779 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -5,7 +5,10 @@ use hir_expand::name::Name;
5use once_cell::sync::Lazy; 5use once_cell::sync::Lazy;
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7 7
8use crate::{per_ns::PerNs, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, TraitId}; 8use crate::{
9 per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId,
10 TraitId,
11};
9 12
10#[derive(Debug, Default, PartialEq, Eq)] 13#[derive(Debug, Default, PartialEq, Eq)]
11pub struct ItemScope { 14pub struct ItemScope {
@@ -30,7 +33,7 @@ pub struct ItemScope {
30static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { 33static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
31 BuiltinType::ALL 34 BuiltinType::ALL
32 .iter() 35 .iter()
33 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into()))) 36 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
34 .collect() 37 .collect()
35}); 38});
36 39
@@ -144,8 +147,8 @@ impl ItemScope {
144 changed 147 changed
145 } 148 }
146 149
147 pub(crate) fn collect_resolutions(&self) -> Vec<(Name, PerNs)> { 150 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
148 self.visible.iter().map(|(name, res)| (name.clone(), res.clone())).collect() 151 self.visible.iter().map(|(name, res)| (name.clone(), res.clone()))
149 } 152 }
150 153
151 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 154 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
@@ -153,20 +156,20 @@ impl ItemScope {
153 } 156 }
154} 157}
155 158
156impl From<ModuleDefId> for PerNs { 159impl PerNs {
157 fn from(def: ModuleDefId) -> PerNs { 160 pub(crate) fn from_def(def: ModuleDefId, v: Visibility) -> PerNs {
158 match def { 161 match def {
159 ModuleDefId::ModuleId(_) => PerNs::types(def), 162 ModuleDefId::ModuleId(_) => PerNs::types(def, v),
160 ModuleDefId::FunctionId(_) => PerNs::values(def), 163 ModuleDefId::FunctionId(_) => PerNs::values(def, v),
161 ModuleDefId::AdtId(adt) => match adt { 164 ModuleDefId::AdtId(adt) => match adt {
162 AdtId::StructId(_) | AdtId::UnionId(_) => PerNs::both(def, def), 165 AdtId::StructId(_) | AdtId::UnionId(_) => PerNs::both(def, def, v),
163 AdtId::EnumId(_) => PerNs::types(def), 166 AdtId::EnumId(_) => PerNs::types(def, v),
164 }, 167 },
165 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def), 168 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
166 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def), 169 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
167 ModuleDefId::TraitId(_) => PerNs::types(def), 170 ModuleDefId::TraitId(_) => PerNs::types(def, v),
168 ModuleDefId::TypeAliasId(_) => PerNs::types(def), 171 ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
169 ModuleDefId::BuiltinType(_) => PerNs::types(def), 172 ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
170 } 173 }
171 } 174 }
172} 175}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index f6c7f38d1..61f044ecf 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -36,6 +36,8 @@ pub mod nameres;
36pub mod src; 36pub mod src;
37pub mod child_by_source; 37pub mod child_by_source;
38 38
39pub mod visibility;
40
39#[cfg(test)] 41#[cfg(test)]
40mod test_db; 42mod test_db;
41#[cfg(test)] 43#[cfg(test)]
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index b9f40d3dd..8a22b0585 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -24,6 +24,7 @@ use crate::{
24 }, 24 },
25 path::{ModPath, PathKind}, 25 path::{ModPath, PathKind},
26 per_ns::PerNs, 26 per_ns::PerNs,
27 visibility::Visibility,
27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, 28 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
28 LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, 29 LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
29}; 30};
@@ -108,7 +109,7 @@ struct MacroDirective {
108struct DefCollector<'a, DB> { 109struct DefCollector<'a, DB> {
109 db: &'a DB, 110 db: &'a DB,
110 def_map: CrateDefMap, 111 def_map: CrateDefMap,
111 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>, 112 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
112 unresolved_imports: Vec<ImportDirective>, 113 unresolved_imports: Vec<ImportDirective>,
113 resolved_imports: Vec<ImportDirective>, 114 resolved_imports: Vec<ImportDirective>,
114 unexpanded_macros: Vec<MacroDirective>, 115 unexpanded_macros: Vec<MacroDirective>,
@@ -214,7 +215,11 @@ where
214 // In Rust, `#[macro_export]` macros are unconditionally visible at the 215 // In Rust, `#[macro_export]` macros are unconditionally visible at the
215 // crate root, even if the parent modules is **not** visible. 216 // crate root, even if the parent modules is **not** visible.
216 if export { 217 if export {
217 self.update(self.def_map.root, &[(name, PerNs::macros(macro_))]); 218 self.update(
219 self.def_map.root,
220 &[(name, PerNs::macros(macro_, Visibility::Public))],
221 Visibility::Public,
222 );
218 } 223 }
219 } 224 }
220 225
@@ -348,9 +353,12 @@ where
348 353
349 fn record_resolved_import(&mut self, directive: &ImportDirective) { 354 fn record_resolved_import(&mut self, directive: &ImportDirective) {
350 let module_id = directive.module_id; 355 let module_id = directive.module_id;
351 let import_id = directive.import_id;
352 let import = &directive.import; 356 let import = &directive.import;
353 let def = directive.status.namespaces(); 357 let def = directive.status.namespaces();
358 let vis = self
359 .def_map
360 .resolve_visibility(self.db, module_id, &directive.import.visibility)
361 .unwrap_or(Visibility::Public);
354 362
355 if import.is_glob { 363 if import.is_glob {
356 log::debug!("glob import: {:?}", import); 364 log::debug!("glob import: {:?}", import);
@@ -366,9 +374,16 @@ where
366 let scope = &item_map[m.local_id].scope; 374 let scope = &item_map[m.local_id].scope;
367 375
368 // Module scoped macros is included 376 // Module scoped macros is included
369 let items = scope.collect_resolutions(); 377 let items = scope
370 378 .resolutions()
371 self.update(module_id, &items); 379 // only keep visible names...
380 .map(|(n, res)| {
381 (n, res.filter_visibility(|v| v.is_visible_from_other_crate()))
382 })
383 .filter(|(_, res)| !res.is_none())
384 .collect::<Vec<_>>();
385
386 self.update(module_id, &items, vis);
372 } else { 387 } else {
373 // glob import from same crate => we do an initial 388 // glob import from same crate => we do an initial
374 // import, and then need to propagate any further 389 // import, and then need to propagate any further
@@ -376,13 +391,25 @@ where
376 let scope = &self.def_map[m.local_id].scope; 391 let scope = &self.def_map[m.local_id].scope;
377 392
378 // Module scoped macros is included 393 // Module scoped macros is included
379 let items = scope.collect_resolutions(); 394 let items = scope
380 395 .resolutions()
381 self.update(module_id, &items); 396 // only keep visible names...
397 .map(|(n, res)| {
398 (
399 n,
400 res.filter_visibility(|v| {
401 v.is_visible_from_def_map(&self.def_map, module_id)
402 }),
403 )
404 })
405 .filter(|(_, res)| !res.is_none())
406 .collect::<Vec<_>>();
407
408 self.update(module_id, &items, vis);
382 // record the glob import in case we add further items 409 // record the glob import in case we add further items
383 let glob = self.glob_imports.entry(m.local_id).or_default(); 410 let glob = self.glob_imports.entry(m.local_id).or_default();
384 if !glob.iter().any(|it| *it == (module_id, import_id)) { 411 if !glob.iter().any(|(mid, _)| *mid == module_id) {
385 glob.push((module_id, import_id)); 412 glob.push((module_id, vis));
386 } 413 }
387 } 414 }
388 } 415 }
@@ -396,11 +423,11 @@ where
396 .map(|(local_id, variant_data)| { 423 .map(|(local_id, variant_data)| {
397 let name = variant_data.name.clone(); 424 let name = variant_data.name.clone();
398 let variant = EnumVariantId { parent: e, local_id }; 425 let variant = EnumVariantId { parent: e, local_id };
399 let res = PerNs::both(variant.into(), variant.into()); 426 let res = PerNs::both(variant.into(), variant.into(), vis);
400 (name, res) 427 (name, res)
401 }) 428 })
402 .collect::<Vec<_>>(); 429 .collect::<Vec<_>>();
403 self.update(module_id, &resolutions); 430 self.update(module_id, &resolutions, vis);
404 } 431 }
405 Some(d) => { 432 Some(d) => {
406 log::debug!("glob import {:?} from non-module/enum {:?}", import, d); 433 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -422,21 +449,24 @@ where
422 } 449 }
423 } 450 }
424 451
425 self.update(module_id, &[(name, def)]); 452 self.update(module_id, &[(name, def)], vis);
426 } 453 }
427 None => tested_by!(bogus_paths), 454 None => tested_by!(bogus_paths),
428 } 455 }
429 } 456 }
430 } 457 }
431 458
432 fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) { 459 fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)], vis: Visibility) {
433 self.update_recursive(module_id, resolutions, 0) 460 self.update_recursive(module_id, resolutions, vis, 0)
434 } 461 }
435 462
436 fn update_recursive( 463 fn update_recursive(
437 &mut self, 464 &mut self,
438 module_id: LocalModuleId, 465 module_id: LocalModuleId,
439 resolutions: &[(Name, PerNs)], 466 resolutions: &[(Name, PerNs)],
467 // All resolutions are imported with this visibility; the visibilies in
468 // the `PerNs` values are ignored and overwritten
469 vis: Visibility,
440 depth: usize, 470 depth: usize,
441 ) { 471 ) {
442 if depth > 100 { 472 if depth > 100 {
@@ -446,7 +476,7 @@ where
446 let scope = &mut self.def_map.modules[module_id].scope; 476 let scope = &mut self.def_map.modules[module_id].scope;
447 let mut changed = false; 477 let mut changed = false;
448 for (name, res) in resolutions { 478 for (name, res) in resolutions {
449 changed |= scope.push_res(name.clone(), *res); 479 changed |= scope.push_res(name.clone(), res.with_visibility(vis));
450 } 480 }
451 481
452 if !changed { 482 if !changed {
@@ -459,9 +489,13 @@ where
459 .flat_map(|v| v.iter()) 489 .flat_map(|v| v.iter())
460 .cloned() 490 .cloned()
461 .collect::<Vec<_>>(); 491 .collect::<Vec<_>>();
462 for (glob_importing_module, _glob_import) in glob_imports { 492 for (glob_importing_module, glob_import_vis) in glob_imports {
463 // We pass the glob import so that the tracked import in those modules is that glob import 493 // we know all resolutions have the same visibility (`vis`), so we
464 self.update_recursive(glob_importing_module, resolutions, depth + 1); 494 // just need to check that once
495 if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) {
496 continue;
497 }
498 self.update_recursive(glob_importing_module, resolutions, glob_import_vis, depth + 1);
465 } 499 }
466 } 500 }
467 501
@@ -633,9 +667,13 @@ where
633 let is_macro_use = attrs.by_key("macro_use").exists(); 667 let is_macro_use = attrs.by_key("macro_use").exists();
634 match module { 668 match module {
635 // inline module, just recurse 669 // inline module, just recurse
636 raw::ModuleData::Definition { name, items, ast_id } => { 670 raw::ModuleData::Definition { name, visibility, items, ast_id } => {
637 let module_id = 671 let module_id = self.push_child_module(
638 self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None); 672 name.clone(),
673 AstId::new(self.file_id, *ast_id),
674 None,
675 &visibility,
676 );
639 677
640 ModCollector { 678 ModCollector {
641 def_collector: &mut *self.def_collector, 679 def_collector: &mut *self.def_collector,
@@ -650,7 +688,7 @@ where
650 } 688 }
651 } 689 }
652 // out of line module, resolve, parse and recurse 690 // out of line module, resolve, parse and recurse
653 raw::ModuleData::Declaration { name, ast_id } => { 691 raw::ModuleData::Declaration { name, visibility, ast_id } => {
654 let ast_id = AstId::new(self.file_id, *ast_id); 692 let ast_id = AstId::new(self.file_id, *ast_id);
655 match self.mod_dir.resolve_declaration( 693 match self.mod_dir.resolve_declaration(
656 self.def_collector.db, 694 self.def_collector.db,
@@ -659,7 +697,12 @@ where
659 path_attr, 697 path_attr,
660 ) { 698 ) {
661 Ok((file_id, mod_dir)) => { 699 Ok((file_id, mod_dir)) => {
662 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); 700 let module_id = self.push_child_module(
701 name.clone(),
702 ast_id,
703 Some(file_id),
704 &visibility,
705 );
663 let raw_items = self.def_collector.db.raw_items(file_id.into()); 706 let raw_items = self.def_collector.db.raw_items(file_id.into());
664 ModCollector { 707 ModCollector {
665 def_collector: &mut *self.def_collector, 708 def_collector: &mut *self.def_collector,
@@ -690,7 +733,13 @@ where
690 name: Name, 733 name: Name,
691 declaration: AstId<ast::Module>, 734 declaration: AstId<ast::Module>,
692 definition: Option<FileId>, 735 definition: Option<FileId>,
736 visibility: &crate::visibility::RawVisibility,
693 ) -> LocalModuleId { 737 ) -> LocalModuleId {
738 let vis = self
739 .def_collector
740 .def_map
741 .resolve_visibility(self.def_collector.db, self.module_id, visibility)
742 .unwrap_or(Visibility::Public);
694 let modules = &mut self.def_collector.def_map.modules; 743 let modules = &mut self.def_collector.def_map.modules;
695 let res = modules.alloc(ModuleData::default()); 744 let res = modules.alloc(ModuleData::default());
696 modules[res].parent = Some(self.module_id); 745 modules[res].parent = Some(self.module_id);
@@ -702,7 +751,7 @@ where
702 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; 751 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
703 let def: ModuleDefId = module.into(); 752 let def: ModuleDefId = module.into();
704 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 753 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
705 self.def_collector.update(self.module_id, &[(name, def.into())]); 754 self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))], vis);
706 res 755 res
707 } 756 }
708 757
@@ -716,6 +765,7 @@ where
716 765
717 let name = def.name.clone(); 766 let name = def.name.clone();
718 let container = ContainerId::ModuleId(module); 767 let container = ContainerId::ModuleId(module);
768 let vis = &def.visibility;
719 let def: ModuleDefId = match def.kind { 769 let def: ModuleDefId = match def.kind {
720 raw::DefKind::Function(ast_id) => FunctionLoc { 770 raw::DefKind::Function(ast_id) => FunctionLoc {
721 container: container.into(), 771 container: container.into(),
@@ -761,7 +811,12 @@ where
761 .into(), 811 .into(),
762 }; 812 };
763 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 813 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
764 self.def_collector.update(self.module_id, &[(name, def.into())]) 814 let vis = self
815 .def_collector
816 .def_map
817 .resolve_visibility(self.def_collector.db, self.module_id, vis)
818 .unwrap_or(Visibility::Public);
819 self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))], vis)
765 } 820 }
766 821
767 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { 822 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index 695014c7b..fd6422d60 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -21,6 +21,7 @@ use crate::{
21 nameres::{BuiltinShadowMode, CrateDefMap}, 21 nameres::{BuiltinShadowMode, CrateDefMap},
22 path::{ModPath, PathKind}, 22 path::{ModPath, PathKind},
23 per_ns::PerNs, 23 per_ns::PerNs,
24 visibility::{RawVisibility, Visibility},
24 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 25 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
25}; 26};
26 27
@@ -61,7 +62,35 @@ impl ResolvePathResult {
61 62
62impl CrateDefMap { 63impl CrateDefMap {
63 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 64 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
64 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 65 self.extern_prelude
66 .get(name)
67 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
68 }
69
70 pub(crate) fn resolve_visibility(
71 &self,
72 db: &impl DefDatabase,
73 original_module: LocalModuleId,
74 visibility: &RawVisibility,
75 ) -> Option<Visibility> {
76 match visibility {
77 RawVisibility::Module(path) => {
78 let (result, remaining) =
79 self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module);
80 if remaining.is_some() {
81 return None;
82 }
83 let types = result.take_types()?;
84 match types {
85 ModuleDefId::ModuleId(m) => Some(Visibility::Module(m)),
86 _ => {
87 // error: visibility needs to refer to module
88 None
89 }
90 }
91 }
92 RawVisibility::Public => Some(Visibility::Public),
93 }
65 } 94 }
66 95
67 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 96 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -88,17 +117,21 @@ impl CrateDefMap {
88 PathKind::DollarCrate(krate) => { 117 PathKind::DollarCrate(krate) => {
89 if krate == self.krate { 118 if krate == self.krate {
90 tested_by!(macro_dollar_crate_self); 119 tested_by!(macro_dollar_crate_self);
91 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) 120 PerNs::types(
121 ModuleId { krate: self.krate, local_id: self.root }.into(),
122 Visibility::Public,
123 )
92 } else { 124 } else {
93 let def_map = db.crate_def_map(krate); 125 let def_map = db.crate_def_map(krate);
94 let module = ModuleId { krate, local_id: def_map.root }; 126 let module = ModuleId { krate, local_id: def_map.root };
95 tested_by!(macro_dollar_crate_other); 127 tested_by!(macro_dollar_crate_other);
96 PerNs::types(module.into()) 128 PerNs::types(module.into(), Visibility::Public)
97 } 129 }
98 } 130 }
99 PathKind::Crate => { 131 PathKind::Crate => PerNs::types(
100 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) 132 ModuleId { krate: self.krate, local_id: self.root }.into(),
101 } 133 Visibility::Public,
134 ),
102 // plain import or absolute path in 2015: crate-relative with 135 // plain import or absolute path in 2015: crate-relative with
103 // fallback to extern prelude (with the simplification in 136 // fallback to extern prelude (with the simplification in
104 // rust-lang/rust#57745) 137 // rust-lang/rust#57745)
@@ -126,7 +159,10 @@ impl CrateDefMap {
126 let m = successors(Some(original_module), |m| self.modules[*m].parent) 159 let m = successors(Some(original_module), |m| self.modules[*m].parent)
127 .nth(lvl as usize); 160 .nth(lvl as usize);
128 if let Some(local_id) = m { 161 if let Some(local_id) = m {
129 PerNs::types(ModuleId { krate: self.krate, local_id }.into()) 162 PerNs::types(
163 ModuleId { krate: self.krate, local_id }.into(),
164 Visibility::Public,
165 )
130 } else { 166 } else {
131 log::debug!("super path in root module"); 167 log::debug!("super path in root module");
132 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 168 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -140,7 +176,7 @@ impl CrateDefMap {
140 }; 176 };
141 if let Some(def) = self.extern_prelude.get(&segment) { 177 if let Some(def) = self.extern_prelude.get(&segment) {
142 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 178 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
143 PerNs::types(*def) 179 PerNs::types(*def, Visibility::Public)
144 } else { 180 } else {
145 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 181 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
146 } 182 }
@@ -148,7 +184,7 @@ impl CrateDefMap {
148 }; 184 };
149 185
150 for (i, segment) in segments { 186 for (i, segment) in segments {
151 let curr = match curr_per_ns.take_types() { 187 let (curr, vis) = match curr_per_ns.take_types_vis() {
152 Some(r) => r, 188 Some(r) => r,
153 None => { 189 None => {
154 // we still have path segments left, but the path so far 190 // we still have path segments left, but the path so far
@@ -189,11 +225,11 @@ impl CrateDefMap {
189 match enum_data.variant(&segment) { 225 match enum_data.variant(&segment) {
190 Some(local_id) => { 226 Some(local_id) => {
191 let variant = EnumVariantId { parent: e, local_id }; 227 let variant = EnumVariantId { parent: e, local_id };
192 PerNs::both(variant.into(), variant.into()) 228 PerNs::both(variant.into(), variant.into(), Visibility::Public)
193 } 229 }
194 None => { 230 None => {
195 return ResolvePathResult::with( 231 return ResolvePathResult::with(
196 PerNs::types(e.into()), 232 PerNs::types(e.into(), vis),
197 ReachedFixedPoint::Yes, 233 ReachedFixedPoint::Yes,
198 Some(i), 234 Some(i),
199 Some(self.krate), 235 Some(self.krate),
@@ -211,7 +247,7 @@ impl CrateDefMap {
211 ); 247 );
212 248
213 return ResolvePathResult::with( 249 return ResolvePathResult::with(
214 PerNs::types(s), 250 PerNs::types(s, vis),
215 ReachedFixedPoint::Yes, 251 ReachedFixedPoint::Yes,
216 Some(i), 252 Some(i),
217 Some(self.krate), 253 Some(self.krate),
@@ -235,11 +271,15 @@ impl CrateDefMap {
235 // - current module / scope 271 // - current module / scope
236 // - extern prelude 272 // - extern prelude
237 // - std prelude 273 // - std prelude
238 let from_legacy_macro = 274 let from_legacy_macro = self[module]
239 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); 275 .scope
276 .get_legacy_macro(name)
277 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
240 let from_scope = self[module].scope.get(name, shadow); 278 let from_scope = self[module].scope.get(name, shadow);
241 let from_extern_prelude = 279 let from_extern_prelude = self
242 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 280 .extern_prelude
281 .get(name)
282 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
243 let from_prelude = self.resolve_in_prelude(db, name, shadow); 283 let from_prelude = self.resolve_in_prelude(db, name, shadow);
244 284
245 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) 285 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 73dc08745..fac1169ef 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -16,12 +16,15 @@ use hir_expand::{
16use ra_arena::{impl_arena_id, Arena, RawId}; 16use ra_arena::{impl_arena_id, Arena, RawId};
17use ra_prof::profile; 17use ra_prof::profile;
18use ra_syntax::{ 18use ra_syntax::{
19 ast::{self, AttrsOwner, NameOwner}, 19 ast::{self, AttrsOwner, NameOwner, VisibilityOwner},
20 AstNode, 20 AstNode,
21}; 21};
22use test_utils::tested_by; 22use test_utils::tested_by;
23 23
24use crate::{attr::Attrs, db::DefDatabase, path::ModPath, FileAstId, HirFileId, InFile}; 24use crate::{
25 attr::Attrs, db::DefDatabase, path::ModPath, visibility::RawVisibility, FileAstId, HirFileId,
26 InFile,
27};
25 28
26/// `RawItems` is a set of top-level items in a file (except for impls). 29/// `RawItems` is a set of top-level items in a file (except for impls).
27/// 30///
@@ -122,8 +125,17 @@ impl_arena_id!(Module);
122 125
123#[derive(Debug, PartialEq, Eq)] 126#[derive(Debug, PartialEq, Eq)]
124pub(super) enum ModuleData { 127pub(super) enum ModuleData {
125 Declaration { name: Name, ast_id: FileAstId<ast::Module> }, 128 Declaration {
126 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 129 name: Name,
130 visibility: RawVisibility,
131 ast_id: FileAstId<ast::Module>,
132 },
133 Definition {
134 name: Name,
135 visibility: RawVisibility,
136 ast_id: FileAstId<ast::Module>,
137 items: Vec<RawItem>,
138 },
127} 139}
128 140
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 141#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -138,6 +150,7 @@ pub struct ImportData {
138 pub(super) is_prelude: bool, 150 pub(super) is_prelude: bool,
139 pub(super) is_extern_crate: bool, 151 pub(super) is_extern_crate: bool,
140 pub(super) is_macro_use: bool, 152 pub(super) is_macro_use: bool,
153 pub(super) visibility: RawVisibility,
141} 154}
142 155
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -148,6 +161,7 @@ impl_arena_id!(Def);
148pub(super) struct DefData { 161pub(super) struct DefData {
149 pub(super) name: Name, 162 pub(super) name: Name,
150 pub(super) kind: DefKind, 163 pub(super) kind: DefKind,
164 pub(super) visibility: RawVisibility,
151} 165}
152 166
153#[derive(Debug, PartialEq, Eq, Clone, Copy)] 167#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -218,6 +232,7 @@ impl RawItemsCollector {
218 232
219 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { 233 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) {
220 let attrs = self.parse_attrs(&item); 234 let attrs = self.parse_attrs(&item);
235 let visibility = RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
221 let (kind, name) = match item { 236 let (kind, name) = match item {
222 ast::ModuleItem::Module(module) => { 237 ast::ModuleItem::Module(module) => {
223 self.add_module(current_module, module); 238 self.add_module(current_module, module);
@@ -266,7 +281,7 @@ impl RawItemsCollector {
266 }; 281 };
267 if let Some(name) = name { 282 if let Some(name) = name {
268 let name = name.as_name(); 283 let name = name.as_name();
269 let def = self.raw_items.defs.alloc(DefData { name, kind }); 284 let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
270 self.push_item(current_module, attrs, RawItemKind::Def(def)); 285 self.push_item(current_module, attrs, RawItemKind::Def(def));
271 } 286 }
272 } 287 }
@@ -277,10 +292,12 @@ impl RawItemsCollector {
277 None => return, 292 None => return,
278 }; 293 };
279 let attrs = self.parse_attrs(&module); 294 let attrs = self.parse_attrs(&module);
295 let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene);
280 296
281 let ast_id = self.source_ast_id_map.ast_id(&module); 297 let ast_id = self.source_ast_id_map.ast_id(&module);
282 if module.has_semi() { 298 if module.has_semi() {
283 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id }); 299 let item =
300 self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id });
284 self.push_item(current_module, attrs, RawItemKind::Module(item)); 301 self.push_item(current_module, attrs, RawItemKind::Module(item));
285 return; 302 return;
286 } 303 }
@@ -288,6 +305,7 @@ impl RawItemsCollector {
288 if let Some(item_list) = module.item_list() { 305 if let Some(item_list) = module.item_list() {
289 let item = self.raw_items.modules.alloc(ModuleData::Definition { 306 let item = self.raw_items.modules.alloc(ModuleData::Definition {
290 name, 307 name,
308 visibility,
291 ast_id, 309 ast_id,
292 items: Vec::new(), 310 items: Vec::new(),
293 }); 311 });
@@ -302,6 +320,7 @@ impl RawItemsCollector {
302 // FIXME: cfg_attr 320 // FIXME: cfg_attr
303 let is_prelude = use_item.has_atom_attr("prelude_import"); 321 let is_prelude = use_item.has_atom_attr("prelude_import");
304 let attrs = self.parse_attrs(&use_item); 322 let attrs = self.parse_attrs(&use_item);
323 let visibility = RawVisibility::from_ast_with_hygiene(use_item.visibility(), &self.hygiene);
305 324
306 let mut buf = Vec::new(); 325 let mut buf = Vec::new();
307 ModPath::expand_use_item( 326 ModPath::expand_use_item(
@@ -315,6 +334,7 @@ impl RawItemsCollector {
315 is_prelude, 334 is_prelude,
316 is_extern_crate: false, 335 is_extern_crate: false,
317 is_macro_use: false, 336 is_macro_use: false,
337 visibility: visibility.clone(),
318 }; 338 };
319 buf.push(import_data); 339 buf.push(import_data);
320 }, 340 },
@@ -331,6 +351,8 @@ impl RawItemsCollector {
331 ) { 351 ) {
332 if let Some(name_ref) = extern_crate.name_ref() { 352 if let Some(name_ref) = extern_crate.name_ref() {
333 let path = ModPath::from_name_ref(&name_ref); 353 let path = ModPath::from_name_ref(&name_ref);
354 let visibility =
355 RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene);
334 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 356 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
335 let attrs = self.parse_attrs(&extern_crate); 357 let attrs = self.parse_attrs(&extern_crate);
336 // FIXME: cfg_attr 358 // FIXME: cfg_attr
@@ -342,6 +364,7 @@ impl RawItemsCollector {
342 is_prelude: false, 364 is_prelude: false,
343 is_extern_crate: true, 365 is_extern_crate: true,
344 is_macro_use, 366 is_macro_use,
367 visibility,
345 }; 368 };
346 self.push_import(current_module, attrs, import_data); 369 self.push_import(current_module, attrs, import_data);
347 } 370 }
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index ff474b53b..78bcdc850 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -12,8 +12,8 @@ use test_utils::covers;
12 12
13use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId}; 13use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId};
14 14
15fn def_map(fixtute: &str) -> String { 15fn def_map(fixture: &str) -> String {
16 let dm = compute_crate_def_map(fixtute); 16 let dm = compute_crate_def_map(fixture);
17 render_crate_def_map(&dm) 17 render_crate_def_map(&dm)
18} 18}
19 19
@@ -32,7 +32,7 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
32 *buf += path; 32 *buf += path;
33 *buf += "\n"; 33 *buf += "\n";
34 34
35 let mut entries = map.modules[module].scope.collect_resolutions(); 35 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
36 entries.sort_by_key(|(name, _)| name.clone()); 36 entries.sort_by_key(|(name, _)| name.clone());
37 37
38 for (name, def) in entries { 38 for (name, def) in entries {
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 5e24cb94d..71fa0abe8 100644
--- a/crates/ra_hir_def/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -74,6 +74,83 @@ fn glob_2() {
74} 74}
75 75
76#[test] 76#[test]
77fn glob_privacy_1() {
78 let map = def_map(
79 "
80 //- /lib.rs
81 mod foo;
82 use foo::*;
83
84 //- /foo/mod.rs
85 pub mod bar;
86 pub use self::bar::*;
87 struct PrivateStructFoo;
88
89 //- /foo/bar.rs
90 pub struct Baz;
91 struct PrivateStructBar;
92 pub use super::*;
93 ",
94 );
95 assert_snapshot!(map, @r###"
96 crate
97 Baz: t v
98 bar: t
99 foo: t
100
101 crate::foo
102 Baz: t v
103 PrivateStructFoo: t v
104 bar: t
105
106 crate::foo::bar
107 Baz: t v
108 PrivateStructBar: t v
109 PrivateStructFoo: t v
110 bar: t
111 "###
112 );
113}
114
115#[test]
116fn glob_privacy_2() {
117 let map = def_map(
118 "
119 //- /lib.rs
120 mod foo;
121 use foo::*;
122 use foo::bar::*;
123
124 //- /foo/mod.rs
125 mod bar;
126 fn Foo() {};
127 pub struct Foo {};
128
129 //- /foo/bar.rs
130 pub(super) struct PrivateBaz;
131 struct PrivateBar;
132 pub(crate) struct PubCrateStruct;
133 ",
134 );
135 assert_snapshot!(map, @r###"
136 crate
137 Foo: t
138 PubCrateStruct: t v
139 foo: t
140
141 crate::foo
142 Foo: t v
143 bar: t
144
145 crate::foo::bar
146 PrivateBar: t v
147 PrivateBaz: t v
148 PubCrateStruct: t v
149 "###
150 );
151}
152
153#[test]
77fn glob_across_crates() { 154fn glob_across_crates() {
78 covers!(glob_across_crates); 155 covers!(glob_across_crates);
79 let map = def_map( 156 let map = def_map(
@@ -93,6 +170,26 @@ fn glob_across_crates() {
93} 170}
94 171
95#[test] 172#[test]
173fn glob_privacy_across_crates() {
174 covers!(glob_across_crates);
175 let map = def_map(
176 "
177 //- /main.rs crate:main deps:test_crate
178 use test_crate::*;
179
180 //- /lib.rs crate:test_crate
181 pub struct Baz;
182 struct Foo;
183 ",
184 );
185 assert_snapshot!(map, @r###"
186 â‹®crate
187 â‹®Baz: t v
188 "###
189 );
190}
191
192#[test]
96fn glob_enum() { 193fn glob_enum() {
97 covers!(glob_enum); 194 covers!(glob_enum);
98 let map = def_map( 195 let map = def_map(
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index ef2e9435c..faeb7aa4d 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let crate_def_map = db.crate_def_map(krate); 117 let crate_def_map = db.crate_def_map(krate);
118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
119 assert_eq!(module_data.scope.collect_resolutions().len(), 1); 119 assert_eq!(module_data.scope.resolutions().collect::<Vec<_>>().len(), 1);
120 }); 120 });
121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
122 } 122 }
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
126 let events = db.log_executed(|| { 126 let events = db.log_executed(|| {
127 let crate_def_map = db.crate_def_map(krate); 127 let crate_def_map = db.crate_def_map(krate);
128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
129 assert_eq!(module_data.scope.collect_resolutions().len(), 1); 129 assert_eq!(module_data.scope.resolutions().collect::<Vec<_>>().len(), 1);
130 }); 130 });
131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
132 } 132 }
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 3a5105028..6e435c8c1 100644
--- a/crates/ra_hir_def/src/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
@@ -5,13 +5,13 @@
5 5
6use hir_expand::MacroDefId; 6use hir_expand::MacroDefId;
7 7
8use crate::ModuleDefId; 8use crate::{visibility::Visibility, ModuleDefId};
9 9
10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
11pub struct PerNs { 11pub struct PerNs {
12 pub types: Option<ModuleDefId>, 12 pub types: Option<(ModuleDefId, Visibility)>,
13 pub values: Option<ModuleDefId>, 13 pub values: Option<(ModuleDefId, Visibility)>,
14 pub macros: Option<MacroDefId>, 14 pub macros: Option<(MacroDefId, Visibility)>,
15} 15}
16 16
17impl Default for PerNs { 17impl Default for PerNs {
@@ -25,20 +25,20 @@ impl PerNs {
25 PerNs { types: None, values: None, macros: None } 25 PerNs { types: None, values: None, macros: None }
26 } 26 }
27 27
28 pub fn values(t: ModuleDefId) -> PerNs { 28 pub fn values(t: ModuleDefId, v: Visibility) -> PerNs {
29 PerNs { types: None, values: Some(t), macros: None } 29 PerNs { types: None, values: Some((t, v)), macros: None }
30 } 30 }
31 31
32 pub fn types(t: ModuleDefId) -> PerNs { 32 pub fn types(t: ModuleDefId, v: Visibility) -> PerNs {
33 PerNs { types: Some(t), values: None, macros: None } 33 PerNs { types: Some((t, v)), values: None, macros: None }
34 } 34 }
35 35
36 pub fn both(types: ModuleDefId, values: ModuleDefId) -> PerNs { 36 pub fn both(types: ModuleDefId, values: ModuleDefId, v: Visibility) -> PerNs {
37 PerNs { types: Some(types), values: Some(values), macros: None } 37 PerNs { types: Some((types, v)), values: Some((values, v)), macros: None }
38 } 38 }
39 39
40 pub fn macros(macro_: MacroDefId) -> PerNs { 40 pub fn macros(macro_: MacroDefId, v: Visibility) -> PerNs {
41 PerNs { types: None, values: None, macros: Some(macro_) } 41 PerNs { types: None, values: None, macros: Some((macro_, v)) }
42 } 42 }
43 43
44 pub fn is_none(&self) -> bool { 44 pub fn is_none(&self) -> bool {
@@ -46,15 +46,35 @@ impl PerNs {
46 } 46 }
47 47
48 pub fn take_types(self) -> Option<ModuleDefId> { 48 pub fn take_types(self) -> Option<ModuleDefId> {
49 self.types.map(|it| it.0)
50 }
51
52 pub fn take_types_vis(self) -> Option<(ModuleDefId, Visibility)> {
49 self.types 53 self.types
50 } 54 }
51 55
52 pub fn take_values(self) -> Option<ModuleDefId> { 56 pub fn take_values(self) -> Option<ModuleDefId> {
53 self.values 57 self.values.map(|it| it.0)
54 } 58 }
55 59
56 pub fn take_macros(self) -> Option<MacroDefId> { 60 pub fn take_macros(self) -> Option<MacroDefId> {
57 self.macros 61 self.macros.map(|it| it.0)
62 }
63
64 pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
65 PerNs {
66 types: self.types.filter(|(_, v)| f(*v)),
67 values: self.values.filter(|(_, v)| f(*v)),
68 macros: self.macros.filter(|(_, v)| f(*v)),
69 }
70 }
71
72 pub fn with_visibility(self, vis: Visibility) -> PerNs {
73 PerNs {
74 types: self.types.map(|(it, _)| (it, vis)),
75 values: self.values.map(|(it, _)| (it, vis)),
76 macros: self.macros.map(|(it, _)| (it, vis)),
77 }
58 } 78 }
59 79
60 pub fn or(self, other: PerNs) -> PerNs { 80 pub fn or(self, other: PerNs) -> PerNs {
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index cf3c33d78..43dc751d9 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -19,6 +19,7 @@ use crate::{
19 nameres::CrateDefMap, 19 nameres::CrateDefMap,
20 path::{ModPath, PathKind}, 20 path::{ModPath, PathKind},
21 per_ns::PerNs, 21 per_ns::PerNs,
22 visibility::{RawVisibility, Visibility},
22 AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, 23 AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId,
23 FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, 24 FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
24 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, 25 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
@@ -231,6 +232,23 @@ impl Resolver {
231 Some(res) 232 Some(res)
232 } 233 }
233 234
235 pub fn resolve_visibility(
236 &self,
237 db: &impl DefDatabase,
238 visibility: &RawVisibility,
239 ) -> Option<Visibility> {
240 match visibility {
241 RawVisibility::Module(_) => {
242 let (item_map, module) = match self.module() {
243 Some(it) => it,
244 None => return None,
245 };
246 item_map.resolve_visibility(db, module, visibility)
247 }
248 RawVisibility::Public => Some(Visibility::Public),
249 }
250 }
251
234 pub fn resolve_path_in_value_ns( 252 pub fn resolve_path_in_value_ns(
235 &self, 253 &self,
236 db: &impl DefDatabase, 254 db: &impl DefDatabase,
@@ -448,10 +466,10 @@ impl Scope {
448 f(name.clone(), ScopeDef::PerNs(def)); 466 f(name.clone(), ScopeDef::PerNs(def));
449 }); 467 });
450 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { 468 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
451 f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_))); 469 f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_, Visibility::Public)));
452 }); 470 });
453 m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| { 471 m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| {
454 f(name.clone(), ScopeDef::PerNs(PerNs::types(def.into()))); 472 f(name.clone(), ScopeDef::PerNs(PerNs::types(def.into(), Visibility::Public)));
455 }); 473 });
456 if let Some(prelude) = m.crate_def_map.prelude { 474 if let Some(prelude) = m.crate_def_map.prelude {
457 let prelude_def_map = db.crate_def_map(prelude.krate); 475 let prelude_def_map = db.crate_def_map(prelude.krate);
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs
new file mode 100644
index 000000000..d8296da4b
--- /dev/null
+++ b/crates/ra_hir_def/src/visibility.rs
@@ -0,0 +1,120 @@
1//! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).
2
3use hir_expand::{hygiene::Hygiene, InFile};
4use ra_syntax::ast;
5
6use 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)]
14pub 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
22impl RawVisibility {
23 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: &impl DefDatabase,
30 node: InFile<Option<ast::Visibility>>,
31 ) -> RawVisibility {
32 Self::from_ast_with_hygiene(node.value, &Hygiene::new(db, node.file_id))
33 }
34
35 pub(crate) fn from_ast_with_hygiene(
36 node: Option<ast::Visibility>,
37 hygiene: &Hygiene,
38 ) -> RawVisibility {
39 let node = match node {
40 None => return RawVisibility::private(),
41 Some(node) => node,
42 };
43 match node.kind() {
44 ast::VisibilityKind::In(path) => {
45 let path = ModPath::from_src(path, hygiene);
46 let path = match path {
47 None => return RawVisibility::private(),
48 Some(path) => path,
49 };
50 RawVisibility::Module(path)
51 }
52 ast::VisibilityKind::PubCrate => {
53 let path = ModPath { kind: PathKind::Crate, segments: Vec::new() };
54 RawVisibility::Module(path)
55 }
56 ast::VisibilityKind::PubSuper => {
57 let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() };
58 RawVisibility::Module(path)
59 }
60 ast::VisibilityKind::Pub => RawVisibility::Public,
61 }
62 }
63
64 pub fn resolve(
65 &self,
66 db: &impl DefDatabase,
67 resolver: &crate::resolver::Resolver,
68 ) -> Visibility {
69 // we fall back to public visibility (i.e. fail open) if the path can't be resolved
70 resolver.resolve_visibility(db, self).unwrap_or(Visibility::Public)
71 }
72}
73
74/// Visibility of an item, with the path resolved.
75#[derive(Debug, Copy, Clone, PartialEq, Eq)]
76pub enum Visibility {
77 /// Visibility is restricted to a certain module.
78 Module(ModuleId),
79 /// Visibility is unrestricted.
80 Public,
81}
82
83impl Visibility {
84 pub fn is_visible_from(self, db: &impl DefDatabase, from_module: ModuleId) -> bool {
85 let to_module = match self {
86 Visibility::Module(m) => m,
87 Visibility::Public => return true,
88 };
89 // if they're not in the same crate, it can't be visible
90 if from_module.krate != to_module.krate {
91 return false;
92 }
93 let def_map = db.crate_def_map(from_module.krate);
94 self.is_visible_from_def_map(&def_map, from_module.local_id)
95 }
96
97 pub(crate) fn is_visible_from_other_crate(self) -> bool {
98 match self {
99 Visibility::Module(_) => false,
100 Visibility::Public => true,
101 }
102 }
103
104 pub(crate) fn is_visible_from_def_map(
105 self,
106 def_map: &crate::nameres::CrateDefMap,
107 from_module: crate::LocalModuleId,
108 ) -> bool {
109 let to_module = match self {
110 Visibility::Module(m) => m,
111 Visibility::Public => return true,
112 };
113 // from_module needs to be a descendant of to_module
114 let mut ancestors = std::iter::successors(Some(from_module), |m| {
115 let parent_id = def_map[*m].parent?;
116 Some(parent_id)
117 });
118 ancestors.any(|m| m == to_module.local_id)
119 }
120}
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 294964887..210a685e4 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Type; 3use hir::{HasVisibility, Type};
4 4
5use crate::completion::completion_item::CompletionKind; 5use crate::completion::completion_item::CompletionKind;
6use crate::{ 6use crate::{
@@ -38,9 +38,15 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
39 for receiver in receiver.autoderef(ctx.db) { 39 for receiver in receiver.autoderef(ctx.db) {
40 for (field, ty) in receiver.fields(ctx.db) { 40 for (field, ty) in receiver.fields(ctx.db) {
41 if ctx.module.map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
42 // Skip private field. FIXME: If the definition location of the
43 // field is editable, we should show the completion
44 continue;
45 }
41 acc.add_field(ctx, field, &ty); 46 acc.add_field(ctx, field, &ty);
42 } 47 }
43 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { 48 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
49 // FIXME: Handle visibility
44 acc.add_tuple_field(ctx, i, &ty); 50 acc.add_tuple_field(ctx, i, &ty);
45 } 51 }
46 } 52 }
@@ -187,6 +193,55 @@ mod tests {
187 } 193 }
188 194
189 #[test] 195 #[test]
196 fn test_struct_field_visibility_private() {
197 assert_debug_snapshot!(
198 do_ref_completion(
199 r"
200 mod inner {
201 struct A {
202 private_field: u32,
203 pub pub_field: u32,
204 pub(crate) crate_field: u32,
205 pub(super) super_field: u32,
206 }
207 }
208 fn foo(a: inner::A) {
209 a.<|>
210 }
211 ",
212 ),
213 @r###"
214 [
215 CompletionItem {
216 label: "crate_field",
217 source_range: [313; 313),
218 delete: [313; 313),
219 insert: "crate_field",
220 kind: Field,
221 detail: "u32",
222 },
223 CompletionItem {
224 label: "pub_field",
225 source_range: [313; 313),
226 delete: [313; 313),
227 insert: "pub_field",
228 kind: Field,
229 detail: "u32",
230 },
231 CompletionItem {
232 label: "super_field",
233 source_range: [313; 313),
234 delete: [313; 313),
235 insert: "super_field",
236 kind: Field,
237 detail: "u32",
238 },
239 ]
240 "###
241 );
242 }
243
244 #[test]
190 fn test_method_completion() { 245 fn test_method_completion() {
191 assert_debug_snapshot!( 246 assert_debug_snapshot!(
192 do_ref_completion( 247 do_ref_completion(
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
18pub use self::{ 18pub 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
417pub enum VisibilityKind {
418 In(ast::Path),
419 PubCrate,
420 PubSuper,
421 Pub,
422}
423
424impl 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}
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 9f9d6e63c..e64c83d33 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1064,6 +1064,7 @@ impl AstNode for ExternCrateItem {
1064 } 1064 }
1065} 1065}
1066impl ast::AttrsOwner for ExternCrateItem {} 1066impl ast::AttrsOwner for ExternCrateItem {}
1067impl ast::VisibilityOwner for ExternCrateItem {}
1067impl ExternCrateItem { 1068impl ExternCrateItem {
1068 pub fn name_ref(&self) -> Option<NameRef> { 1069 pub fn name_ref(&self) -> Option<NameRef> {
1069 AstChildren::new(&self.syntax).next() 1070 AstChildren::new(&self.syntax).next()
@@ -2006,6 +2007,7 @@ impl AstNode for ModuleItem {
2006 } 2007 }
2007} 2008}
2008impl ast::AttrsOwner for ModuleItem {} 2009impl ast::AttrsOwner for ModuleItem {}
2010impl ast::VisibilityOwner for ModuleItem {}
2009impl ModuleItem {} 2011impl ModuleItem {}
2010#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2012#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2011pub struct Name { 2013pub struct Name {
@@ -3893,6 +3895,7 @@ impl AstNode for UseItem {
3893 } 3895 }
3894} 3896}
3895impl ast::AttrsOwner for UseItem {} 3897impl ast::AttrsOwner for UseItem {}
3898impl ast::VisibilityOwner for UseItem {}
3896impl UseItem { 3899impl UseItem {
3897 pub fn use_tree(&self) -> Option<UseTree> { 3900 pub fn use_tree(&self) -> Option<UseTree> {
3898 AstChildren::new(&self.syntax).next() 3901 AstChildren::new(&self.syntax).next()
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 08aafb610..e43a724f0 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -412,7 +412,7 @@ Grammar(
412 "ModuleItem": ( 412 "ModuleItem": (
413 enum: ["StructDef", "UnionDef", "EnumDef", "FnDef", "TraitDef", "TypeAliasDef", "ImplBlock", 413 enum: ["StructDef", "UnionDef", "EnumDef", "FnDef", "TraitDef", "TypeAliasDef", "ImplBlock",
414 "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ], 414 "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ],
415 traits: ["AttrsOwner"], 415 traits: ["AttrsOwner", "VisibilityOwner"],
416 ), 416 ),
417 "ImplItem": ( 417 "ImplItem": (
418 enum: ["FnDef", "TypeAliasDef", "ConstDef"], 418 enum: ["FnDef", "TypeAliasDef", "ConstDef"],
@@ -683,7 +683,7 @@ Grammar(
683 ] 683 ]
684 ), 684 ),
685 "UseItem": ( 685 "UseItem": (
686 traits: ["AttrsOwner"], 686 traits: ["AttrsOwner", "VisibilityOwner"],
687 options: [ "UseTree" ], 687 options: [ "UseTree" ],
688 ), 688 ),
689 "UseTree": ( 689 "UseTree": (
@@ -696,7 +696,7 @@ Grammar(
696 collections: [("use_trees", "UseTree")] 696 collections: [("use_trees", "UseTree")]
697 ), 697 ),
698 "ExternCrateItem": ( 698 "ExternCrateItem": (
699 traits: ["AttrsOwner"], 699 traits: ["AttrsOwner", "VisibilityOwner"],
700 options: ["NameRef", "Alias"], 700 options: ["NameRef", "Alias"],
701 ), 701 ),
702 "ArgList": ( 702 "ArgList": (