internal: prevent possible bugs when adding magical comments

This commit is contained in:
Aleksey Kladov 2021-09-13 13:43:13 +03:00
parent c56f041477
commit 076c972e3b
5 changed files with 139 additions and 109 deletions

View file

@ -6,21 +6,21 @@ use syntax::{
use crate::{AssistContext, AssistId, AssistKind, Assists};
/// Assist: line_to_block
///
/// Converts comments between block and single-line form
///
/// ```
/// // Multi-line
/// // comment
/// ```
/// ->
/// ```
/// /**
/// Multi-line
/// comment
/// */
/// ```
// Assist: line_to_block
//
// Converts comments between block and single-line form.
//
// ```
// // Multi-line$0
// // comment
// ```
// ->
// ```
// /*
// Multi-line
// comment
// */
// ```
pub(crate) fn convert_comment_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let comment = ctx.find_token_at_offset::<ast::Comment>()?;
// Only allow comments which are alone on their line

View file

@ -1064,6 +1064,23 @@ fn main() {
)
}
#[test]
fn doctest_line_to_block() {
check_doc_test(
"line_to_block",
r#####"
// Multi-line$0
// comment
"#####,
r#####"
/*
Multi-line
comment
*/
"#####,
)
}
#[test]
fn doctest_make_raw_string() {
check_doc_test(

View file

@ -1,95 +1,4 @@
//! Feature: completion with imports-on-the-fly
//!
//! When completing names in the current scope, proposes additional imports from other modules or crates,
//! if they can be qualified in the scope, and their name contains all symbols from the completion input.
//!
//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
//!
//! ```
//! fn main() {
//! pda$0
//! }
//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
//! ```
//! ->
//! ```
//! use std::marker::PhantomData;
//!
//! fn main() {
//! PhantomData
//! }
//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
//! ```
//!
//! Also completes associated items, that require trait imports.
//! If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
//! Currently, only the imports with their import path ending with the whole qualifier will be proposed
//! (no fuzzy matching for qualifier).
//!
//! ```
//! mod foo {
//! pub mod bar {
//! pub struct Item;
//!
//! impl Item {
//! pub const TEST_ASSOC: usize = 3;
//! }
//! }
//! }
//!
//! fn main() {
//! bar::Item::TEST_A$0
//! }
//! ```
//! ->
//! ```
//! use foo::bar;
//!
//! mod foo {
//! pub mod bar {
//! pub struct Item;
//!
//! impl Item {
//! pub const TEST_ASSOC: usize = 3;
//! }
//! }
//! }
//!
//! fn main() {
//! bar::Item::TEST_ASSOC
//! }
//! ```
//!
//! NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
//! no imports will be proposed.
//!
//! .Fuzzy search details
//!
//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
//! For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
//! (but shows all associated items for any input length).
//!
//! .Import configuration
//!
//! It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
//! Mimics the corresponding behavior of the `Auto Import` feature.
//!
//! .LSP and performance implications
//!
//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
//! (case-sensitive) resolve client capability in its client capabilities.
//! This way the server is able to defer the costly computations, doing them for a selected completion item only.
//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
//! which might be slow ergo the feature is automatically disabled.
//!
//! .Feature toggle
//!
//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
//! capability enabled.
//! See [`import_on_the_fly`].
use ide_db::helpers::{
import_assets::{ImportAssets, ImportCandidate},
insert_use::ImportScope,
@ -105,6 +14,97 @@ use crate::{
use super::Completions;
// Feature: Completion With Autoimport
//
// When completing names in the current scope, proposes additional imports from other modules or crates,
// if they can be qualified in the scope, and their name contains all symbols from the completion input.
//
// To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
// If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
//
// ```
// fn main() {
// pda$0
// }
// # pub mod std { pub mod marker { pub struct PhantomData { } } }
// ```
// ->
// ```
// use std::marker::PhantomData;
//
// fn main() {
// PhantomData
// }
// # pub mod std { pub mod marker { pub struct PhantomData { } } }
// ```
//
// Also completes associated items, that require trait imports.
// If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
// Currently, only the imports with their import path ending with the whole qualifier will be proposed
// (no fuzzy matching for qualifier).
//
// ```
// mod foo {
// pub mod bar {
// pub struct Item;
//
// impl Item {
// pub const TEST_ASSOC: usize = 3;
// }
// }
// }
//
// fn main() {
// bar::Item::TEST_A$0
// }
// ```
// ->
// ```
// use foo::bar;
//
// mod foo {
// pub mod bar {
// pub struct Item;
//
// impl Item {
// pub const TEST_ASSOC: usize = 3;
// }
// }
// }
//
// fn main() {
// bar::Item::TEST_ASSOC
// }
// ```
//
// NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
// no imports will be proposed.
//
// .Fuzzy search details
//
// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
// (i.e. in `HashMap` in the `std::collections::HashMap` path).
// For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
// (but shows all associated items for any input length).
//
// .Import configuration
//
// It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
// Mimics the corresponding behavior of the `Auto Import` feature.
//
// .LSP and performance implications
//
// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
// (case-sensitive) resolve client capability in its client capabilities.
// This way the server is able to defer the costly computations, doing them for a selected completion item only.
// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
// which might be slow ergo the feature is automatically disabled.
//
// .Feature toggle
//
// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
// capability enabled.
pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
if !ctx.config.enable_imports_on_the_fly {
return None;

View file

@ -1,4 +1,4 @@
//! See `complete_fn_param`.
//! See [`complete_fn_param`].
use rustc_hash::FxHashMap;
use syntax::{

View file

@ -48,6 +48,7 @@ pub struct CommentBlock {
pub id: String,
pub line: usize,
pub contents: Vec<String>,
is_doc: bool,
}
impl CommentBlock {
@ -61,6 +62,13 @@ impl CommentBlock {
.filter_map(|mut block| {
let first = block.contents.remove(0);
first.strip_prefix(&tag).map(|id| {
if block.is_doc {
panic!(
"Use plain (non-doc) comments with tags like {}:\n {}",
tag, first
)
}
block.id = id.trim().to_string();
block
})
@ -73,11 +81,16 @@ impl CommentBlock {
let lines = text.lines().map(str::trim_start);
let dummy_block = CommentBlock { id: String::new(), line: 0, contents: Vec::new() };
let dummy_block =
CommentBlock { id: String::new(), line: 0, contents: Vec::new(), is_doc: false };
let mut block = dummy_block.clone();
for (line_num, line) in lines.enumerate() {
match line.strip_prefix("//") {
Some(mut contents) => {
if let Some('/' | '!') = contents.chars().next() {
contents = &contents[1..];
block.is_doc = true;
}
if let Some(' ') = contents.chars().next() {
contents = &contents[1..];
}