mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Resolve single assist only
This commit is contained in:
parent
e5cdcb8b12
commit
1679a376f3
9 changed files with 78 additions and 32 deletions
|
@ -85,7 +85,7 @@ pub struct DiagnosticsConfig {
|
||||||
pub(crate) fn diagnostics(
|
pub(crate) fn diagnostics(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
config: &DiagnosticsConfig,
|
config: &DiagnosticsConfig,
|
||||||
resolve: AssistResolveStrategy,
|
resolve: &AssistResolveStrategy,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
) -> Vec<Diagnostic> {
|
) -> Vec<Diagnostic> {
|
||||||
let _p = profile::span("diagnostics");
|
let _p = profile::span("diagnostics");
|
||||||
|
@ -213,7 +213,7 @@ pub(crate) fn diagnostics(
|
||||||
fn diagnostic_with_fix<D: DiagnosticWithFix>(
|
fn diagnostic_with_fix<D: DiagnosticWithFix>(
|
||||||
d: &D,
|
d: &D,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
resolve: AssistResolveStrategy,
|
resolve: &AssistResolveStrategy,
|
||||||
) -> Diagnostic {
|
) -> Diagnostic {
|
||||||
Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
|
Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
|
||||||
.with_fix(d.fix(&sema, resolve))
|
.with_fix(d.fix(&sema, resolve))
|
||||||
|
@ -223,7 +223,7 @@ fn diagnostic_with_fix<D: DiagnosticWithFix>(
|
||||||
fn warning_with_fix<D: DiagnosticWithFix>(
|
fn warning_with_fix<D: DiagnosticWithFix>(
|
||||||
d: &D,
|
d: &D,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
resolve: AssistResolveStrategy,
|
resolve: &AssistResolveStrategy,
|
||||||
) -> Diagnostic {
|
) -> Diagnostic {
|
||||||
Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
|
Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
|
||||||
.with_fix(d.fix(&sema, resolve))
|
.with_fix(d.fix(&sema, resolve))
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub(crate) trait DiagnosticWithFix: Diagnostic {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist>;
|
) -> Option<Assist>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ impl DiagnosticWithFix for UnresolvedModule {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let root = sema.db.parse_or_expand(self.file)?;
|
let root = sema.db.parse_or_expand(self.file)?;
|
||||||
let unresolved_module = self.decl.to_node(&root);
|
let unresolved_module = self.decl.to_node(&root);
|
||||||
|
@ -71,7 +71,7 @@ impl DiagnosticWithFix for NoSuchField {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let root = sema.db.parse_or_expand(self.file)?;
|
let root = sema.db.parse_or_expand(self.file)?;
|
||||||
missing_record_expr_field_fix(
|
missing_record_expr_field_fix(
|
||||||
|
@ -86,7 +86,7 @@ impl DiagnosticWithFix for MissingFields {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
// Note that although we could add a diagnostics to
|
// Note that although we could add a diagnostics to
|
||||||
// fill the missing tuple field, e.g :
|
// fill the missing tuple field, e.g :
|
||||||
|
@ -126,7 +126,7 @@ impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let root = sema.db.parse_or_expand(self.file)?;
|
let root = sema.db.parse_or_expand(self.file)?;
|
||||||
let tail_expr = self.expr.to_node(&root);
|
let tail_expr = self.expr.to_node(&root);
|
||||||
|
@ -143,7 +143,7 @@ impl DiagnosticWithFix for RemoveThisSemicolon {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let root = sema.db.parse_or_expand(self.file)?;
|
let root = sema.db.parse_or_expand(self.file)?;
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ impl DiagnosticWithFix for IncorrectCase {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
resolve: AssistResolveStrategy,
|
resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let root = sema.db.parse_or_expand(self.file)?;
|
let root = sema.db.parse_or_expand(self.file)?;
|
||||||
let name_node = self.ident.to_node(&root);
|
let name_node = self.ident.to_node(&root);
|
||||||
|
@ -191,7 +191,7 @@ impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let root = sema.db.parse_or_expand(self.file)?;
|
let root = sema.db.parse_or_expand(self.file)?;
|
||||||
let next_expr = self.next_expr.to_node(&root);
|
let next_expr = self.next_expr.to_node(&root);
|
||||||
|
|
|
@ -54,7 +54,7 @@ impl DiagnosticWithFix for UnlinkedFile {
|
||||||
fn fix(
|
fn fix(
|
||||||
&self,
|
&self,
|
||||||
sema: &hir::Semantics<RootDatabase>,
|
sema: &hir::Semantics<RootDatabase>,
|
||||||
_resolve: AssistResolveStrategy,
|
_resolve: &AssistResolveStrategy,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
// If there's an existing module that could add a `mod` item to include the unlinked file,
|
// If there's an existing module that could add a `mod` item to include the unlinked file,
|
||||||
// suggest that as a fix.
|
// suggest that as a fix.
|
||||||
|
|
|
@ -522,7 +522,7 @@ impl Analysis {
|
||||||
frange: FileRange,
|
frange: FileRange,
|
||||||
) -> Cancelable<Vec<Assist>> {
|
) -> Cancelable<Vec<Assist>> {
|
||||||
self.with_db(|db| {
|
self.with_db(|db| {
|
||||||
let ssr_assists = ssr::ssr_assists(db, resolve, frange);
|
let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
|
||||||
let mut acc = Assist::get(db, config, resolve, frange);
|
let mut acc = Assist::get(db, config, resolve, frange);
|
||||||
acc.extend(ssr_assists.into_iter());
|
acc.extend(ssr_assists.into_iter());
|
||||||
acc
|
acc
|
||||||
|
@ -536,7 +536,7 @@ impl Analysis {
|
||||||
resolve: AssistResolveStrategy,
|
resolve: AssistResolveStrategy,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
) -> Cancelable<Vec<Diagnostic>> {
|
) -> Cancelable<Vec<Diagnostic>> {
|
||||||
self.with_db(|db| diagnostics::diagnostics(db, config, resolve, file_id))
|
self.with_db(|db| diagnostics::diagnostics(db, config, &resolve, file_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function to return assists + quick fixes for diagnostics
|
/// Convenience function to return assists + quick fixes for diagnostics
|
||||||
|
@ -553,9 +553,9 @@ impl Analysis {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.with_db(|db| {
|
self.with_db(|db| {
|
||||||
let ssr_assists = ssr::ssr_assists(db, resolve, frange);
|
let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
|
||||||
let diagnostic_assists = if include_fixes {
|
let diagnostic_assists = if include_fixes {
|
||||||
diagnostics::diagnostics(db, diagnostics_config, resolve, frange.file_id)
|
diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|it| it.fix)
|
.filter_map(|it| it.fix)
|
||||||
.filter(|it| it.target.intersect(frange.range).is_some())
|
.filter(|it| it.target.intersect(frange.range).is_some())
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, Root
|
||||||
|
|
||||||
pub(crate) fn ssr_assists(
|
pub(crate) fn ssr_assists(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
resolve: AssistResolveStrategy,
|
resolve: &AssistResolveStrategy,
|
||||||
frange: FileRange,
|
frange: FileRange,
|
||||||
) -> Vec<Assist> {
|
) -> Vec<Assist> {
|
||||||
let mut ssr_assists = Vec::with_capacity(2);
|
let mut ssr_assists = Vec::with_capacity(2);
|
||||||
|
@ -73,7 +73,7 @@ mod tests {
|
||||||
let mut local_roots = FxHashSet::default();
|
let mut local_roots = FxHashSet::default();
|
||||||
local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
|
local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
|
||||||
db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
|
db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
|
||||||
ssr_assists(&db, resolve, FileRange { file_id, range: range_or_offset.into() })
|
ssr_assists(&db, &resolve, FileRange { file_id, range: range_or_offset.into() })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -17,6 +17,8 @@ mod tests;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod ast_transform;
|
pub mod ast_transform;
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::base_db::FileRange;
|
use ide_db::base_db::FileRange;
|
||||||
use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
|
use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
|
||||||
|
@ -56,6 +58,35 @@ impl AssistKind {
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
AssistKind::None => "None",
|
||||||
|
AssistKind::QuickFix => "QuickFix",
|
||||||
|
AssistKind::Generate => "Generate",
|
||||||
|
AssistKind::Refactor => "Refactor",
|
||||||
|
AssistKind::RefactorExtract => "RefactorExtract",
|
||||||
|
AssistKind::RefactorInline => "RefactorInline",
|
||||||
|
AssistKind::RefactorRewrite => "RefactorRewrite",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for AssistKind {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"None" => Ok(AssistKind::None),
|
||||||
|
"QuickFix" => Ok(AssistKind::QuickFix),
|
||||||
|
"Generate" => Ok(AssistKind::Generate),
|
||||||
|
"Refactor" => Ok(AssistKind::Refactor),
|
||||||
|
"RefactorExtract" => Ok(AssistKind::RefactorExtract),
|
||||||
|
"RefactorInline" => Ok(AssistKind::RefactorInline),
|
||||||
|
"RefactorRewrite" => Ok(AssistKind::RefactorRewrite),
|
||||||
|
unknown => Err(format!("Unknown AssistKind: '{}'", unknown)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unique identifier of the assist, should not be shown to the user
|
/// Unique identifier of the assist, should not be shown to the user
|
||||||
|
@ -64,11 +95,11 @@ impl AssistKind {
|
||||||
pub struct AssistId(pub &'static str, pub AssistKind);
|
pub struct AssistId(pub &'static str, pub AssistKind);
|
||||||
|
|
||||||
// TODO kb docs
|
// TODO kb docs
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AssistResolveStrategy {
|
pub enum AssistResolveStrategy {
|
||||||
None,
|
None,
|
||||||
All,
|
All,
|
||||||
Single(AssistId),
|
Single(String, AssistKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssistResolveStrategy {
|
impl AssistResolveStrategy {
|
||||||
|
@ -76,7 +107,9 @@ impl AssistResolveStrategy {
|
||||||
match self {
|
match self {
|
||||||
AssistResolveStrategy::None => false,
|
AssistResolveStrategy::None => false,
|
||||||
AssistResolveStrategy::All => true,
|
AssistResolveStrategy::All => true,
|
||||||
AssistResolveStrategy::Single(id_to_resolve) => id_to_resolve == id,
|
AssistResolveStrategy::Single(id_to_resolve, kind) => {
|
||||||
|
id_to_resolve == id.0 && kind == &id.1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use ide::{
|
use ide::{
|
||||||
AnnotationConfig, AssistResolveStrategy, FileId, FilePosition, FileRange, HoverAction,
|
AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange,
|
||||||
HoverGotoTypeData, Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange,
|
HoverAction, HoverGotoTypeData, Query, RangeInfo, Runnable, RunnableKind, SearchScope,
|
||||||
TextEdit,
|
SourceChange, TextEdit,
|
||||||
};
|
};
|
||||||
use ide_db::SymbolKind;
|
use ide_db::SymbolKind;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -28,7 +28,7 @@ use lsp_types::{
|
||||||
use project_model::TargetKind;
|
use project_model::TargetKind;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::to_value;
|
use serde_json::to_value;
|
||||||
use stdx::{format_to, split_once};
|
use stdx::format_to;
|
||||||
use syntax::{algo, ast, AstNode, TextRange, TextSize};
|
use syntax::{algo, ast, AstNode, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -1058,18 +1058,27 @@ pub(crate) fn handle_code_action_resolve(
|
||||||
.only
|
.only
|
||||||
.map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
|
.map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
|
||||||
|
|
||||||
|
let assist_kind: AssistKind = match params.kind.parse() {
|
||||||
|
Ok(kind) => kind,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(LspError::new(
|
||||||
|
ErrorCode::InvalidParams as i32,
|
||||||
|
format!("For the assist to resolve, failed to parse the kind: {}", e),
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let assists = snap.analysis.assists_with_fixes(
|
let assists = snap.analysis.assists_with_fixes(
|
||||||
&assists_config,
|
&assists_config,
|
||||||
&snap.config.diagnostics(),
|
&snap.config.diagnostics(),
|
||||||
// TODO kb pass a certain id
|
AssistResolveStrategy::Single(params.id.clone(), assist_kind),
|
||||||
AssistResolveStrategy::All,
|
|
||||||
frange,
|
frange,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let (id, index) = split_once(¶ms.id, ':').unwrap();
|
let assist = &assists[params.index];
|
||||||
let index = index.parse::<usize>().unwrap();
|
assert!(assist.id.0 == params.id);
|
||||||
let assist = &assists[index];
|
assert!(assist.id.1 == assist_kind);
|
||||||
assert!(assist.id.0 == id);
|
|
||||||
let edit = to_proto::code_action(&snap, assist.clone(), None)?.edit;
|
let edit = to_proto::code_action(&snap, assist.clone(), None)?.edit;
|
||||||
code_action.edit = edit;
|
code_action.edit = edit;
|
||||||
Ok(code_action)
|
Ok(code_action)
|
||||||
|
|
|
@ -303,6 +303,8 @@ pub struct CodeAction {
|
||||||
pub struct CodeActionData {
|
pub struct CodeActionData {
|
||||||
pub code_action_params: lsp_types::CodeActionParams,
|
pub code_action_params: lsp_types::CodeActionParams,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
pub kind: String,
|
||||||
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||||
|
|
|
@ -897,8 +897,10 @@ pub(crate) fn code_action(
|
||||||
(Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
|
(Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
|
||||||
(None, Some((index, code_action_params))) => {
|
(None, Some((index, code_action_params))) => {
|
||||||
res.data = Some(lsp_ext::CodeActionData {
|
res.data = Some(lsp_ext::CodeActionData {
|
||||||
id: format!("{}:{}", assist.id.0, index.to_string()),
|
id: assist.id.0.to_string(),
|
||||||
code_action_params,
|
code_action_params,
|
||||||
|
kind: assist.id.1.name().to_string(),
|
||||||
|
index,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue