mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 21:28:51 +00:00
internal: cut deps between assists and diagnostics
This commit is contained in:
parent
2e8dab631b
commit
a91071b57b
10 changed files with 147 additions and 140 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -678,7 +678,6 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"hir",
|
"hir",
|
||||||
"ide_assists",
|
|
||||||
"ide_db",
|
"ide_db",
|
||||||
"itertools",
|
"itertools",
|
||||||
"profile",
|
"profile",
|
||||||
|
|
|
@ -17,139 +17,16 @@ mod tests;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod path_transform;
|
pub mod path_transform;
|
||||||
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase};
|
use ide_db::{base_db::FileRange, RootDatabase};
|
||||||
use syntax::TextRange;
|
use syntax::TextRange;
|
||||||
|
|
||||||
pub(crate) use crate::assist_context::{AssistContext, Assists};
|
pub(crate) use crate::assist_context::{AssistContext, Assists};
|
||||||
|
|
||||||
pub use assist_config::AssistConfig;
|
pub use assist_config::AssistConfig;
|
||||||
|
pub use ide_db::assists::{
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve,
|
||||||
pub enum AssistKind {
|
};
|
||||||
// FIXME: does the None variant make sense? Probably not.
|
|
||||||
None,
|
|
||||||
|
|
||||||
QuickFix,
|
|
||||||
Generate,
|
|
||||||
Refactor,
|
|
||||||
RefactorExtract,
|
|
||||||
RefactorInline,
|
|
||||||
RefactorRewrite,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AssistKind {
|
|
||||||
pub fn contains(self, other: AssistKind) -> bool {
|
|
||||||
if self == other {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self {
|
|
||||||
AssistKind::None | AssistKind::Generate => true,
|
|
||||||
AssistKind::Refactor => match other {
|
|
||||||
AssistKind::RefactorExtract
|
|
||||||
| AssistKind::RefactorInline
|
|
||||||
| AssistKind::RefactorRewrite => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
_ => 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
|
|
||||||
/// directly.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct AssistId(pub &'static str, pub AssistKind);
|
|
||||||
|
|
||||||
/// A way to control how many asssist to resolve during the assist resolution.
|
|
||||||
/// When an assist is resolved, its edits are calculated that might be costly to always do by default.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AssistResolveStrategy {
|
|
||||||
/// No assists should be resolved.
|
|
||||||
None,
|
|
||||||
/// All assists should be resolved.
|
|
||||||
All,
|
|
||||||
/// Only a certain assist should be resolved.
|
|
||||||
Single(SingleResolve),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hold the [`AssistId`] data of a certain assist to resolve.
|
|
||||||
/// The original id object cannot be used due to a `'static` lifetime
|
|
||||||
/// and the requirement to construct this struct dynamically during the resolve handling.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SingleResolve {
|
|
||||||
/// The id of the assist.
|
|
||||||
pub assist_id: String,
|
|
||||||
// The kind of the assist.
|
|
||||||
pub assist_kind: AssistKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AssistResolveStrategy {
|
|
||||||
pub fn should_resolve(&self, id: &AssistId) -> bool {
|
|
||||||
match self {
|
|
||||||
AssistResolveStrategy::None => false,
|
|
||||||
AssistResolveStrategy::All => true,
|
|
||||||
AssistResolveStrategy::Single(single_resolve) => {
|
|
||||||
single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct GroupLabel(pub String);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Assist {
|
|
||||||
pub id: AssistId,
|
|
||||||
/// Short description of the assist, as shown in the UI.
|
|
||||||
pub label: Label,
|
|
||||||
pub group: Option<GroupLabel>,
|
|
||||||
/// Target ranges are used to sort assists: the smaller the target range,
|
|
||||||
/// the more specific assist is, and so it should be sorted first.
|
|
||||||
pub target: TextRange,
|
|
||||||
/// Computing source change sometimes is much more costly then computing the
|
|
||||||
/// other fields. Additionally, the actual change is not required to show
|
|
||||||
/// the lightbulb UI, it only is needed when the user tries to apply an
|
|
||||||
/// assist. So, we compute it lazily: the API allow requesting assists with
|
|
||||||
/// or without source change. We could (and in fact, used to) distinguish
|
|
||||||
/// between resolved and unresolved assists at the type level, but this is
|
|
||||||
/// cumbersome, especially if you want to embed an assist into another data
|
|
||||||
/// structure, such as a diagnostic.
|
|
||||||
pub source_change: Option<SourceChange>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return all the assists applicable at the given position.
|
/// Return all the assists applicable at the given position.
|
||||||
pub fn assists(
|
pub fn assists(
|
||||||
|
|
136
crates/ide_db/src/assists.rs
Normal file
136
crates/ide_db/src/assists.rs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
//! This module defines the `Assist` data structure. The actual assist live in
|
||||||
|
//! the `ide_assists` downstream crate. We want to define the data structures in
|
||||||
|
//! this low-level crate though, because `ide_diagnostics` also need them
|
||||||
|
//! (fixits for diagnostics and assists are the same thing under the hood). We
|
||||||
|
//! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so
|
||||||
|
//! we pull the common definitions upstream, to this crate.
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use syntax::TextRange;
|
||||||
|
|
||||||
|
use crate::{label::Label, source_change::SourceChange};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Assist {
|
||||||
|
pub id: AssistId,
|
||||||
|
/// Short description of the assist, as shown in the UI.
|
||||||
|
pub label: Label,
|
||||||
|
pub group: Option<GroupLabel>,
|
||||||
|
/// Target ranges are used to sort assists: the smaller the target range,
|
||||||
|
/// the more specific assist is, and so it should be sorted first.
|
||||||
|
pub target: TextRange,
|
||||||
|
/// Computing source change sometimes is much more costly then computing the
|
||||||
|
/// other fields. Additionally, the actual change is not required to show
|
||||||
|
/// the lightbulb UI, it only is needed when the user tries to apply an
|
||||||
|
/// assist. So, we compute it lazily: the API allow requesting assists with
|
||||||
|
/// or without source change. We could (and in fact, used to) distinguish
|
||||||
|
/// between resolved and unresolved assists at the type level, but this is
|
||||||
|
/// cumbersome, especially if you want to embed an assist into another data
|
||||||
|
/// structure, such as a diagnostic.
|
||||||
|
pub source_change: Option<SourceChange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum AssistKind {
|
||||||
|
// FIXME: does the None variant make sense? Probably not.
|
||||||
|
None,
|
||||||
|
|
||||||
|
QuickFix,
|
||||||
|
Generate,
|
||||||
|
Refactor,
|
||||||
|
RefactorExtract,
|
||||||
|
RefactorInline,
|
||||||
|
RefactorRewrite,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssistKind {
|
||||||
|
pub fn contains(self, other: AssistKind) -> bool {
|
||||||
|
if self == other {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
AssistKind::None | AssistKind::Generate => true,
|
||||||
|
AssistKind::Refactor => match other {
|
||||||
|
AssistKind::RefactorExtract
|
||||||
|
| AssistKind::RefactorInline
|
||||||
|
| AssistKind::RefactorRewrite => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => 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
|
||||||
|
/// directly.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct AssistId(pub &'static str, pub AssistKind);
|
||||||
|
|
||||||
|
/// A way to control how many asssist to resolve during the assist resolution.
|
||||||
|
/// When an assist is resolved, its edits are calculated that might be costly to always do by default.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AssistResolveStrategy {
|
||||||
|
/// No assists should be resolved.
|
||||||
|
None,
|
||||||
|
/// All assists should be resolved.
|
||||||
|
All,
|
||||||
|
/// Only a certain assist should be resolved.
|
||||||
|
Single(SingleResolve),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hold the [`AssistId`] data of a certain assist to resolve.
|
||||||
|
/// The original id object cannot be used due to a `'static` lifetime
|
||||||
|
/// and the requirement to construct this struct dynamically during the resolve handling.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SingleResolve {
|
||||||
|
/// The id of the assist.
|
||||||
|
pub assist_id: String,
|
||||||
|
// The kind of the assist.
|
||||||
|
pub assist_kind: AssistKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssistResolveStrategy {
|
||||||
|
pub fn should_resolve(&self, id: &AssistId) -> bool {
|
||||||
|
match self {
|
||||||
|
AssistResolveStrategy::None => false,
|
||||||
|
AssistResolveStrategy::All => true,
|
||||||
|
AssistResolveStrategy::Single(single_resolve) => {
|
||||||
|
single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct GroupLabel(pub String);
|
|
@ -3,6 +3,7 @@
|
||||||
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
|
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
|
||||||
|
|
||||||
mod apply_change;
|
mod apply_change;
|
||||||
|
pub mod assists;
|
||||||
pub mod label;
|
pub mod label;
|
||||||
pub mod line_index;
|
pub mod line_index;
|
||||||
pub mod symbol_index;
|
pub mod symbol_index;
|
||||||
|
|
|
@ -22,7 +22,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
|
||||||
cfg = { path = "../cfg", version = "0.0.0" }
|
cfg = { path = "../cfg", version = "0.0.0" }
|
||||||
hir = { path = "../hir", version = "0.0.0" }
|
hir = { path = "../hir", version = "0.0.0" }
|
||||||
ide_db = { path = "../ide_db", version = "0.0.0" }
|
ide_db = { path = "../ide_db", version = "0.0.0" }
|
||||||
ide_assists = { path = "../ide_assists", version = "0.0.0" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
expect-test = "1.1"
|
expect-test = "1.1"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use hir::{db::AstDatabase, InFile};
|
use hir::{db::AstDatabase, InFile};
|
||||||
use ide_assists::Assist;
|
use ide_db::{assists::Assist, base_db::FilePosition};
|
||||||
use ide_db::base_db::FilePosition;
|
|
||||||
use syntax::AstNode;
|
use syntax::AstNode;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -28,6 +28,7 @@ mod field_shorthand;
|
||||||
|
|
||||||
use hir::{diagnostics::AnyDiagnostic, Semantics};
|
use hir::{diagnostics::AnyDiagnostic, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
|
assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
|
||||||
base_db::{FileId, SourceDatabase},
|
base_db::{FileId, SourceDatabase},
|
||||||
label::Label,
|
label::Label,
|
||||||
source_change::SourceChange,
|
source_change::SourceChange,
|
||||||
|
@ -42,8 +43,6 @@ use syntax::{
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
use unlinked_file::UnlinkedFile;
|
use unlinked_file::UnlinkedFile;
|
||||||
|
|
||||||
use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct DiagnosticCode(pub &'static str);
|
pub struct DiagnosticCode(pub &'static str);
|
||||||
|
|
||||||
|
@ -265,8 +264,8 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::Expect;
|
use expect_test::Expect;
|
||||||
use ide_assists::AssistResolveStrategy;
|
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
|
assists::AssistResolveStrategy,
|
||||||
base_db::{fixture::WithFixture, SourceDatabaseExt},
|
base_db::{fixture::WithFixture, SourceDatabaseExt},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{db::AstDatabase, InFile};
|
use hir::{db::AstDatabase, InFile};
|
||||||
use ide_assists::Assist;
|
use ide_db::{assists::Assist, source_change::SourceChange};
|
||||||
use ide_db::source_change::SourceChange;
|
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
|
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use hir::db::AstDatabase;
|
use hir::db::AstDatabase;
|
||||||
use ide_assists::Assist;
|
use ide_db::{assists::Assist, source_change::SourceChange};
|
||||||
use ide_db::source_change::SourceChange;
|
|
||||||
use syntax::AstNode;
|
use syntax::AstNode;
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use hir::db::AstDatabase;
|
use hir::db::AstDatabase;
|
||||||
use ide_assists::Assist;
|
use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit};
|
||||||
use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit};
|
|
||||||
use syntax::AstNode;
|
use syntax::AstNode;
|
||||||
|
|
||||||
use crate::{fix, Diagnostic, DiagnosticsContext};
|
use crate::{fix, Diagnostic, DiagnosticsContext};
|
||||||
|
|
Loading…
Reference in a new issue