2020-05-06 03:21:35 -05:00
|
|
|
mod generated;
|
|
|
|
|
2020-05-06 03:16:55 -05:00
|
|
|
use hir::Semantics;
|
|
|
|
use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
|
2020-06-11 04:04:09 -05:00
|
|
|
use ra_ide_db::RootDatabase;
|
2020-05-06 03:16:55 -05:00
|
|
|
use ra_syntax::TextRange;
|
2020-06-23 17:48:38 -05:00
|
|
|
use test_utils::{assert_eq_text, extract_offset, extract_range};
|
2020-05-06 03:16:55 -05:00
|
|
|
|
2020-07-13 16:41:47 -05:00
|
|
|
use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists};
|
2020-06-23 17:30:34 -05:00
|
|
|
use stdx::trim_indent;
|
2020-05-06 03:16:55 -05:00
|
|
|
|
|
|
|
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
|
2020-06-11 04:04:09 -05:00
|
|
|
RootDatabase::with_single_file(text)
|
2020-05-06 03:16:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) {
|
2020-06-23 17:30:34 -05:00
|
|
|
let ra_fixture_after = trim_indent(ra_fixture_after);
|
|
|
|
check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after));
|
2020-05-06 03:16:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: instead of having a separate function here, maybe use
|
|
|
|
// `extract_ranges` and mark the target as `<target> </target>` in the
|
|
|
|
// fixuture?
|
|
|
|
pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) {
|
|
|
|
check(assist, ra_fixture, ExpectedResult::Target(target));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) {
|
|
|
|
check(assist, ra_fixture, ExpectedResult::NotApplicable);
|
|
|
|
}
|
|
|
|
|
2020-05-06 03:18:12 -05:00
|
|
|
fn check_doc_test(assist_id: &str, before: &str, after: &str) {
|
2020-06-23 17:48:38 -05:00
|
|
|
let after = trim_indent(after);
|
|
|
|
let (db, file_id, selection) = RootDatabase::with_range_or_offset(&before);
|
|
|
|
let before = db.file_text(file_id).to_string();
|
2020-05-06 03:18:12 -05:00
|
|
|
let frange = FileRange { file_id, range: selection.into() };
|
|
|
|
|
2020-07-15 08:45:30 -05:00
|
|
|
let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange)
|
2020-05-06 03:18:12 -05:00
|
|
|
.into_iter()
|
2020-05-07 10:09:59 -05:00
|
|
|
.find(|assist| assist.assist.id.0 == assist_id)
|
2020-05-06 03:18:12 -05:00
|
|
|
.unwrap_or_else(|| {
|
|
|
|
panic!(
|
|
|
|
"\n\nAssist is not applicable: {}\nAvailable assists: {}",
|
|
|
|
assist_id,
|
2020-07-15 08:45:30 -05:00
|
|
|
Assist::resolved(&db, &AssistConfig::default(), frange)
|
2020-05-06 03:18:12 -05:00
|
|
|
.into_iter()
|
2020-05-07 10:09:59 -05:00
|
|
|
.map(|assist| assist.assist.id.0)
|
2020-05-06 03:18:12 -05:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
let actual = {
|
2020-05-06 09:01:47 -05:00
|
|
|
let change = assist.source_change.source_file_edits.pop().unwrap();
|
2020-06-23 17:48:38 -05:00
|
|
|
let mut actual = before;
|
2020-05-06 08:26:40 -05:00
|
|
|
change.edit.apply(&mut actual);
|
2020-05-06 03:18:12 -05:00
|
|
|
actual
|
|
|
|
};
|
2020-06-23 17:48:38 -05:00
|
|
|
assert_eq_text!(&after, &actual);
|
2020-05-06 03:18:12 -05:00
|
|
|
}
|
|
|
|
|
2020-05-06 03:16:55 -05:00
|
|
|
enum ExpectedResult<'a> {
|
|
|
|
NotApplicable,
|
|
|
|
After(&'a str),
|
|
|
|
Target(&'a str),
|
|
|
|
}
|
|
|
|
|
2020-05-06 11:45:35 -05:00
|
|
|
fn check(handler: Handler, before: &str, expected: ExpectedResult) {
|
2020-06-23 17:30:34 -05:00
|
|
|
let (db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
|
2020-06-23 17:48:38 -05:00
|
|
|
let text_without_caret = db.file_text(file_with_caret_id).to_string();
|
2020-05-06 03:16:55 -05:00
|
|
|
|
|
|
|
let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
|
|
|
|
|
|
|
|
let sema = Semantics::new(&db);
|
2020-05-17 05:09:53 -05:00
|
|
|
let config = AssistConfig::default();
|
2020-07-15 08:45:30 -05:00
|
|
|
let ctx = AssistContext::new(sema, &config, frange);
|
2020-05-06 11:45:35 -05:00
|
|
|
let mut acc = Assists::new_resolved(&ctx);
|
|
|
|
handler(&mut acc, &ctx);
|
|
|
|
let mut res = acc.finish_resolved();
|
|
|
|
let assist = res.pop();
|
|
|
|
match (assist, expected) {
|
2020-05-06 03:16:55 -05:00
|
|
|
(Some(assist), ExpectedResult::After(after)) => {
|
2020-05-06 11:45:35 -05:00
|
|
|
let mut source_change = assist.source_change;
|
|
|
|
let change = source_change.source_file_edits.pop().unwrap();
|
2020-05-06 03:16:55 -05:00
|
|
|
|
2020-05-06 08:26:40 -05:00
|
|
|
let mut actual = db.file_text(change.file_id).as_ref().to_owned();
|
|
|
|
change.edit.apply(&mut actual);
|
2020-05-06 03:16:55 -05:00
|
|
|
assert_eq_text!(after, &actual);
|
|
|
|
}
|
|
|
|
(Some(assist), ExpectedResult::Target(target)) => {
|
2020-05-07 10:09:59 -05:00
|
|
|
let range = assist.assist.target;
|
2020-05-06 03:16:55 -05:00
|
|
|
assert_eq_text!(&text_without_caret[range], target);
|
|
|
|
}
|
|
|
|
(Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
|
|
|
|
(None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => {
|
|
|
|
panic!("code action is not applicable")
|
|
|
|
}
|
|
|
|
(None, ExpectedResult::NotApplicable) => (),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn assist_order_field_struct() {
|
|
|
|
let before = "struct Foo { <|>bar: u32 }";
|
|
|
|
let (before_cursor_pos, before) = extract_offset(before);
|
|
|
|
let (db, file_id) = with_single_file(&before);
|
|
|
|
let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
|
2020-07-15 08:45:30 -05:00
|
|
|
let assists = Assist::resolved(&db, &AssistConfig::default(), frange);
|
2020-05-06 03:16:55 -05:00
|
|
|
let mut assists = assists.iter();
|
|
|
|
|
|
|
|
assert_eq!(
|
2020-05-07 10:09:59 -05:00
|
|
|
assists.next().expect("expected assist").assist.label,
|
2020-05-06 03:16:55 -05:00
|
|
|
"Change visibility to pub(crate)"
|
|
|
|
);
|
2020-05-07 10:09:59 -05:00
|
|
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Add `#[derive]`");
|
2020-05-06 03:16:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn assist_order_if_expr() {
|
|
|
|
let before = "
|
|
|
|
pub fn test_some_range(a: int) -> bool {
|
|
|
|
if let 2..6 = <|>5<|> {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}";
|
|
|
|
let (range, before) = extract_range(before);
|
|
|
|
let (db, file_id) = with_single_file(&before);
|
|
|
|
let frange = FileRange { file_id, range };
|
2020-07-15 08:45:30 -05:00
|
|
|
let assists = Assist::resolved(&db, &AssistConfig::default(), frange);
|
2020-05-06 03:16:55 -05:00
|
|
|
let mut assists = assists.iter();
|
|
|
|
|
2020-05-07 10:09:59 -05:00
|
|
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
|
|
|
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match");
|
2020-05-06 03:16:55 -05:00
|
|
|
}
|
2020-07-13 16:41:47 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn assist_filter_works() {
|
|
|
|
let before = "
|
|
|
|
pub fn test_some_range(a: int) -> bool {
|
|
|
|
if let 2..6 = <|>5<|> {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}";
|
|
|
|
let (range, before) = extract_range(before);
|
|
|
|
let (db, file_id) = with_single_file(&before);
|
|
|
|
let frange = FileRange { file_id, range };
|
|
|
|
|
|
|
|
{
|
2020-07-15 08:45:30 -05:00
|
|
|
let mut cfg = AssistConfig::default();
|
|
|
|
cfg.allowed = Some(vec![AssistKind::Refactor]);
|
2020-07-13 16:41:47 -05:00
|
|
|
|
2020-07-15 08:45:30 -05:00
|
|
|
let assists = Assist::resolved(&db, &cfg, frange);
|
2020-07-13 16:41:47 -05:00
|
|
|
let mut assists = assists.iter();
|
|
|
|
|
|
|
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
|
|
|
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-07-15 08:45:30 -05:00
|
|
|
let mut cfg = AssistConfig::default();
|
|
|
|
cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
|
|
|
|
let assists = Assist::resolved(&db, &cfg, frange);
|
2020-07-13 16:41:47 -05:00
|
|
|
assert_eq!(assists.len(), 1);
|
|
|
|
|
|
|
|
let mut assists = assists.iter();
|
|
|
|
assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-07-15 08:45:30 -05:00
|
|
|
let mut cfg = AssistConfig::default();
|
|
|
|
cfg.allowed = Some(vec![AssistKind::QuickFix]);
|
|
|
|
let assists = Assist::resolved(&db, &cfg, frange);
|
2020-07-13 16:41:47 -05:00
|
|
|
assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out");
|
|
|
|
}
|
|
|
|
}
|