Restrict completions inside visibility modifiers

This commit is contained in:
Lukas Wirth 2021-07-20 18:37:52 +02:00
parent ea105f9396
commit f6cb42fdb8
7 changed files with 53 additions and 9 deletions

View File

@ -39,10 +39,16 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
let has_block_expr_parent = ctx.has_block_expr_parent();
let expects_item = ctx.expects_item();
if let Some(ImmediateLocation::Visibility(vis)) = &ctx.completion_location {
if vis.in_token().is_none() {
add_keyword("in", "in");
}
return;
}
if ctx.has_impl_or_trait_prev_sibling() {
add_keyword("where", "where ");
add_keyword("where", "where");
if ctx.has_impl_prev_sibling() {
add_keyword("for", "for ");
add_keyword("for", "for");
}
return;
}
@ -62,12 +68,12 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
if !ctx.has_visibility_prev_sibling()
&& (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
{
add_keyword("pub(crate)", "pub(crate) ");
add_keyword("pub", "pub ");
add_keyword("pub(crate)", "pub(crate)");
add_keyword("pub", "pub");
}
if expects_item || expects_assoc_item || has_block_expr_parent {
add_keyword("unsafe", "unsafe ");
add_keyword("unsafe", "unsafe");
add_keyword("fn", "fn $1($2) {\n $0\n}");
add_keyword("const", "const $0");
add_keyword("type", "type $0");
@ -110,7 +116,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
}
if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
add_keyword("let", "let ");
add_keyword("let", "let");
}
if ctx.after_if() {

View File

@ -24,6 +24,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return;
}
std::array::IntoIter::new(["self", "super", "crate"]).for_each(|kw| acc.add_keyword(ctx, kw));
if let Some(ImmediateLocation::Visibility(_)) = ctx.completion_location {
return;
}
if ctx.expects_item() || ctx.expects_assoc_item() {
// only show macros in {Assoc}ItemList

View File

@ -41,6 +41,7 @@ pub(crate) enum ImmediateLocation {
Attribute(ast::Attr),
// Fake file ast node
ModDeclaration(ast::Module),
Visibility(ast::Visibility),
// Original file ast node
MethodCall {
receiver: Option<ast::Expr>,
@ -246,6 +247,8 @@ pub(crate) fn determine_location(
.and_then(|r| find_node_with_range(original_file, r)),
has_parens: it.arg_list().map_or(false, |it| it.l_paren_token().is_some())
},
ast::Visibility(it) => it.pub_token()
.and_then(|t| (t.text_range().end() < offset).then(|| ImmediateLocation::Visibility(it)))?,
_ => return None,
}
};

View File

@ -9,10 +9,10 @@
mod item;
mod pattern;
mod predicate;
mod sourcegen;
mod type_pos;
mod use_tree;
mod sourcegen;
mod visibility;
use std::mem;

View File

@ -0,0 +1,24 @@
//! Completion tests for visibility modifiers.
use expect_test::{expect, Expect};
use crate::tests::completion_list;
fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list(ra_fixture);
expect.assert_eq(&actual)
}
#[test]
fn empty_pub() {
check(
r#"
pub($0)
"#,
expect![[r#"
kw in
kw self
kw super
kw crate
"#]],
);
}

View File

@ -162,7 +162,7 @@ fn opt_visibility(p: &mut Parser) -> bool {
// test pub_parens_typepath
// struct B(pub (super::A));
// struct B(pub (crate::A,));
T![crate] | T![self] | T![super] if p.nth(2) != T![:] => {
T![crate] | T![self] | T![super] | T![ident] if p.nth(2) != T![:] => {
p.bump_any();
let path_m = p.start();
let path_segment_m = p.start();

View File

@ -211,6 +211,14 @@ fn int_token(name_ref: Option<ast::NameRef>) -> Option<SyntaxToken> {
}
fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
if vis.in_token().is_none() {
if vis.path().and_then(|p| p.as_single_name_ref()).and_then(|n| n.ident_token()).is_some() {
errors.push(SyntaxError::new(
"incorrect visibility restriction",
vis.syntax.text_range(),
));
}
}
let parent = match vis.syntax().parent() {
Some(it) => it,
None => return,