Skip to content

Commit 33972da

Browse files
bors[bot]Veykril
andauthored
Merge #9651
9651: Restrict completions inside visibility modifiers r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 4705df4 + f6cb42f commit 33972da

File tree

7 files changed

+53
-9
lines changed

7 files changed

+53
-9
lines changed

crates/ide_completion/src/completions/keyword.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,16 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
3939
let has_block_expr_parent = ctx.has_block_expr_parent();
4040
let expects_item = ctx.expects_item();
4141

42+
if let Some(ImmediateLocation::Visibility(vis)) = &ctx.completion_location {
43+
if vis.in_token().is_none() {
44+
add_keyword("in", "in");
45+
}
46+
return;
47+
}
4248
if ctx.has_impl_or_trait_prev_sibling() {
43-
add_keyword("where", "where ");
49+
add_keyword("where", "where");
4450
if ctx.has_impl_prev_sibling() {
45-
add_keyword("for", "for ");
51+
add_keyword("for", "for");
4652
}
4753
return;
4854
}
@@ -62,12 +68,12 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
6268
if !ctx.has_visibility_prev_sibling()
6369
&& (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
6470
{
65-
add_keyword("pub(crate)", "pub(crate) ");
66-
add_keyword("pub", "pub ");
71+
add_keyword("pub(crate)", "pub(crate)");
72+
add_keyword("pub", "pub");
6773
}
6874

6975
if expects_item || expects_assoc_item || has_block_expr_parent {
70-
add_keyword("unsafe", "unsafe ");
76+
add_keyword("unsafe", "unsafe");
7177
add_keyword("fn", "fn $1($2) {\n $0\n}");
7278
add_keyword("const", "const $0");
7379
add_keyword("type", "type $0");
@@ -110,7 +116,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
110116
}
111117

112118
if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
113-
add_keyword("let", "let ");
119+
add_keyword("let", "let");
114120
}
115121

116122
if ctx.after_if() {

crates/ide_completion/src/completions/unqualified_path.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
2424
return;
2525
}
2626
std::array::IntoIter::new(["self", "super", "crate"]).for_each(|kw| acc.add_keyword(ctx, kw));
27+
if let Some(ImmediateLocation::Visibility(_)) = ctx.completion_location {
28+
return;
29+
}
2730

2831
if ctx.expects_item() || ctx.expects_assoc_item() {
2932
// only show macros in {Assoc}ItemList

crates/ide_completion/src/patterns.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub(crate) enum ImmediateLocation {
4141
Attribute(ast::Attr),
4242
// Fake file ast node
4343
ModDeclaration(ast::Module),
44+
Visibility(ast::Visibility),
4445
// Original file ast node
4546
MethodCall {
4647
receiver: Option<ast::Expr>,
@@ -246,6 +247,8 @@ pub(crate) fn determine_location(
246247
.and_then(|r| find_node_with_range(original_file, r)),
247248
has_parens: it.arg_list().map_or(false, |it| it.l_paren_token().is_some())
248249
},
250+
ast::Visibility(it) => it.pub_token()
251+
.and_then(|t| (t.text_range().end() < offset).then(|| ImmediateLocation::Visibility(it)))?,
249252
_ => return None,
250253
}
251254
};

crates/ide_completion/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ mod item_list;
99
mod item;
1010
mod pattern;
1111
mod predicate;
12+
mod sourcegen;
1213
mod type_pos;
1314
mod use_tree;
14-
15-
mod sourcegen;
15+
mod visibility;
1616

1717
use std::mem;
1818

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//! Completion tests for visibility modifiers.
2+
use expect_test::{expect, Expect};
3+
4+
use crate::tests::completion_list;
5+
6+
fn check(ra_fixture: &str, expect: Expect) {
7+
let actual = completion_list(ra_fixture);
8+
expect.assert_eq(&actual)
9+
}
10+
11+
#[test]
12+
fn empty_pub() {
13+
check(
14+
r#"
15+
pub($0)
16+
"#,
17+
expect![[r#"
18+
kw in
19+
kw self
20+
kw super
21+
kw crate
22+
"#]],
23+
);
24+
}

crates/parser/src/grammar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ fn opt_visibility(p: &mut Parser) -> bool {
162162
// test pub_parens_typepath
163163
// struct B(pub (super::A));
164164
// struct B(pub (crate::A,));
165-
T![crate] | T![self] | T![super] if p.nth(2) != T![:] => {
165+
T![crate] | T![self] | T![super] | T![ident] if p.nth(2) != T![:] => {
166166
p.bump_any();
167167
let path_m = p.start();
168168
let path_segment_m = p.start();

crates/syntax/src/validation.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<Syntax
211211
}
212212

213213
fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
214+
if vis.in_token().is_none() {
215+
if vis.path().and_then(|p| p.as_single_name_ref()).and_then(|n| n.ident_token()).is_some() {
216+
errors.push(SyntaxError::new(
217+
"incorrect visibility restriction",
218+
vis.syntax.text_range(),
219+
));
220+
}
221+
}
214222
let parent = match vis.syntax().parent() {
215223
Some(it) => it,
216224
None => return,

0 commit comments

Comments
 (0)