internal: cut deps between assists and diagnostics

This commit is contained in:
Aleksey Kladov 2021-06-14 13:27:11 +03:00
parent 2e8dab631b
commit a91071b57b
10 changed files with 147 additions and 140 deletions

1
Cargo.lock generated
View file

@ -678,7 +678,6 @@ dependencies = [
"either",
"expect-test",
"hir",
"ide_assists",
"ide_db",
"itertools",
"profile",

View file

@ -17,139 +17,16 @@ mod tests;
pub mod utils;
pub mod path_transform;
use std::str::FromStr;
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;
pub(crate) use crate::assist_context::{AssistContext, Assists};
pub use assist_config::AssistConfig;
#[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);
#[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>,
}
pub use ide_db::assists::{
Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve,
};
/// Return all the assists applicable at the given position.
pub fn assists(

View 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);

View file

@ -3,6 +3,7 @@
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
mod apply_change;
pub mod assists;
pub mod label;
pub mod line_index;
pub mod symbol_index;

View file

@ -22,7 +22,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
cfg = { path = "../cfg", version = "0.0.0" }
hir = { path = "../hir", version = "0.0.0" }
ide_db = { path = "../ide_db", version = "0.0.0" }
ide_assists = { path = "../ide_assists", version = "0.0.0" }
[dev-dependencies]
expect-test = "1.1"

View file

@ -1,6 +1,5 @@
use hir::{db::AstDatabase, InFile};
use ide_assists::Assist;
use ide_db::base_db::FilePosition;
use ide_db::{assists::Assist, base_db::FilePosition};
use syntax::AstNode;
use crate::{

View file

@ -28,6 +28,7 @@ mod field_shorthand;
use hir::{diagnostics::AnyDiagnostic, Semantics};
use ide_db::{
assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
base_db::{FileId, SourceDatabase},
label::Label,
source_change::SourceChange,
@ -42,8 +43,6 @@ use syntax::{
use text_edit::TextEdit;
use unlinked_file::UnlinkedFile;
use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DiagnosticCode(pub &'static str);
@ -265,8 +264,8 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
#[cfg(test)]
mod tests {
use expect_test::Expect;
use ide_assists::AssistResolveStrategy;
use ide_db::{
assists::AssistResolveStrategy,
base_db::{fixture::WithFixture, SourceDatabaseExt},
RootDatabase,
};

View file

@ -1,7 +1,6 @@
use either::Either;
use hir::{db::AstDatabase, InFile};
use ide_assists::Assist;
use ide_db::source_change::SourceChange;
use ide_db::{assists::Assist, source_change::SourceChange};
use stdx::format_to;
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
use text_edit::TextEdit;

View file

@ -1,6 +1,5 @@
use hir::db::AstDatabase;
use ide_assists::Assist;
use ide_db::source_change::SourceChange;
use ide_db::{assists::Assist, source_change::SourceChange};
use syntax::AstNode;
use text_edit::TextEdit;

View file

@ -1,6 +1,5 @@
use hir::db::AstDatabase;
use ide_assists::Assist;
use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit};
use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit};
use syntax::AstNode;
use crate::{fix, Diagnostic, DiagnosticsContext};