diff --git a/language_service/src/completion.rs b/language_service/src/completion.rs index b4a7b9bd4b..7e3e41e7a0 100644 --- a/language_service/src/completion.rs +++ b/language_service/src/completion.rs @@ -102,6 +102,16 @@ fn expected_word_kinds( source_contents: &str, cursor_offset: u32, ) -> WordKinds { + // We should not retun any completions in comments. + // This compensates for a bug in [`possible_words_at_offset_in_source`] . + // Ideally, that function would be aware of the comment context and not + // return any completions, however this is difficult to do today because + // of the parser's unawareness of comment tokens. + // So we do a simple check here where we have access to the full source contents. + if in_comment(source_contents, cursor_offset) { + return WordKinds::empty(); + } + match &compilation.kind { CompilationKind::OpenProject { package_graph_sources, @@ -121,6 +131,16 @@ fn expected_word_kinds( } } +fn in_comment(source_contents: &str, cursor_offset: u32) -> bool { + // find the last newline before the cursor + let last_line_start = source_contents[..cursor_offset as usize] + .rfind('\n') + .unwrap_or(0); + // find the last comment start before the cursor + let last_comment_start = source_contents[last_line_start..cursor_offset as usize].rfind("//"); + last_comment_start.is_some() +} + /// Collects hardcoded completions from the given set of parser predictions. /// /// Hardcoded words are actual keywords (`let`, etc) as well as other words that are diff --git a/language_service/src/completion/tests.rs b/language_service/src/completion/tests.rs index 4e5aed3a13..cd1a00856c 100644 --- a/language_service/src/completion/tests.rs +++ b/language_service/src/completion/tests.rs @@ -121,6 +121,13 @@ fn check_with_dependency( assert_no_duplicates(actual_completions); } +fn check_no_completions(source_with_cursor: &str) { + let (compilation, cursor_position, _) = compile_with_markers(source_with_cursor, true); + let actual_completions = + get_completions(&compilation, "", cursor_position, Encoding::Utf8); + assert_eq!(actual_completions.items, Vec::default()); +} + fn assert_no_duplicates(mut actual_completions: CompletionList) { actual_completions .items @@ -4075,42 +4082,55 @@ fn incomplete_return_type_in_partial_callable_signature() { #[test] fn no_path_segment_completion_inside_attr() { - check( + check_no_completions( "namespace Test { @Config(FakeStdLib.↘) function Main() : Unit { } }", - &["Fake", "not", "Test"], - &expect![[r#" - [ - None, - None, - None, - ] - "#]], ); } #[test] fn no_completion_inside_attr() { - check( + check_no_completions( "namespace Test { @Config(↘) function Main() : Unit { - let FakeStdLib = new Foo { bar = 3 }; - FakeStdLib.↘ } }", - &["Fake", "not", "Test"], - &expect![[r#" - [ - None, - None, - None, - ] - "#]], + ); +} + +#[test] +fn in_comment() { + check_no_completions( + "namespace Test { + import Foo; + // Hello there ↘ + import Bar; + }", + ); +} + +#[test] +fn in_doc_comment() { + check_no_completions( + "namespace Test { + import Foo; + /// Hello there ↘ + import Bar; + }", + ); +} + +#[test] +fn in_trailing_comment() { + check_no_completions( + "namespace Test { + import Foo; // Hello there ↘ + }", ); }