3034: Remove ImportLocator hack r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-02-06 16:50:01 +00:00 committed by GitHub
commit 895cdb5883
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 132 additions and 350 deletions

2
Cargo.lock generated
View file

@ -963,6 +963,7 @@ dependencies = [
"ra_db", "ra_db",
"ra_fmt", "ra_fmt",
"ra_hir", "ra_hir",
"ra_ide_db",
"ra_prof", "ra_prof",
"ra_syntax", "ra_syntax",
"ra_text_edit", "ra_text_edit",
@ -1165,7 +1166,6 @@ dependencies = [
"log", "log",
"once_cell", "once_cell",
"proptest", "proptest",
"ra_assists",
"ra_cfg", "ra_cfg",
"ra_db", "ra_db",
"ra_fmt", "ra_fmt",

View file

@ -18,5 +18,6 @@ ra_text_edit = { path = "../ra_text_edit" }
ra_fmt = { path = "../ra_fmt" } ra_fmt = { path = "../ra_fmt" }
ra_prof = { path = "../ra_prof" } ra_prof = { path = "../ra_prof" }
ra_db = { path = "../ra_db" } ra_db = { path = "../ra_db" }
ra_ide_db = { path = "../ra_ide_db" }
hir = { path = "../ra_hir", package = "ra_hir" } hir = { path = "../ra_hir", package = "ra_hir" }
test_utils = { path = "../test_utils" } test_utils = { path = "../test_utils" }

View file

@ -1,8 +1,9 @@
//! This module defines `AssistCtx` -- the API surface that is exposed to assists. //! This module defines `AssistCtx` -- the API surface that is exposed to assists.
use either::Either; use either::Either;
use hir::{db::HirDatabase, InFile, SourceAnalyzer, SourceBinder}; use hir::{InFile, SourceAnalyzer, SourceBinder};
use ra_db::FileRange; use ra_db::{FileRange, SourceDatabase};
use ra_fmt::{leading_indent, reindent}; use ra_fmt::{leading_indent, reindent};
use ra_ide_db::RootDatabase;
use ra_syntax::{ use ra_syntax::{
algo::{self, find_covering_element, find_node_at_offset}, algo::{self, find_covering_element, find_node_at_offset},
AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextUnit, AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextUnit,
@ -49,14 +50,14 @@ pub(crate) enum Assist {
/// moment, because the LSP API is pretty awkward in this place, and it's much /// moment, because the LSP API is pretty awkward in this place, and it's much
/// easier to just compute the edit eagerly :-) /// easier to just compute the edit eagerly :-)
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct AssistCtx<'a, DB> { pub(crate) struct AssistCtx<'a> {
pub(crate) db: &'a DB, pub(crate) db: &'a RootDatabase,
pub(crate) frange: FileRange, pub(crate) frange: FileRange,
source_file: SourceFile, source_file: SourceFile,
should_compute_edit: bool, should_compute_edit: bool,
} }
impl<'a, DB> Clone for AssistCtx<'a, DB> { impl<'a> Clone for AssistCtx<'a> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
AssistCtx { AssistCtx {
db: self.db, db: self.db,
@ -67,17 +68,24 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> {
} }
} }
impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { impl<'a> AssistCtx<'a> {
pub(crate) fn with_ctx<F, T>(db: &DB, frange: FileRange, should_compute_edit: bool, f: F) -> T pub(crate) fn with_ctx<F, T>(
db: &RootDatabase,
frange: FileRange,
should_compute_edit: bool,
f: F,
) -> T
where where
F: FnOnce(AssistCtx<DB>) -> T, F: FnOnce(AssistCtx) -> T,
{ {
let parse = db.parse(frange.file_id); let parse = db.parse(frange.file_id);
let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit }; let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit };
f(ctx) f(ctx)
} }
}
impl<'a> AssistCtx<'a> {
pub(crate) fn add_assist( pub(crate) fn add_assist(
self, self,
id: AssistId, id: AssistId,
@ -141,7 +149,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
pub(crate) fn covering_element(&self) -> SyntaxElement { pub(crate) fn covering_element(&self) -> SyntaxElement {
find_covering_element(self.source_file.syntax(), self.frange.range) find_covering_element(self.source_file.syntax(), self.frange.range)
} }
pub(crate) fn source_binder(&self) -> SourceBinder<'a, DB> { pub(crate) fn source_binder(&self) -> SourceBinder<'a, RootDatabase> {
SourceBinder::new(self.db) SourceBinder::new(self.db)
} }
pub(crate) fn source_analyzer( pub(crate) fn source_analyzer(

View file

@ -1,7 +1,7 @@
//! FIXME: write short doc here //! FIXME: write short doc here
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
use hir::db::HirDatabase;
use join_to_string::join; use join_to_string::join;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
@ -29,7 +29,7 @@ const DERIVE_TRAIT: &str = "derive";
// //
// } // }
// ``` // ```
pub(crate) fn add_custom_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
let input = ctx.find_node_at_offset::<ast::AttrInput>()?; let input = ctx.find_node_at_offset::<ast::AttrInput>()?;
let attr = input.syntax().parent().and_then(ast::Attr::cast)?; let attr = input.syntax().parent().and_then(ast::Attr::cast)?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, AttrsOwner}, ast::{self, AstNode, AttrsOwner},
SyntaxKind::{COMMENT, WHITESPACE}, SyntaxKind::{COMMENT, WHITESPACE},
@ -25,7 +24,7 @@ use crate::{Assist, AssistCtx, AssistId};
// y: u32, // y: u32,
// } // }
// ``` // ```
pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> {
let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
let node_start = derive_insertion_offset(&nominal)?; let node_start = derive_insertion_offset(&nominal)?;
ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", |edit| { ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", |edit| {

View file

@ -1,4 +1,4 @@
use hir::{db::HirDatabase, HirDisplay}; use hir::HirDisplay;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner}, ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner},
TextRange, TextRange,
@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
// let x: i32 = 92; // let x: i32 = 92;
// } // }
// ``` // ```
pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> {
let stmt = ctx.find_node_at_offset::<LetStmt>()?; let stmt = ctx.find_node_at_offset::<LetStmt>()?;
let expr = stmt.initializer()?; let expr = stmt.initializer()?;
let pat = stmt.pat()?; let pat = stmt.pat()?;

View file

@ -1,5 +1,5 @@
use format_buf::format; use format_buf::format;
use hir::db::HirDatabase;
use join_to_string::join; use join_to_string::join;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, NameOwner, TypeParamsOwner}, ast::{self, AstNode, NameOwner, TypeParamsOwner},
@ -27,7 +27,7 @@ use crate::{Assist, AssistCtx, AssistId};
// //
// } // }
// ``` // ```
pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
let name = nominal.name()?; let name = nominal.name()?;
ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| { ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| {

View file

@ -1,4 +1,4 @@
use hir::{self, db::HirDatabase, ModPath}; use hir::{self, ModPath};
use ra_syntax::{ use ra_syntax::{
ast::{self, NameOwner}, ast::{self, NameOwner},
AstNode, Direction, SmolStr, AstNode, Direction, SmolStr,
@ -50,7 +50,7 @@ pub fn auto_import_text_edit(
// //
// fn process(map: HashMap<String, String>) {} // fn process(map: HashMap<String, String>) {}
// ``` // ```
pub(crate) fn add_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_import(ctx: AssistCtx) -> Option<Assist> {
let path: ast::Path = ctx.find_node_at_offset()?; let path: ast::Path = ctx.find_node_at_offset()?;
// We don't want to mess with use statements // We don't want to mess with use statements
if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {

View file

@ -43,7 +43,7 @@ enum AddMissingImplMembersMode {
// //
// } // }
// ``` // ```
pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option<Assist> {
add_missing_impl_members_inner( add_missing_impl_members_inner(
ctx, ctx,
AddMissingImplMembersMode::NoDefaultMethods, AddMissingImplMembersMode::NoDefaultMethods,
@ -84,7 +84,7 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
// //
// } // }
// ``` // ```
pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option<Assist> {
add_missing_impl_members_inner( add_missing_impl_members_inner(
ctx, ctx,
AddMissingImplMembersMode::DefaultMethodsOnly, AddMissingImplMembersMode::DefaultMethodsOnly,
@ -94,7 +94,7 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> O
} }
fn add_missing_impl_members_inner( fn add_missing_impl_members_inner(
ctx: AssistCtx<impl HirDatabase>, ctx: AssistCtx,
mode: AddMissingImplMembersMode, mode: AddMissingImplMembersMode,
assist_id: &'static str, assist_id: &'static str,
label: &'static str, label: &'static str,

View file

@ -1,5 +1,5 @@
use format_buf::format; use format_buf::format;
use hir::{db::HirDatabase, InFile}; use hir::InFile;
use join_to_string::join; use join_to_string::join;
use ra_syntax::{ use ra_syntax::{
ast::{ ast::{
@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId};
// } // }
// //
// ``` // ```
pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
let strukt = ctx.find_node_at_offset::<ast::StructDef>()?; let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;
// We want to only apply this to non-union structs with named fields // We want to only apply this to non-union structs with named fields
@ -128,10 +128,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
// //
// FIXME: change the new fn checking to a more semantic approach when that's more // FIXME: change the new fn checking to a more semantic approach when that's more
// viable (e.g. we process proc macros, etc) // viable (e.g. we process proc macros, etc)
fn find_struct_impl( fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplBlock>> {
ctx: &AssistCtx<impl HirDatabase>,
strukt: &ast::StructDef,
) -> Option<Option<ast::ImplBlock>> {
let db = ctx.db; let db = ctx.db;
let module = strukt.syntax().ancestors().find(|node| { let module = strukt.syntax().ancestors().find(|node| {
ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())

View file

@ -1,5 +1,4 @@
use super::invert_if::invert_boolean_expression; use super::invert_if::invert_boolean_expression;
use hir::db::HirDatabase;
use ra_syntax::ast::{self, AstNode}; use ra_syntax::ast::{self, AstNode};
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
@ -23,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId};
// if !(x == 4 && y) {} // if !(x == 4 && y) {}
// } // }
// ``` // ```
pub(crate) fn apply_demorgan(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> {
let expr = ctx.find_node_at_offset::<ast::BinExpr>()?; let expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
let op = expr.op_kind()?; let op = expr.op_kind()?;
let op_range = expr.op_token()?.text_range(); let op_range = expr.op_token()?.text_range();

View file

@ -1,4 +1,4 @@
use hir::{db::HirDatabase, ModPath}; use hir::ModPath;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
SyntaxNode, SyntaxNode,
@ -6,8 +6,9 @@ use ra_syntax::{
use crate::{ use crate::{
assist_ctx::{ActionBuilder, Assist, AssistCtx}, assist_ctx::{ActionBuilder, Assist, AssistCtx},
auto_import_text_edit, AssistId, ImportsLocator, auto_import_text_edit, AssistId,
}; };
use ra_ide_db::imports_locator::ImportsLocatorIde;
// Assist: auto_import // Assist: auto_import
// //
@ -26,10 +27,7 @@ use crate::{
// let map = HashMap<|>::new(); // let map = HashMap<|>::new();
// } // }
// ``` // ```
pub(crate) fn auto_import<F: ImportsLocator>( pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
ctx: AssistCtx<impl HirDatabase>,
imports_locator: &mut F,
) -> Option<Assist> {
let path_to_import: ast::Path = ctx.find_node_at_offset()?; let path_to_import: ast::Path = ctx.find_node_at_offset()?;
let path_to_import_syntax = path_to_import.syntax(); let path_to_import_syntax = path_to_import.syntax();
if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() { if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() {
@ -52,6 +50,8 @@ pub(crate) fn auto_import<F: ImportsLocator>(
return None; return None;
} }
let mut imports_locator = ImportsLocatorIde::new(ctx.db);
let proposed_imports = imports_locator let proposed_imports = imports_locator
.find_imports(&name_to_import) .find_imports(&name_to_import)
.into_iter() .into_iter()
@ -81,16 +81,12 @@ fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode)
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::helpers::{ use crate::helpers::{check_assist, check_assist_not_applicable};
check_assist_with_imports_locator, check_assist_with_imports_locator_not_applicable,
TestImportsLocator,
};
#[test] #[test]
fn applicable_when_found_an_import() { fn applicable_when_found_an_import() {
check_assist_with_imports_locator( check_assist(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
<|>PubStruct <|>PubStruct
@ -112,9 +108,8 @@ mod tests {
#[test] #[test]
fn auto_imports_are_merged() { fn auto_imports_are_merged() {
check_assist_with_imports_locator( check_assist(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
use PubMod::PubStruct1; use PubMod::PubStruct1;
@ -148,9 +143,8 @@ mod tests {
#[test] #[test]
fn applicable_when_found_multiple_imports() { fn applicable_when_found_multiple_imports() {
check_assist_with_imports_locator( check_assist(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
PubSt<|>ruct PubSt<|>ruct
@ -184,9 +178,8 @@ mod tests {
#[test] #[test]
fn not_applicable_for_already_imported_types() { fn not_applicable_for_already_imported_types() {
check_assist_with_imports_locator_not_applicable( check_assist_not_applicable(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
use PubMod::PubStruct; use PubMod::PubStruct;
@ -201,9 +194,8 @@ mod tests {
#[test] #[test]
fn not_applicable_for_types_with_private_paths() { fn not_applicable_for_types_with_private_paths() {
check_assist_with_imports_locator_not_applicable( check_assist_not_applicable(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
PrivateStruct<|> PrivateStruct<|>
@ -216,9 +208,8 @@ mod tests {
#[test] #[test]
fn not_applicable_when_no_imports_found() { fn not_applicable_when_no_imports_found() {
check_assist_with_imports_locator_not_applicable( check_assist_not_applicable(
auto_import, auto_import,
TestImportsLocator::new,
" "
PubStruct<|>", PubStruct<|>",
); );
@ -226,9 +217,8 @@ mod tests {
#[test] #[test]
fn not_applicable_in_import_statements() { fn not_applicable_in_import_statements() {
check_assist_with_imports_locator_not_applicable( check_assist_not_applicable(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
use PubStruct<|>; use PubStruct<|>;
@ -240,9 +230,8 @@ mod tests {
#[test] #[test]
fn function_import() { fn function_import() {
check_assist_with_imports_locator( check_assist(
auto_import, auto_import,
TestImportsLocator::new,
r" r"
test_function<|> test_function<|>

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, NameOwner, VisibilityOwner}, ast::{self, NameOwner, VisibilityOwner},
AstNode, AstNode,
@ -22,14 +21,14 @@ use crate::{Assist, AssistCtx, AssistId};
// ``` // ```
// pub(crate) fn frobnicate() {} // pub(crate) fn frobnicate() {}
// ``` // ```
pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn change_visibility(ctx: AssistCtx) -> Option<Assist> {
if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() { if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
return change_vis(ctx, vis); return change_vis(ctx, vis);
} }
add_vis(ctx) add_vis(ctx)
} }
fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { fn add_vis(ctx: AssistCtx) -> Option<Assist> {
let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
_ => false, _ => false,
@ -75,7 +74,7 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
.unwrap_or_else(|| node.text_range().start()) .unwrap_or_else(|| node.text_range().start())
} }
fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> {
if vis.syntax().text() == "pub" { if vis.syntax().text() == "pub" {
return ctx.add_assist( return ctx.add_assist(
AssistId("change_visibility"), AssistId("change_visibility"),

View file

@ -1,6 +1,5 @@
use std::{iter::once, ops::RangeInclusive}; use std::{iter::once, ops::RangeInclusive};
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
algo::replace_children, algo::replace_children,
ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat}, ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat},
@ -36,7 +35,7 @@ use crate::{
// bar(); // bar();
// } // }
// ``` // ```
pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
if if_expr.else_branch().is_some() { if if_expr.else_branch().is_some() {
return None; return None;

View file

@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId};
// } // }
// } // }
// ``` // ```
pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
let match_arm_list = match_expr.match_arm_list()?; let match_arm_list = match_expr.match_arm_list()?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::ast::{AstNode, BinExpr, BinOp}; use ra_syntax::ast::{AstNode, BinExpr, BinOp};
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
@ -18,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
// let _ = 2 + 90; // let _ = 2 + 90;
// } // }
// ``` // ```
pub(crate) fn flip_binexpr(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> {
let expr = ctx.find_node_at_offset::<BinExpr>()?; let expr = ctx.find_node_at_offset::<BinExpr>()?;
let lhs = expr.lhs()?.syntax().clone(); let lhs = expr.lhs()?.syntax().clone();
let rhs = expr.rhs()?.syntax().clone(); let rhs = expr.rhs()?.syntax().clone();

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{algo::non_trivia_sibling, Direction, T}; use ra_syntax::{algo::non_trivia_sibling, Direction, T};
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
@ -18,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
// ((3, 4), (1, 2)); // ((3, 4), (1, 2));
// } // }
// ``` // ```
pub(crate) fn flip_comma(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> {
let comma = ctx.find_token_at_offset(T![,])?; let comma = ctx.find_token_at_offset(T![,])?;
let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
algo::non_trivia_sibling, algo::non_trivia_sibling,
ast::{self, AstNode}, ast::{self, AstNode},
@ -18,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
// ``` // ```
// fn foo<T: Copy + Clone>() { } // fn foo<T: Copy + Clone>() { }
// ``` // ```
pub(crate) fn flip_trait_bound(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> {
// We want to replicate the behavior of `flip_binexpr` by only suggesting // We want to replicate the behavior of `flip_binexpr` by only suggesting
// the assist when the cursor is on a `+` // the assist when the cursor is on a `+`
let plus = ctx.find_token_at_offset(T![+])?; let plus = ctx.find_token_at_offset(T![+])?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, AstToken}, ast::{self, AstNode, AstToken},
TextRange, TextRange,
@ -23,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId};
// (1 + 2) * 4; // (1 + 2) * 4;
// } // }
// ``` // ```
pub(crate) fn inline_local_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
let bind_pat = match let_stmt.pat()? { let bind_pat = match let_stmt.pat()? {
ast::Pat::BindPat(pat) => pat, ast::Pat::BindPat(pat) => pat,

View file

@ -1,5 +1,4 @@
use format_buf::format; use format_buf::format;
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
SyntaxKind::{ SyntaxKind::{
@ -28,7 +27,7 @@ use crate::{Assist, AssistCtx, AssistId};
// var_name * 4; // var_name * 4;
// } // }
// ``` // ```
pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
if ctx.frange.range.is_empty() { if ctx.frange.range.is_empty() {
return None; return None;
} }

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::ast::{self, AstNode}; use ra_syntax::ast::{self, AstNode};
use ra_syntax::T; use ra_syntax::T;
@ -23,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId};
// } // }
// ``` // ```
pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
let if_keyword = ctx.find_token_at_offset(T![if])?; let if_keyword = ctx.find_token_at_offset(T![if])?;
let expr = ast::IfExpr::cast(if_keyword.parent())?; let expr = ast::IfExpr::cast(if_keyword.parent())?;
let if_range = if_keyword.text_range(); let if_range = if_keyword.text_range();

View file

@ -1,6 +1,5 @@
use std::iter::successors; use std::iter::successors;
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
Direction, TextUnit, Direction, TextUnit,
@ -32,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId, TextRange};
// } // }
// } // }
// ``` // ```
pub(crate) fn merge_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?; let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?;
// Don't try to handle arms with guards for now - can add support for this later // Don't try to handle arms with guards for now - can add support for this later
if current_arm.guard().is_some() { if current_arm.guard().is_some() {

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner}, ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner},
SyntaxElement, SyntaxElement,
@ -22,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
// f(x) // f(x)
// } // }
// ``` // ```
pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> {
let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?;
let mut type_params = type_param_list.type_params(); let mut type_params = type_param_list.type_params();

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast, ast,
ast::{AstNode, AstToken, IfExpr, MatchArm}, ast::{AstNode, AstToken, IfExpr, MatchArm},
@ -32,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId};
// } // }
// } // }
// ``` // ```
pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
let match_arm = ctx.find_node_at_offset::<MatchArm>()?; let match_arm = ctx.find_node_at_offset::<MatchArm>()?;
let guard = match_arm.guard()?; let guard = match_arm.guard()?;
let space_before_guard = guard.syntax().prev_sibling_or_token(); let space_before_guard = guard.syntax().prev_sibling_or_token();
@ -89,7 +88,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx<impl HirDatabase>) -> Option
// } // }
// } // }
// ``` // ```
pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
let last_match_pat = match_arm.pats().last()?; let last_match_pat = match_arm.pats().last()?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast, AstToken, ast, AstToken,
SyntaxKind::{RAW_STRING, STRING}, SyntaxKind::{RAW_STRING, STRING},
@ -22,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
// r#"Hello, World!"#; // r#"Hello, World!"#;
// } // }
// ``` // ```
pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> {
let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
let value = token.value()?; let value = token.value()?;
ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", |edit| { ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", |edit| {
@ -51,7 +50,7 @@ pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
// "Hello, \"World!\""; // "Hello, \"World!\"";
// } // }
// ``` // ```
pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> {
let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
let value = token.value()?; let value = token.value()?;
ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", |edit| { ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", |edit| {
@ -77,7 +76,7 @@ pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
// r##"Hello, World!"##; // r##"Hello, World!"##;
// } // }
// ``` // ```
pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> {
let token = ctx.find_token_at_offset(RAW_STRING)?; let token = ctx.find_token_at_offset(RAW_STRING)?;
ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| { ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| {
edit.target(token.text_range()); edit.target(token.text_range());
@ -101,7 +100,7 @@ pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
// r"Hello, World!"; // r"Hello, World!";
// } // }
// ``` // ```
pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> {
let token = ctx.find_token_at_offset(RAW_STRING)?; let token = ctx.find_token_at_offset(RAW_STRING)?;
let text = token.text().as_str(); let text = token.text().as_str();
if text.starts_with("r\"") { if text.starts_with("r\"") {

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
TextUnit, T, TextUnit, T,
@ -21,7 +20,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 92; // 92;
// } // }
// ``` // ```
pub(crate) fn remove_dbg(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> {
let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
if !is_valid_macrocall(&macro_call, "dbg")? { if !is_valid_macrocall(&macro_call, "dbg")? {

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_fmt::unwrap_trivial_block; use ra_fmt::unwrap_trivial_block;
use ra_syntax::{ use ra_syntax::{
ast::{self, make}, ast::{self, make},
@ -34,7 +33,7 @@ use ast::edit::IndentLevel;
// } // }
// } // }
// ``` // ```
pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
let cond = if_expr.condition()?; let cond = if_expr.condition()?;
let pat = cond.pat()?; let pat = cond.pat()?;

View file

@ -1,6 +1,5 @@
use std::iter::successors; use std::iter::successors;
use hir::db::HirDatabase;
use ra_syntax::{ast, AstNode, TextUnit, T}; use ra_syntax::{ast, AstNode, TextUnit, T};
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
@ -16,7 +15,7 @@ use crate::{Assist, AssistCtx, AssistId};
// ``` // ```
// use std::{collections::HashMap}; // use std::{collections::HashMap};
// ``` // ```
pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> {
let colon_colon = ctx.find_token_at_offset(T![::])?; let colon_colon = ctx.find_token_at_offset(T![::])?;
let path = ast::Path::cast(colon_colon.parent())?; let path = ast::Path::cast(colon_colon.parent())?;
let top_path = successors(Some(path), |it| it.parent_path()).last()?; let top_path = successors(Some(path), |it| it.parent_path()).last()?;

View file

@ -8,7 +8,7 @@ mod generated;
use ra_db::{fixture::WithFixture, FileRange}; use ra_db::{fixture::WithFixture, FileRange};
use test_utils::{assert_eq_text, extract_range_or_offset}; use test_utils::{assert_eq_text, extract_range_or_offset};
use crate::test_db::TestDB; use ra_ide_db::RootDatabase;
fn check(assist_id: &str, before: &str, after: &str) { fn check(assist_id: &str, before: &str, after: &str) {
// FIXME we cannot get the imports search functionality here yet, but still need to generate a test and a doc for an assist // FIXME we cannot get the imports search functionality here yet, but still need to generate a test and a doc for an assist
@ -16,7 +16,7 @@ fn check(assist_id: &str, before: &str, after: &str) {
return; return;
} }
let (selection, before) = extract_range_or_offset(before); let (selection, before) = extract_range_or_offset(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = RootDatabase::with_single_file(&before);
let frange = FileRange { file_id, range: selection.into() }; let frange = FileRange { file_id, range: selection.into() };
let assist = crate::assists(&db, frange) let assist = crate::assists(&db, frange)

View file

@ -9,13 +9,11 @@ mod assist_ctx;
mod marks; mod marks;
#[cfg(test)] #[cfg(test)]
mod doc_tests; mod doc_tests;
#[cfg(test)]
mod test_db;
pub mod ast_transform; pub mod ast_transform;
use either::Either; use either::Either;
use hir::{db::HirDatabase, ModuleDef};
use ra_db::FileRange; use ra_db::FileRange;
use ra_ide_db::RootDatabase;
use ra_syntax::{TextRange, TextUnit}; use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::TextEdit; use ra_text_edit::TextEdit;
@ -61,10 +59,7 @@ impl ResolvedAssist {
/// ///
/// Assists are returned in the "unresolved" state, that is only labels are /// Assists are returned in the "unresolved" state, that is only labels are
/// returned, without actual edits. /// returned, without actual edits.
pub fn applicable_assists<H>(db: &H, range: FileRange) -> Vec<AssistLabel> pub fn applicable_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> {
where
H: HirDatabase + 'static,
{
AssistCtx::with_ctx(db, range, false, |ctx| { AssistCtx::with_ctx(db, range, false, |ctx| {
assists::all() assists::all()
.iter() .iter()
@ -77,59 +72,11 @@ where
}) })
} }
/// A functionality for locating imports for the given name.
///
/// Currently has to be a trait with the real implementation provided by the ra_ide_api crate,
/// due to the search functionality located there.
/// Later, this trait should be removed completely and the search functionality moved to a separate crate,
/// accessible from the ra_assists crate.
pub trait ImportsLocator {
/// Finds all imports for the given name and the module that contains this name.
fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef>;
}
/// Return all the assists applicable at the given position
/// and additional assists that need the imports locator functionality to work.
///
/// Assists are returned in the "resolved" state, that is with edit fully
/// computed.
pub fn assists_with_imports_locator<H, F>(
db: &H,
range: FileRange,
mut imports_locator: F,
) -> Vec<ResolvedAssist>
where
H: HirDatabase + 'static,
F: ImportsLocator,
{
AssistCtx::with_ctx(db, range, true, |ctx| {
let mut assists = assists::all()
.iter()
.map(|f| f(ctx.clone()))
.chain(
assists::all_with_imports_locator()
.iter()
.map(|f| f(ctx.clone(), &mut imports_locator)),
)
.filter_map(std::convert::identity)
.map(|a| match a {
Assist::Resolved { assist } => assist,
Assist::Unresolved { .. } => unreachable!(),
})
.collect();
sort_assists(&mut assists);
assists
})
}
/// Return all the assists applicable at the given position. /// Return all the assists applicable at the given position.
/// ///
/// Assists are returned in the "resolved" state, that is with edit fully /// Assists are returned in the "resolved" state, that is with edit fully
/// computed. /// computed.
pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist> pub fn assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
where
H: HirDatabase + 'static,
{
AssistCtx::with_ctx(db, range, true, |ctx| { AssistCtx::with_ctx(db, range, true, |ctx| {
let mut a = assists::all() let mut a = assists::all()
.iter() .iter()
@ -155,8 +102,7 @@ fn sort_assists(assists: &mut Vec<ResolvedAssist>) {
} }
mod assists { mod assists {
use crate::{Assist, AssistCtx, ImportsLocator}; use crate::{Assist, AssistCtx};
use hir::db::HirDatabase;
mod add_derive; mod add_derive;
mod add_explicit_type; mod add_explicit_type;
@ -184,7 +130,7 @@ mod assists {
mod move_bounds; mod move_bounds;
mod early_return; mod early_return;
pub(crate) fn all<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { pub(crate) fn all() -> &'static [fn(AssistCtx) -> Option<Assist>] {
&[ &[
add_derive::add_derive, add_derive::add_derive,
add_explicit_type::add_explicit_type, add_explicit_type::add_explicit_type,
@ -215,79 +161,34 @@ mod assists {
raw_string::make_usual_string, raw_string::make_usual_string,
raw_string::remove_hash, raw_string::remove_hash,
early_return::convert_to_guarded_return, early_return::convert_to_guarded_return,
auto_import::auto_import,
] ]
} }
pub(crate) fn all_with_imports_locator<'a, DB: HirDatabase, F: ImportsLocator>(
) -> &'a [fn(AssistCtx<DB>, &mut F) -> Option<Assist>] {
&[auto_import::auto_import]
}
} }
#[cfg(test)] #[cfg(test)]
mod helpers { mod helpers {
use hir::db::DefDatabase; use std::sync::Arc;
use ra_db::{fixture::WithFixture, FileId, FileRange};
use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
use ra_syntax::TextRange; use ra_syntax::TextRange;
use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
use crate::{test_db::TestDB, Assist, AssistCtx, ImportsLocator}; use crate::{Assist, AssistCtx};
use std::sync::Arc;
// FIXME remove the `ModuleDefId` reexport from `ra_hir` when this gets removed. pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
pub(crate) struct TestImportsLocator { let (mut db, file_id) = RootDatabase::with_single_file(text);
db: Arc<TestDB>, // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`,
test_file_id: FileId, // but it looks like this might need specialization? :(
let local_roots = vec![db.file_source_root(file_id)];
db.set_local_roots(Arc::new(local_roots));
(db, file_id)
} }
impl TestImportsLocator { pub(crate) fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) {
pub(crate) fn new(db: Arc<TestDB>, test_file_id: FileId) -> Self {
TestImportsLocator { db, test_file_id }
}
}
impl ImportsLocator for TestImportsLocator {
fn find_imports(&mut self, name_to_import: &str) -> Vec<hir::ModuleDef> {
let crate_def_map = self.db.crate_def_map(self.db.test_crate());
let mut findings = Vec::new();
let mut module_ids_to_process =
crate_def_map.modules_for_file(self.test_file_id).collect::<Vec<_>>();
while !module_ids_to_process.is_empty() {
let mut more_ids_to_process = Vec::new();
for local_module_id in module_ids_to_process.drain(..) {
for (name, namespace_data) in
crate_def_map[local_module_id].scope.entries_without_primitives()
{
let found_a_match = &name.to_string() == name_to_import;
vec![namespace_data.types, namespace_data.values]
.into_iter()
.filter_map(std::convert::identity)
.for_each(|(module_def_id, _)| {
if found_a_match {
findings.push(module_def_id.into());
}
if let hir::ModuleDefId::ModuleId(module_id) = module_def_id {
more_ids_to_process.push(module_id.local_id);
}
});
}
}
module_ids_to_process = more_ids_to_process;
}
findings
}
}
pub(crate) fn check_assist(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
before: &str,
after: &str,
) {
let (before_cursor_pos, before) = extract_offset(before); let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = with_single_file(&before);
let frange = let frange =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist = let assist =
@ -309,45 +210,13 @@ mod helpers {
assert_eq_text!(after, &actual); assert_eq_text!(after, &actual);
} }
pub(crate) fn check_assist_with_imports_locator<F: ImportsLocator>(
assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>,
imports_locator_provider: fn(db: Arc<TestDB>, file_id: FileId) -> F,
before: &str,
after: &str,
) {
let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = TestDB::with_single_file(&before);
let db = Arc::new(db);
let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id);
let frange =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist =
AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator))
.expect("code action is not applicable");
let action = match assist {
Assist::Unresolved { .. } => unreachable!(),
Assist::Resolved { assist } => assist.get_first_action(),
};
let actual = action.edit.apply(&before);
let actual_cursor_pos = match action.cursor_position {
None => action
.edit
.apply_to_offset(before_cursor_pos)
.expect("cursor position is affected by the edit"),
Some(off) => off,
};
let actual = add_cursor(&actual, actual_cursor_pos);
assert_eq_text!(after, &actual);
}
pub(crate) fn check_assist_range( pub(crate) fn check_assist_range(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>, assist: fn(AssistCtx) -> Option<Assist>,
before: &str, before: &str,
after: &str, after: &str,
) { ) {
let (range, before) = extract_range(before); let (range, before) = extract_range(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range }; let frange = FileRange { file_id, range };
let assist = let assist =
AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
@ -364,12 +233,12 @@ mod helpers {
} }
pub(crate) fn check_assist_target( pub(crate) fn check_assist_target(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>, assist: fn(AssistCtx) -> Option<Assist>,
before: &str, before: &str,
target: &str, target: &str,
) { ) {
let (before_cursor_pos, before) = extract_offset(before); let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = with_single_file(&before);
let frange = let frange =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist = let assist =
@ -384,12 +253,12 @@ mod helpers {
} }
pub(crate) fn check_assist_range_target( pub(crate) fn check_assist_range_target(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>, assist: fn(AssistCtx) -> Option<Assist>,
before: &str, before: &str,
target: &str, target: &str,
) { ) {
let (range, before) = extract_range(before); let (range, before) = extract_range(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range }; let frange = FileRange { file_id, range };
let assist = let assist =
AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
@ -403,39 +272,23 @@ mod helpers {
} }
pub(crate) fn check_assist_not_applicable( pub(crate) fn check_assist_not_applicable(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>, assist: fn(AssistCtx) -> Option<Assist>,
before: &str, before: &str,
) { ) {
let (before_cursor_pos, before) = extract_offset(before); let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = with_single_file(&before);
let frange = let frange =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist = AssistCtx::with_ctx(&db, frange, true, assist); let assist = AssistCtx::with_ctx(&db, frange, true, assist);
assert!(assist.is_none()); assert!(assist.is_none());
} }
pub(crate) fn check_assist_with_imports_locator_not_applicable<F: ImportsLocator>(
assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>,
imports_locator_provider: fn(db: Arc<TestDB>, file_id: FileId) -> F,
before: &str,
) {
let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = TestDB::with_single_file(&before);
let db = Arc::new(db);
let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id);
let frange =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist =
AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator));
assert!(assist.is_none());
}
pub(crate) fn check_assist_range_not_applicable( pub(crate) fn check_assist_range_not_applicable(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>, assist: fn(AssistCtx) -> Option<Assist>,
before: &str, before: &str,
) { ) {
let (range, before) = extract_range(before); let (range, before) = extract_range(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = with_single_file(&before);
let frange = FileRange { file_id, range }; let frange = FileRange { file_id, range };
let assist = AssistCtx::with_ctx(&db, frange, true, assist); let assist = AssistCtx::with_ctx(&db, frange, true, assist);
assert!(assist.is_none()); assert!(assist.is_none());
@ -444,17 +297,17 @@ mod helpers {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ra_db::{fixture::WithFixture, FileRange}; use ra_db::FileRange;
use ra_syntax::TextRange; use ra_syntax::TextRange;
use test_utils::{extract_offset, extract_range}; use test_utils::{extract_offset, extract_range};
use crate::test_db::TestDB; use crate::helpers;
#[test] #[test]
fn assist_order_field_struct() { fn assist_order_field_struct() {
let before = "struct Foo { <|>bar: u32 }"; let before = "struct Foo { <|>bar: u32 }";
let (before_cursor_pos, before) = extract_offset(before); let (before_cursor_pos, before) = extract_offset(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = helpers::with_single_file(&before);
let frange = let frange =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assists = super::assists(&db, frange); let assists = super::assists(&db, frange);
@ -478,7 +331,7 @@ mod tests {
} }
}"; }";
let (range, before) = extract_range(before); let (range, before) = extract_range(before);
let (db, file_id) = TestDB::with_single_file(&before); let (db, file_id) = helpers::with_single_file(&before);
let frange = FileRange { file_id, range }; let frange = FileRange { file_id, range };
let assists = super::assists(&db, frange); let assists = super::assists(&db, frange);
let mut assists = assists.iter(); let mut assists = assists.iter();

View file

@ -1,45 +0,0 @@
//! Database used for testing `ra_assists`.
use std::sync::Arc;
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
#[salsa::database(
ra_db::SourceDatabaseExtStorage,
ra_db::SourceDatabaseStorage,
hir::db::InternDatabaseStorage,
hir::db::AstDatabaseStorage,
hir::db::DefDatabaseStorage,
hir::db::HirDatabaseStorage
)]
#[derive(Debug, Default)]
pub struct TestDB {
runtime: salsa::Runtime<TestDB>,
}
impl salsa::Database for TestDB {
fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
&self.runtime
}
fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
&mut self.runtime
}
}
impl std::panic::RefUnwindSafe for TestDB {}
impl FileLoader for TestDB {
fn file_text(&self, file_id: FileId) -> Arc<String> {
FileLoaderDelegate(self).file_text(file_id)
}
fn resolve_relative_path(
&self,
anchor: FileId,
relative_path: &RelativePath,
) -> Option<FileId> {
FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
}
fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
FileLoaderDelegate(self).relevant_crates(file_id)
}
}

View file

@ -3,7 +3,7 @@
use either::Either; use either::Either;
use ra_assists::{AssistAction, AssistLabel}; use ra_assists::{AssistAction, AssistLabel};
use ra_db::{FilePosition, FileRange}; use ra_db::{FilePosition, FileRange};
use ra_ide_db::{imports_locator::ImportsLocatorIde, RootDatabase}; use ra_ide_db::RootDatabase;
use crate::{FileId, SourceChange, SourceFileEdit}; use crate::{FileId, SourceChange, SourceFileEdit};
@ -17,7 +17,7 @@ pub struct Assist {
} }
pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
ra_assists::assists_with_imports_locator(db, frange, ImportsLocatorIde::new(db)) ra_assists::assists(db, frange)
.into_iter() .into_iter()
.map(|assist| { .map(|assist| {
let file_id = frange.file_id; let file_id = frange.file_id;

View file

@ -32,7 +32,6 @@ ra_cfg = { path = "../ra_cfg" }
ra_fmt = { path = "../ra_fmt" } ra_fmt = { path = "../ra_fmt" }
ra_prof = { path = "../ra_prof" } ra_prof = { path = "../ra_prof" }
test_utils = { path = "../test_utils" } test_utils = { path = "../test_utils" }
ra_assists = { path = "../ra_assists" }
# ra_ide should depend only on the top-level `hir` package. if you need # ra_ide should depend only on the top-level `hir` package. if you need
# something from some `hir_xxx` subpackage, reexport the API via `hir`. # something from some `hir_xxx` subpackage, reexport the API via `hir`.

View file

@ -92,7 +92,7 @@ pub fn classify_name(
ast::FnDef(it) => { ast::FnDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def: hir::Function = sb.to_def(src)?; let def: hir::Function = sb.to_def(src)?;
if parent.parent().and_then(ast::ItemList::cast).is_some() { if parent.parent().and_then(ast::ItemList::cast).map_or(false, |it| it.syntax().parent().and_then(ast::Module::cast).is_none()) {
Some(from_assoc_item(sb.db, def.into())) Some(from_assoc_item(sb.db, def.into()))
} else { } else {
Some(from_module_def(sb.db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))

View file

@ -2,7 +2,6 @@
//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.
use hir::{db::HirDatabase, ModuleDef, SourceBinder}; use hir::{db::HirDatabase, ModuleDef, SourceBinder};
use ra_assists::ImportsLocator;
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
@ -22,29 +21,7 @@ impl<'a> ImportsLocatorIde<'a> {
Self { source_binder: SourceBinder::new(db) } Self { source_binder: SourceBinder::new(db) }
} }
fn get_name_definition( pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
&mut self,
db: &impl HirDatabase,
import_candidate: &FileSymbol,
) -> Option<NameKind> {
let _p = profile("get_name_definition");
let file_id = import_candidate.file_id.into();
let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
let candidate_name_node = if candidate_node.kind() != NAME {
candidate_node.children().find(|it| it.kind() == NAME)?
} else {
candidate_node
};
classify_name(
&mut self.source_binder,
hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
)
.map(|it| it.kind)
}
}
impl ImportsLocator for ImportsLocatorIde<'_> {
fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
let _p = profile("search_for_imports"); let _p = profile("search_for_imports");
let db = self.source_binder.db; let db = self.source_binder.db;
@ -72,4 +49,24 @@ impl ImportsLocator for ImportsLocatorIde<'_> {
}) })
.collect() .collect()
} }
fn get_name_definition(
&mut self,
db: &impl HirDatabase,
import_candidate: &FileSymbol,
) -> Option<NameKind> {
let _p = profile("get_name_definition");
let file_id = import_candidate.file_id.into();
let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
let candidate_name_node = if candidate_node.kind() != NAME {
candidate_node.children().find(|it| it.kind() == NAME)?
} else {
candidate_node
};
classify_name(
&mut self.source_binder,
hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
)
.map(|it| it.kind)
}
} }