aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock15
-rw-r--r--crates/ra_assists/src/assist_ctx.rs2
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs131
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs22
-rw-r--r--crates/ra_hir/src/code_model.rs30
-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_hir_ty/src/display.rs12
-rw-r--r--crates/ra_hir_ty/src/lib.rs31
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs57
-rw-r--r--crates/ra_ide/src/inlay_hints.rs37
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs2
-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
-rw-r--r--docs/user/assists.md22
-rw-r--r--xtask/tests/tidy-tests/cli.rs2
30 files changed, 831 insertions, 177 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7d2911076..b63b5ae13 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,7 +10,7 @@ dependencies = [
10 10
11[[package]] 11[[package]]
12name = "anyhow" 12name = "anyhow"
13version = "1.0.25" 13version = "1.0.26"
14source = "registry+https://github.com/rust-lang/crates.io-index" 14source = "registry+https://github.com/rust-lang/crates.io-index"
15 15
16[[package]] 16[[package]]
@@ -237,7 +237,7 @@ dependencies = [
237 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 237 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
238 "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 238 "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
239 "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 239 "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
240 "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 240 "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
241 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 241 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
242] 242]
243 243
@@ -273,9 +273,10 @@ dependencies = [
273 273
274[[package]] 274[[package]]
275name = "crossbeam-queue" 275name = "crossbeam-queue"
276version = "0.2.0" 276version = "0.2.1"
277source = "registry+https://github.com/rust-lang/crates.io-index" 277source = "registry+https://github.com/rust-lang/crates.io-index"
278dependencies = [ 278dependencies = [
279 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
279 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 280 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
280] 281]
281 282
@@ -1349,7 +1350,7 @@ version = "1.7.0"
1349source = "registry+https://github.com/rust-lang/crates.io-index" 1350source = "registry+https://github.com/rust-lang/crates.io-index"
1350dependencies = [ 1351dependencies = [
1351 "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1352 "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1352 "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1353 "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1353 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 1354 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
1354 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1355 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1355 "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", 1356 "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1767,7 +1768,7 @@ dependencies = [
1767name = "xtask" 1768name = "xtask"
1768version = "0.1.0" 1769version = "0.1.0"
1769dependencies = [ 1770dependencies = [
1770 "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", 1771 "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
1771 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1772 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1772 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1773 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1773 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1774 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1786,7 +1787,7 @@ dependencies = [
1786 1787
1787[metadata] 1788[metadata]
1788"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 1789"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
1789"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" 1790"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
1790"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" 1791"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
1791"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 1792"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
1792"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 1793"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
@@ -1817,7 +1818,7 @@ dependencies = [
1817"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" 1818"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
1818"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" 1819"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
1819"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" 1820"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
1820"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700" 1821"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
1821"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" 1822"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
1822"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 1823"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
1823"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f" 1824"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f"
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 993aebc47..28152f724 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -46,7 +46,7 @@ pub(crate) enum Assist {
46/// 46///
47/// Note, however, that we don't actually use such two-phase logic at the 47/// Note, however, that we don't actually use such two-phase logic at the
48/// moment, because the LSP API is pretty awkward in this place, and it's much 48/// moment, because the LSP API is pretty awkward in this place, and it's much
49/// easier to just compute the edit eagerly :-)#[derive(Debug, Clone)] 49/// easier to just compute the edit eagerly :-)
50#[derive(Debug)] 50#[derive(Debug)]
51pub(crate) struct AssistCtx<'a, DB> { 51pub(crate) struct AssistCtx<'a, DB> {
52 pub(crate) db: &'a DB, 52 pub(crate) db: &'a DB,
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index cef669cb5..bc49e71fe 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -1,3 +1,5 @@
1use std::collections::HashMap;
2
1use hir::{db::HirDatabase, HasSource}; 3use hir::{db::HirDatabase, HasSource};
2use ra_syntax::{ 4use ra_syntax::{
3 ast::{self, edit, make, AstNode, NameOwner}, 5 ast::{self, edit, make, AstNode, NameOwner},
@@ -17,26 +19,26 @@ enum AddMissingImplMembersMode {
17// Adds scaffold for required impl members. 19// Adds scaffold for required impl members.
18// 20//
19// ``` 21// ```
20// trait T { 22// trait Trait<T> {
21// Type X; 23// Type X;
22// fn foo(&self); 24// fn foo(&self) -> T;
23// fn bar(&self) {} 25// fn bar(&self) {}
24// } 26// }
25// 27//
26// impl T for () {<|> 28// impl Trait<u32> for () {<|>
27// 29//
28// } 30// }
29// ``` 31// ```
30// -> 32// ->
31// ``` 33// ```
32// trait T { 34// trait Trait<T> {
33// Type X; 35// Type X;
34// fn foo(&self); 36// fn foo(&self) -> T;
35// fn bar(&self) {} 37// fn bar(&self) {}
36// } 38// }
37// 39//
38// impl T for () { 40// impl Trait<u32> for () {
39// fn foo(&self) { unimplemented!() } 41// fn foo(&self) -> u32 { unimplemented!() }
40// 42//
41// } 43// }
42// ``` 44// ```
@@ -54,13 +56,13 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
54// Adds scaffold for overriding default impl members. 56// Adds scaffold for overriding default impl members.
55// 57//
56// ``` 58// ```
57// trait T { 59// trait Trait {
58// Type X; 60// Type X;
59// fn foo(&self); 61// fn foo(&self);
60// fn bar(&self) {} 62// fn bar(&self) {}
61// } 63// }
62// 64//
63// impl T for () { 65// impl Trait for () {
64// Type X = (); 66// Type X = ();
65// fn foo(&self) {}<|> 67// fn foo(&self) {}<|>
66// 68//
@@ -68,13 +70,13 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
68// ``` 70// ```
69// -> 71// ->
70// ``` 72// ```
71// trait T { 73// trait Trait {
72// Type X; 74// Type X;
73// fn foo(&self); 75// fn foo(&self);
74// fn bar(&self) {} 76// fn bar(&self) {}
75// } 77// }
76// 78//
77// impl T for () { 79// impl Trait for () {
78// Type X = (); 80// Type X = ();
79// fn foo(&self) {} 81// fn foo(&self) {}
80// fn bar(&self) {} 82// fn bar(&self) {}
@@ -99,7 +101,7 @@ fn add_missing_impl_members_inner(
99 let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?; 101 let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?;
100 let impl_item_list = impl_node.item_list()?; 102 let impl_item_list = impl_node.item_list()?;
101 103
102 let trait_def = { 104 let (trait_, trait_def) = {
103 let analyzer = ctx.source_analyzer(impl_node.syntax(), None); 105 let analyzer = ctx.source_analyzer(impl_node.syntax(), None);
104 106
105 resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? 107 resolve_target_trait_def(ctx.db, &analyzer, &impl_node)?
@@ -132,10 +134,25 @@ fn add_missing_impl_members_inner(
132 return None; 134 return None;
133 } 135 }
134 136
137 let file_id = ctx.frange.file_id;
138 let db = ctx.db;
139
135 ctx.add_assist(AssistId(assist_id), label, |edit| { 140 ctx.add_assist(AssistId(assist_id), label, |edit| {
136 let n_existing_items = impl_item_list.impl_items().count(); 141 let n_existing_items = impl_item_list.impl_items().count();
142 let substs = get_syntactic_substs(impl_node).unwrap_or_default();
143 let generic_def: hir::GenericDef = trait_.into();
144 let substs_by_param: HashMap<_, _> = generic_def
145 .params(db)
146 .into_iter()
147 // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
148 .skip(1)
149 .zip(substs.into_iter())
150 .collect();
137 let items = missing_items 151 let items = missing_items
138 .into_iter() 152 .into_iter()
153 .map(|it| {
154 substitute_type_params(db, hir::InFile::new(file_id.into(), it), &substs_by_param)
155 })
139 .map(|it| match it { 156 .map(|it| match it {
140 ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), 157 ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)),
141 _ => it, 158 _ => it,
@@ -160,13 +177,63 @@ fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
160 } 177 }
161} 178}
162 179
180// FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
181// trait ref, and then go from the types in the substs back to the syntax)
182// FIXME: This should be a general utility (not even just for assists)
183fn get_syntactic_substs(impl_block: ast::ImplBlock) -> Option<Vec<ast::TypeRef>> {
184 let target_trait = impl_block.target_trait()?;
185 let path_type = match target_trait {
186 ast::TypeRef::PathType(path) => path,
187 _ => return None,
188 };
189 let type_arg_list = path_type.path()?.segment()?.type_arg_list()?;
190 let mut result = Vec::new();
191 for type_arg in type_arg_list.type_args() {
192 let type_arg: ast::TypeArg = type_arg;
193 result.push(type_arg.type_ref()?);
194 }
195 Some(result)
196}
197
198// FIXME: This should be a general utility (not even just for assists)
199fn substitute_type_params<N: AstNode>(
200 db: &impl HirDatabase,
201 node: hir::InFile<N>,
202 substs: &HashMap<hir::TypeParam, ast::TypeRef>,
203) -> N {
204 let type_param_replacements = node
205 .value
206 .syntax()
207 .descendants()
208 .filter_map(ast::TypeRef::cast)
209 .filter_map(|n| {
210 let path = match &n {
211 ast::TypeRef::PathType(path_type) => path_type.path()?,
212 _ => return None,
213 };
214 let analyzer = hir::SourceAnalyzer::new(db, node.with_value(n.syntax()), None);
215 let resolution = analyzer.resolve_path(db, &path)?;
216 match resolution {
217 hir::PathResolution::TypeParam(tp) => Some((n, substs.get(&tp)?.clone())),
218 _ => None,
219 }
220 })
221 .collect::<Vec<_>>();
222
223 if type_param_replacements.is_empty() {
224 node.value
225 } else {
226 edit::replace_descendants(&node.value, type_param_replacements.into_iter())
227 }
228}
229
163/// Given an `ast::ImplBlock`, resolves the target trait (the one being 230/// Given an `ast::ImplBlock`, resolves the target trait (the one being
164/// implemented) to a `ast::TraitDef`. 231/// implemented) to a `ast::TraitDef`.
165fn resolve_target_trait_def( 232fn resolve_target_trait_def(
166 db: &impl HirDatabase, 233 db: &impl HirDatabase,
167 analyzer: &hir::SourceAnalyzer, 234 analyzer: &hir::SourceAnalyzer,
168 impl_block: &ast::ImplBlock, 235 impl_block: &ast::ImplBlock,
169) -> Option<ast::TraitDef> { 236) -> Option<(hir::Trait, ast::TraitDef)> {
170 let ast_path = impl_block 237 let ast_path = impl_block
171 .target_trait() 238 .target_trait()
172 .map(|it| it.syntax().clone()) 239 .map(|it| it.syntax().clone())
@@ -174,7 +241,9 @@ fn resolve_target_trait_def(
174 .path()?; 241 .path()?;
175 242
176 match analyzer.resolve_path(db, &ast_path) { 243 match analyzer.resolve_path(db, &ast_path) {
177 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).value), 244 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => {
245 Some((def, def.source(db).value))
246 }
178 _ => None, 247 _ => None,
179 } 248 }
180} 249}
@@ -281,6 +350,40 @@ impl Foo for S {
281 } 350 }
282 351
283 #[test] 352 #[test]
353 fn fill_in_type_params_1() {
354 check_assist(
355 add_missing_impl_members,
356 "
357trait Foo<T> { fn foo(&self, t: T) -> &T; }
358struct S;
359impl Foo<u32> for S { <|> }",
360 "
361trait Foo<T> { fn foo(&self, t: T) -> &T; }
362struct S;
363impl Foo<u32> for S {
364 <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() }
365}",
366 );
367 }
368
369 #[test]
370 fn fill_in_type_params_2() {
371 check_assist(
372 add_missing_impl_members,
373 "
374trait Foo<T> { fn foo(&self, t: T) -> &T; }
375struct S;
376impl<U> Foo<U> for S { <|> }",
377 "
378trait Foo<T> { fn foo(&self, t: T) -> &T; }
379struct S;
380impl<U> Foo<U> for S {
381 <|>fn foo(&self, t: U) -> &U { unimplemented!() }
382}",
383 );
384 }
385
386 #[test]
284 fn test_cursor_after_empty_impl_block() { 387 fn test_cursor_after_empty_impl_block() {
285 check_assist( 388 check_assist(
286 add_missing_impl_members, 389 add_missing_impl_members,
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 4586eeb59..7d84dc8fb 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -101,26 +101,26 @@ fn doctest_add_impl_default_members() {
101 check( 101 check(
102 "add_impl_default_members", 102 "add_impl_default_members",
103 r#####" 103 r#####"
104trait T { 104trait Trait {
105 Type X; 105 Type X;
106 fn foo(&self); 106 fn foo(&self);
107 fn bar(&self) {} 107 fn bar(&self) {}
108} 108}
109 109
110impl T for () { 110impl Trait for () {
111 Type X = (); 111 Type X = ();
112 fn foo(&self) {}<|> 112 fn foo(&self) {}<|>
113 113
114} 114}
115"#####, 115"#####,
116 r#####" 116 r#####"
117trait T { 117trait Trait {
118 Type X; 118 Type X;
119 fn foo(&self); 119 fn foo(&self);
120 fn bar(&self) {} 120 fn bar(&self) {}
121} 121}
122 122
123impl T for () { 123impl Trait for () {
124 Type X = (); 124 Type X = ();
125 fn foo(&self) {} 125 fn foo(&self) {}
126 fn bar(&self) {} 126 fn bar(&self) {}
@@ -135,25 +135,25 @@ fn doctest_add_impl_missing_members() {
135 check( 135 check(
136 "add_impl_missing_members", 136 "add_impl_missing_members",
137 r#####" 137 r#####"
138trait T { 138trait Trait<T> {
139 Type X; 139 Type X;
140 fn foo(&self); 140 fn foo(&self) -> T;
141 fn bar(&self) {} 141 fn bar(&self) {}
142} 142}
143 143
144impl T for () {<|> 144impl Trait<u32> for () {<|>
145 145
146} 146}
147"#####, 147"#####,
148 r#####" 148 r#####"
149trait T { 149trait Trait<T> {
150 Type X; 150 Type X;
151 fn foo(&self); 151 fn foo(&self) -> T;
152 fn bar(&self) {} 152 fn bar(&self) {}
153} 153}
154 154
155impl T for () { 155impl Trait<u32> for () {
156 fn foo(&self) { unimplemented!() } 156 fn foo(&self) -> u32 { unimplemented!() }
157 157
158} 158}
159"#####, 159"#####,
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index bcfc0d03e..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,
@@ -644,6 +653,17 @@ impl_froms!(
644 Const 653 Const
645); 654);
646 655
656impl GenericDef {
657 pub fn params(self, db: &impl HirDatabase) -> Vec<TypeParam> {
658 let generics: Arc<hir_def::generics::GenericParams> = db.generic_params(self.into());
659 generics
660 .types
661 .iter()
662 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
663 .collect()
664 }
665}
666
647#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 667#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
648pub struct Local { 668pub struct Local {
649 pub(crate) parent: DefWithBody, 669 pub(crate) parent: DefWithBody,
@@ -1030,3 +1050,11 @@ impl<T: Into<AttrDef> + Copy> Docs for T {
1030 db.documentation(def.into()) 1050 db.documentation(def.into())
1031 } 1051 }
1032} 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_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index dcca1bace..37def7c03 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -10,7 +10,7 @@ pub struct HirFormatter<'a, 'b, DB> {
10 buf: String, 10 buf: String,
11 curr_size: usize, 11 curr_size: usize,
12 max_size: Option<usize>, 12 max_size: Option<usize>,
13 should_display_default_types: bool, 13 omit_verbose_types: bool,
14} 14}
15 15
16pub trait HirDisplay { 16pub trait HirDisplay {
@@ -20,7 +20,7 @@ pub trait HirDisplay {
20 where 20 where
21 Self: Sized, 21 Self: Sized,
22 { 22 {
23 HirDisplayWrapper(db, self, None, true) 23 HirDisplayWrapper(db, self, None, false)
24 } 24 }
25 25
26 fn display_truncated<'a, DB>( 26 fn display_truncated<'a, DB>(
@@ -31,7 +31,7 @@ pub trait HirDisplay {
31 where 31 where
32 Self: Sized, 32 Self: Sized,
33 { 33 {
34 HirDisplayWrapper(db, self, max_size, false) 34 HirDisplayWrapper(db, self, max_size, true)
35 } 35 }
36} 36}
37 37
@@ -74,8 +74,8 @@ where
74 } 74 }
75 } 75 }
76 76
77 pub fn should_display_default_types(&self) -> bool { 77 pub fn omit_verbose_types(&self) -> bool {
78 self.should_display_default_types 78 self.omit_verbose_types
79 } 79 }
80} 80}
81 81
@@ -93,7 +93,7 @@ where
93 buf: String::with_capacity(20), 93 buf: String::with_capacity(20),
94 curr_size: 0, 94 curr_size: 0,
95 max_size: self.2, 95 max_size: self.2,
96 should_display_default_types: self.3, 96 omit_verbose_types: self.3,
97 }) 97 })
98 } 98 }
99} 99}
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 48abf97c9..55b6dd836 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -821,6 +821,8 @@ impl TypeWalk for Ty {
821 } 821 }
822} 822}
823 823
824const TYPE_HINT_TRUNCATION: &str = "…";
825
824impl HirDisplay for &Ty { 826impl HirDisplay for &Ty {
825 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 827 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
826 HirDisplay::hir_fmt(*self, f) 828 HirDisplay::hir_fmt(*self, f)
@@ -830,7 +832,7 @@ impl HirDisplay for &Ty {
830impl HirDisplay for ApplicationTy { 832impl HirDisplay for ApplicationTy {
831 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 833 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
832 if f.should_truncate() { 834 if f.should_truncate() {
833 return write!(f, ""); 835 return write!(f, "{}", TYPE_HINT_TRUNCATION);
834 } 836 }
835 837
836 match self.ctor { 838 match self.ctor {
@@ -908,9 +910,7 @@ impl HirDisplay for ApplicationTy {
908 write!(f, "<")?; 910 write!(f, "<")?;
909 911
910 let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); 912 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
911 let parameters_to_write = if f.should_display_default_types() { 913 let parameters_to_write = if f.omit_verbose_types() {
912 self.parameters.0.as_ref()
913 } else {
914 match self 914 match self
915 .ctor 915 .ctor
916 .as_generic_def() 916 .as_generic_def()
@@ -935,6 +935,8 @@ impl HirDisplay for ApplicationTy {
935 &non_default_parameters 935 &non_default_parameters
936 } 936 }
937 } 937 }
938 } else {
939 self.parameters.0.as_ref()
938 }; 940 };
939 941
940 f.write_joined(parameters_to_write, ", ")?; 942 f.write_joined(parameters_to_write, ", ")?;
@@ -959,9 +961,16 @@ impl HirDisplay for ApplicationTy {
959 let sig = self.parameters[0] 961 let sig = self.parameters[0]
960 .callable_sig(f.db) 962 .callable_sig(f.db)
961 .expect("first closure parameter should contain signature"); 963 .expect("first closure parameter should contain signature");
962 write!(f, "|")?; 964 let return_type_hint = sig.ret().display(f.db);
963 f.write_joined(sig.params(), ", ")?; 965 if sig.params().is_empty() {
964 write!(f, "| -> {}", sig.ret().display(f.db))?; 966 write!(f, "|| -> {}", return_type_hint)?;
967 } else if f.omit_verbose_types() {
968 write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
969 } else {
970 write!(f, "|")?;
971 f.write_joined(sig.params(), ", ")?;
972 write!(f, "| -> {}", return_type_hint)?;
973 };
965 } 974 }
966 } 975 }
967 Ok(()) 976 Ok(())
@@ -971,7 +980,7 @@ impl HirDisplay for ApplicationTy {
971impl HirDisplay for ProjectionTy { 980impl HirDisplay for ProjectionTy {
972 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 981 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
973 if f.should_truncate() { 982 if f.should_truncate() {
974 return write!(f, ""); 983 return write!(f, "{}", TYPE_HINT_TRUNCATION);
975 } 984 }
976 985
977 let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); 986 let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone();
@@ -989,7 +998,7 @@ impl HirDisplay for ProjectionTy {
989impl HirDisplay for Ty { 998impl HirDisplay for Ty {
990 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 999 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
991 if f.should_truncate() { 1000 if f.should_truncate() {
992 return write!(f, ""); 1001 return write!(f, "{}", TYPE_HINT_TRUNCATION);
993 } 1002 }
994 1003
995 match self { 1004 match self {
@@ -1074,7 +1083,7 @@ impl HirDisplay for Ty {
1074impl TraitRef { 1083impl TraitRef {
1075 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { 1084 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
1076 if f.should_truncate() { 1085 if f.should_truncate() {
1077 return write!(f, ""); 1086 return write!(f, "{}", TYPE_HINT_TRUNCATION);
1078 } 1087 }
1079 1088
1080 self.substs[0].hir_fmt(f)?; 1089 self.substs[0].hir_fmt(f)?;
@@ -1108,7 +1117,7 @@ impl HirDisplay for &GenericPredicate {
1108impl HirDisplay for GenericPredicate { 1117impl HirDisplay for GenericPredicate {
1109 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 1118 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1110 if f.should_truncate() { 1119 if f.should_truncate() {
1111 return write!(f, ""); 1120 return write!(f, "{}", TYPE_HINT_TRUNCATION);
1112 } 1121 }
1113 1122
1114 match self { 1123 match self {
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_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index c5e406977..977aafc51 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -293,7 +293,7 @@ fn main() {
293 } 293 }
294 294
295 #[test] 295 #[test]
296 fn closure_parameter() { 296 fn closure_parameters() {
297 let (analysis, file_id) = single_file( 297 let (analysis, file_id) = single_file(
298 r#" 298 r#"
299fn main() { 299fn main() {
@@ -301,6 +301,11 @@ fn main() {
301 (0..2).for_each(|increment| { 301 (0..2).for_each(|increment| {
302 start += increment; 302 start += increment;
303 }) 303 })
304
305 let multiply = |a, b, c, d| a * b * c * d;
306 let _: i32 = multiply(1, 2, 3, 4);
307
308 let return_42 = || 42;
304}"#, 309}"#,
305 ); 310 );
306 311
@@ -316,6 +321,36 @@ fn main() {
316 kind: TypeHint, 321 kind: TypeHint,
317 label: "i32", 322 label: "i32",
318 }, 323 },
324 InlayHint {
325 range: [114; 122),
326 kind: TypeHint,
327 label: "|…| -> i32",
328 },
329 InlayHint {
330 range: [126; 127),
331 kind: TypeHint,
332 label: "i32",
333 },
334 InlayHint {
335 range: [129; 130),
336 kind: TypeHint,
337 label: "i32",
338 },
339 InlayHint {
340 range: [132; 133),
341 kind: TypeHint,
342 label: "i32",
343 },
344 InlayHint {
345 range: [135; 136),
346 kind: TypeHint,
347 label: "i32",
348 },
349 InlayHint {
350 range: [201; 210),
351 kind: TypeHint,
352 label: "|| -> i32",
353 },
319 ] 354 ]
320 "### 355 "###
321 ); 356 );
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index c862d3912..1b3c246c7 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -165,7 +165,7 @@ impl CargoWorkspace {
165 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` 165 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
166 // https://github.com/oli-obk/cargo_metadata/issues/79 166 // https://github.com/oli-obk/cargo_metadata/issues/79
167 meta.features(CargoOpt::NoDefaultFeatures); 167 meta.features(CargoOpt::NoDefaultFeatures);
168 } else { 168 } else if cargo_features.features.len() > 0 {
169 meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); 169 meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
170 } 170 }
171 if let Some(parent) = cargo_toml.parent() { 171 if let Some(parent) = cargo_toml.parent() {
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": (
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 334ba450f..ecf206f71 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -98,26 +98,26 @@ Adds scaffold for overriding default impl members.
98 98
99```rust 99```rust
100// BEFORE 100// BEFORE
101trait T { 101trait Trait {
102 Type X; 102 Type X;
103 fn foo(&self); 103 fn foo(&self);
104 fn bar(&self) {} 104 fn bar(&self) {}
105} 105}
106 106
107impl T for () { 107impl Trait for () {
108 Type X = (); 108 Type X = ();
109 fn foo(&self) {}┃ 109 fn foo(&self) {}┃
110 110
111} 111}
112 112
113// AFTER 113// AFTER
114trait T { 114trait Trait {
115 Type X; 115 Type X;
116 fn foo(&self); 116 fn foo(&self);
117 fn bar(&self) {} 117 fn bar(&self) {}
118} 118}
119 119
120impl T for () { 120impl Trait for () {
121 Type X = (); 121 Type X = ();
122 fn foo(&self) {} 122 fn foo(&self) {}
123 fn bar(&self) {} 123 fn bar(&self) {}
@@ -131,25 +131,25 @@ Adds scaffold for required impl members.
131 131
132```rust 132```rust
133// BEFORE 133// BEFORE
134trait T { 134trait Trait<T> {
135 Type X; 135 Type X;
136 fn foo(&self); 136 fn foo(&self) -> T;
137 fn bar(&self) {} 137 fn bar(&self) {}
138} 138}
139 139
140impl T for () {┃ 140impl Trait<u32> for () {┃
141 141
142} 142}
143 143
144// AFTER 144// AFTER
145trait T { 145trait Trait<T> {
146 Type X; 146 Type X;
147 fn foo(&self); 147 fn foo(&self) -> T;
148 fn bar(&self) {} 148 fn bar(&self) {}
149} 149}
150 150
151impl T for () { 151impl Trait<u32> for () {
152 fn foo(&self) { unimplemented!() } 152 fn foo(&self) -> u32 { unimplemented!() }
153 153
154} 154}
155``` 155```
diff --git a/xtask/tests/tidy-tests/cli.rs b/xtask/tests/tidy-tests/cli.rs
index 573ffadbf..f9ca45292 100644
--- a/xtask/tests/tidy-tests/cli.rs
+++ b/xtask/tests/tidy-tests/cli.rs
@@ -43,7 +43,7 @@ fn no_todo() {
43 return; 43 return;
44 } 44 }
45 let text = std::fs::read_to_string(e.path()).unwrap(); 45 let text = std::fs::read_to_string(e.path()).unwrap();
46 if text.contains("TODO") || text.contains("TOOD") { 46 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
47 panic!( 47 panic!(
48 "\nTODO markers should not be committed to the master branch,\n\ 48 "\nTODO markers should not be committed to the master branch,\n\
49 use FIXME instead\n\ 49 use FIXME instead\n\