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_fmt",
"ra_hir",
"ra_ide_db",
"ra_prof",
"ra_syntax",
"ra_text_edit",
@ -1165,7 +1166,6 @@ dependencies = [
"log",
"once_cell",
"proptest",
"ra_assists",
"ra_cfg",
"ra_db",
"ra_fmt",

View file

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

View file

@ -1,8 +1,9 @@
//! This module defines `AssistCtx` -- the API surface that is exposed to assists.
use either::Either;
use hir::{db::HirDatabase, InFile, SourceAnalyzer, SourceBinder};
use ra_db::FileRange;
use hir::{InFile, SourceAnalyzer, SourceBinder};
use ra_db::{FileRange, SourceDatabase};
use ra_fmt::{leading_indent, reindent};
use ra_ide_db::RootDatabase;
use ra_syntax::{
algo::{self, find_covering_element, find_node_at_offset},
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
/// easier to just compute the edit eagerly :-)
#[derive(Debug)]
pub(crate) struct AssistCtx<'a, DB> {
pub(crate) db: &'a DB,
pub(crate) struct AssistCtx<'a> {
pub(crate) db: &'a RootDatabase,
pub(crate) frange: FileRange,
source_file: SourceFile,
should_compute_edit: bool,
}
impl<'a, DB> Clone for AssistCtx<'a, DB> {
impl<'a> Clone for AssistCtx<'a> {
fn clone(&self) -> Self {
AssistCtx {
db: self.db,
@ -67,17 +68,24 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> {
}
}
impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
pub(crate) fn with_ctx<F, T>(db: &DB, frange: FileRange, should_compute_edit: bool, f: F) -> T
impl<'a> AssistCtx<'a> {
pub(crate) fn with_ctx<F, T>(
db: &RootDatabase,
frange: FileRange,
should_compute_edit: bool,
f: F,
) -> T
where
F: FnOnce(AssistCtx<DB>) -> T,
F: FnOnce(AssistCtx) -> T,
{
let parse = db.parse(frange.file_id);
let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit };
f(ctx)
}
}
impl<'a> AssistCtx<'a> {
pub(crate) fn add_assist(
self,
id: AssistId,
@ -141,7 +149,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
pub(crate) fn covering_element(&self) -> SyntaxElement {
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)
}
pub(crate) fn source_analyzer(

View file

@ -1,7 +1,7 @@
//! FIXME: write short doc here
use crate::{Assist, AssistCtx, AssistId};
use hir::db::HirDatabase;
use join_to_string::join;
use ra_syntax::{
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 attr = input.syntax().parent().and_then(ast::Attr::cast)?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, AstNode, AttrsOwner},
SyntaxKind::{COMMENT, WHITESPACE},
@ -25,7 +24,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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 node_start = derive_insertion_offset(&nominal)?;
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::{
ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner},
TextRange,
@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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 expr = stmt.initializer()?;
let pat = stmt.pat()?;

View file

@ -1,5 +1,5 @@
use format_buf::format;
use hir::db::HirDatabase;
use join_to_string::join;
use ra_syntax::{
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 name = nominal.name()?;
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::{
ast::{self, NameOwner},
AstNode, Direction, SmolStr,
@ -50,7 +50,7 @@ pub fn auto_import_text_edit(
//
// 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()?;
// We don't want to mess with use statements
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(
ctx,
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(
ctx,
AddMissingImplMembersMode::DefaultMethodsOnly,
@ -94,7 +94,7 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> O
}
fn add_missing_impl_members_inner(
ctx: AssistCtx<impl HirDatabase>,
ctx: AssistCtx,
mode: AddMissingImplMembersMode,
assist_id: &'static str,
label: &'static str,

View file

@ -1,5 +1,5 @@
use format_buf::format;
use hir::{db::HirDatabase, InFile};
use hir::InFile;
use join_to_string::join;
use ra_syntax::{
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>()?;
// 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
// viable (e.g. we process proc macros, etc)
fn find_struct_impl(
ctx: &AssistCtx<impl HirDatabase>,
strukt: &ast::StructDef,
) -> Option<Option<ast::ImplBlock>> {
fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplBlock>> {
let db = ctx.db;
let module = strukt.syntax().ancestors().find(|node| {
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 hir::db::HirDatabase;
use ra_syntax::ast::{self, AstNode};
use crate::{Assist, AssistCtx, AssistId};
@ -23,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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 op = expr.op_kind()?;
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::{
ast::{self, AstNode},
SyntaxNode,
@ -6,8 +6,9 @@ use ra_syntax::{
use crate::{
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
//
@ -26,10 +27,7 @@ use crate::{
// let map = HashMap<|>::new();
// }
// ```
pub(crate) fn auto_import<F: ImportsLocator>(
ctx: AssistCtx<impl HirDatabase>,
imports_locator: &mut F,
) -> Option<Assist> {
pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
let path_to_import: ast::Path = ctx.find_node_at_offset()?;
let path_to_import_syntax = path_to_import.syntax();
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;
}
let mut imports_locator = ImportsLocatorIde::new(ctx.db);
let proposed_imports = imports_locator
.find_imports(&name_to_import)
.into_iter()
@ -81,16 +81,12 @@ fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode)
#[cfg(test)]
mod tests {
use super::*;
use crate::helpers::{
check_assist_with_imports_locator, check_assist_with_imports_locator_not_applicable,
TestImportsLocator,
};
use crate::helpers::{check_assist, check_assist_not_applicable};
#[test]
fn applicable_when_found_an_import() {
check_assist_with_imports_locator(
check_assist(
auto_import,
TestImportsLocator::new,
r"
<|>PubStruct
@ -112,9 +108,8 @@ mod tests {
#[test]
fn auto_imports_are_merged() {
check_assist_with_imports_locator(
check_assist(
auto_import,
TestImportsLocator::new,
r"
use PubMod::PubStruct1;
@ -148,9 +143,8 @@ mod tests {
#[test]
fn applicable_when_found_multiple_imports() {
check_assist_with_imports_locator(
check_assist(
auto_import,
TestImportsLocator::new,
r"
PubSt<|>ruct
@ -184,9 +178,8 @@ mod tests {
#[test]
fn not_applicable_for_already_imported_types() {
check_assist_with_imports_locator_not_applicable(
check_assist_not_applicable(
auto_import,
TestImportsLocator::new,
r"
use PubMod::PubStruct;
@ -201,9 +194,8 @@ mod tests {
#[test]
fn not_applicable_for_types_with_private_paths() {
check_assist_with_imports_locator_not_applicable(
check_assist_not_applicable(
auto_import,
TestImportsLocator::new,
r"
PrivateStruct<|>
@ -216,9 +208,8 @@ mod tests {
#[test]
fn not_applicable_when_no_imports_found() {
check_assist_with_imports_locator_not_applicable(
check_assist_not_applicable(
auto_import,
TestImportsLocator::new,
"
PubStruct<|>",
);
@ -226,9 +217,8 @@ mod tests {
#[test]
fn not_applicable_in_import_statements() {
check_assist_with_imports_locator_not_applicable(
check_assist_not_applicable(
auto_import,
TestImportsLocator::new,
r"
use PubStruct<|>;
@ -240,9 +230,8 @@ mod tests {
#[test]
fn function_import() {
check_assist_with_imports_locator(
check_assist(
auto_import,
TestImportsLocator::new,
r"
test_function<|>

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, NameOwner, VisibilityOwner},
AstNode,
@ -22,14 +21,14 @@ use crate::{Assist, AssistCtx, AssistId};
// ```
// 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>() {
return change_vis(ctx, vis);
}
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() {
T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
_ => false,
@ -75,7 +74,7 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
.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" {
return ctx.add_assist(
AssistId("change_visibility"),

View file

@ -1,6 +1,5 @@
use std::{iter::once, ops::RangeInclusive};
use hir::db::HirDatabase;
use ra_syntax::{
algo::replace_children,
ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat},
@ -36,7 +35,7 @@ use crate::{
// 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()?;
if if_expr.else_branch().is_some() {
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_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 crate::{Assist, AssistCtx, AssistId};
@ -18,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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 lhs = expr.lhs()?.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 crate::{Assist, AssistCtx, AssistId};
@ -18,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
// ((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 prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
algo::non_trivia_sibling,
ast::{self, AstNode},
@ -18,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
// ```
// 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
// the assist when the cursor is on a `+`
let plus = ctx.find_token_at_offset(T![+])?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, AstNode, AstToken},
TextRange,
@ -23,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId};
// (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 bind_pat = match let_stmt.pat()? {
ast::Pat::BindPat(pat) => pat,

View file

@ -1,5 +1,4 @@
use format_buf::format;
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, AstNode},
SyntaxKind::{
@ -28,7 +27,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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() {
return None;
}

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::ast::{self, AstNode};
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 expr = ast::IfExpr::cast(if_keyword.parent())?;
let if_range = if_keyword.text_range();

View file

@ -1,6 +1,5 @@
use std::iter::successors;
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, AstNode},
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>()?;
// Don't try to handle arms with guards for now - can add support for this later
if current_arm.guard().is_some() {

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner},
SyntaxElement,
@ -22,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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 mut type_params = type_param_list.type_params();

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast,
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 guard = match_arm.guard()?;
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 last_match_pat = match_arm.pats().last()?;

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast, AstToken,
SyntaxKind::{RAW_STRING, STRING},
@ -22,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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 value = token.value()?;
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!\"";
// }
// ```
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 value = token.value()?;
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!"##;
// }
// ```
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)?;
ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| {
edit.target(token.text_range());
@ -101,7 +100,7 @@ pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
// 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 text = token.text().as_str();
if text.starts_with("r\"") {

View file

@ -1,4 +1,3 @@
use hir::db::HirDatabase;
use ra_syntax::{
ast::{self, AstNode},
TextUnit, T,
@ -21,7 +20,7 @@ use crate::{Assist, AssistCtx, AssistId};
// 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>()?;
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_syntax::{
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 cond = if_expr.condition()?;
let pat = cond.pat()?;

View file

@ -1,6 +1,5 @@
use std::iter::successors;
use hir::db::HirDatabase;
use ra_syntax::{ast, AstNode, TextUnit, T};
use crate::{Assist, AssistCtx, AssistId};
@ -16,7 +15,7 @@ use crate::{Assist, AssistCtx, AssistId};
// ```
// 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 path = ast::Path::cast(colon_colon.parent())?;
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 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) {
// 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;
}
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 assist = crate::assists(&db, frange)

View file

@ -9,13 +9,11 @@ mod assist_ctx;
mod marks;
#[cfg(test)]
mod doc_tests;
#[cfg(test)]
mod test_db;
pub mod ast_transform;
use either::Either;
use hir::{db::HirDatabase, ModuleDef};
use ra_db::FileRange;
use ra_ide_db::RootDatabase;
use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::TextEdit;
@ -61,10 +59,7 @@ impl ResolvedAssist {
///
/// Assists are returned in the "unresolved" state, that is only labels are
/// returned, without actual edits.
pub fn applicable_assists<H>(db: &H, range: FileRange) -> Vec<AssistLabel>
where
H: HirDatabase + 'static,
{
pub fn applicable_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> {
AssistCtx::with_ctx(db, range, false, |ctx| {
assists::all()
.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.
///
/// Assists are returned in the "resolved" state, that is with edit fully
/// computed.
pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist>
where
H: HirDatabase + 'static,
{
pub fn assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> {
AssistCtx::with_ctx(db, range, true, |ctx| {
let mut a = assists::all()
.iter()
@ -155,8 +102,7 @@ fn sort_assists(assists: &mut Vec<ResolvedAssist>) {
}
mod assists {
use crate::{Assist, AssistCtx, ImportsLocator};
use hir::db::HirDatabase;
use crate::{Assist, AssistCtx};
mod add_derive;
mod add_explicit_type;
@ -184,7 +130,7 @@ mod assists {
mod move_bounds;
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_explicit_type::add_explicit_type,
@ -215,79 +161,34 @@ mod assists {
raw_string::make_usual_string,
raw_string::remove_hash,
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)]
mod helpers {
use hir::db::DefDatabase;
use ra_db::{fixture::WithFixture, FileId, FileRange};
use std::sync::Arc;
use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
use ra_syntax::TextRange;
use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
use crate::{test_db::TestDB, Assist, AssistCtx, ImportsLocator};
use std::sync::Arc;
use crate::{Assist, AssistCtx};
// FIXME remove the `ModuleDefId` reexport from `ra_hir` when this gets removed.
pub(crate) struct TestImportsLocator {
db: Arc<TestDB>,
test_file_id: FileId,
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
let (mut db, file_id) = RootDatabase::with_single_file(text);
// FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`,
// 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 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,
) {
pub(crate) fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) {
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 =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist =
@ -309,45 +210,13 @@ mod helpers {
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(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
assist: fn(AssistCtx) -> Option<Assist>,
before: &str,
after: &str,
) {
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 assist =
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(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
assist: fn(AssistCtx) -> Option<Assist>,
before: &str,
target: &str,
) {
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 =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist =
@ -384,12 +253,12 @@ mod helpers {
}
pub(crate) fn check_assist_range_target(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
assist: fn(AssistCtx) -> Option<Assist>,
before: &str,
target: &str,
) {
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 assist =
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(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
assist: fn(AssistCtx) -> Option<Assist>,
before: &str,
) {
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 =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assist = AssistCtx::with_ctx(&db, frange, true, assist);
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(
assist: fn(AssistCtx<TestDB>) -> Option<Assist>,
assist: fn(AssistCtx) -> Option<Assist>,
before: &str,
) {
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 assist = AssistCtx::with_ctx(&db, frange, true, assist);
assert!(assist.is_none());
@ -444,17 +297,17 @@ mod helpers {
#[cfg(test)]
mod tests {
use ra_db::{fixture::WithFixture, FileRange};
use ra_db::FileRange;
use ra_syntax::TextRange;
use test_utils::{extract_offset, extract_range};
use crate::test_db::TestDB;
use crate::helpers;
#[test]
fn assist_order_field_struct() {
let before = "struct Foo { <|>bar: u32 }";
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 =
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
let assists = super::assists(&db, frange);
@ -478,7 +331,7 @@ mod tests {
}
}";
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 assists = super::assists(&db, frange);
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 ra_assists::{AssistAction, AssistLabel};
use ra_db::{FilePosition, FileRange};
use ra_ide_db::{imports_locator::ImportsLocatorIde, RootDatabase};
use ra_ide_db::RootDatabase;
use crate::{FileId, SourceChange, SourceFileEdit};
@ -17,7 +17,7 @@ pub struct 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()
.map(|assist| {
let file_id = frange.file_id;

View file

@ -32,7 +32,6 @@ ra_cfg = { path = "../ra_cfg" }
ra_fmt = { path = "../ra_fmt" }
ra_prof = { path = "../ra_prof" }
test_utils = { path = "../test_utils" }
ra_assists = { path = "../ra_assists" }
# 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`.

View file

@ -92,7 +92,7 @@ pub fn classify_name(
ast::FnDef(it) => {
let src = name.with_value(it);
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()))
} else {
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.
use hir::{db::HirDatabase, ModuleDef, SourceBinder};
use ra_assists::ImportsLocator;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
@ -22,29 +21,7 @@ impl<'a> ImportsLocatorIde<'a> {
Self { source_binder: SourceBinder::new(db) }
}
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)
}
}
impl ImportsLocator for ImportsLocatorIde<'_> {
fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
let _p = profile("search_for_imports");
let db = self.source_binder.db;
@ -72,4 +49,24 @@ impl ImportsLocator for ImportsLocatorIde<'_> {
})
.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)
}
}