aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-11-17 13:22:04 +0000
committerAleksey Kladov <[email protected]>2020-11-17 13:22:04 +0000
commit9a30707281d3a978741a549196b71a27284f7240 (patch)
tree3cf3a7bc4d7ef9a327418279354a68c2472db1af /crates
parent10e3a9879c8714320f9a0729d647da7877f0a753 (diff)
Add **Ignore Test** assist
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/ignore_test.rs34
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests/generated.rs20
-rw-r--r--crates/assists/src/utils.rs18
-rw-r--r--crates/ide/src/fn_references.rs5
-rw-r--r--crates/ide/src/runnables.rs19
6 files changed, 80 insertions, 18 deletions
diff --git a/crates/assists/src/handlers/ignore_test.rs b/crates/assists/src/handlers/ignore_test.rs
new file mode 100644
index 000000000..d2339184f
--- /dev/null
+++ b/crates/assists/src/handlers/ignore_test.rs
@@ -0,0 +1,34 @@
1use syntax::{ast, AstNode};
2
3use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists};
4
5// Assist: ignore_test
6//
7// Adds `#[ignore]` attribute to the test.
8//
9// ```
10// <|>#[test]
11// fn arithmetics {
12// assert_eq!(2 + 2, 5);
13// }
14// ```
15// ->
16// ```
17// #[test]
18// #[ignore]
19// fn arithmetics {
20// assert_eq!(2 + 2, 5);
21// }
22// ```
23pub(crate) fn ignore_test(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let attr: ast::Attr = ctx.find_node_at_offset()?;
25 let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
26 let attr = test_related_attribute(&func)?;
27
28 acc.add(
29 AssistId("ignore_test", AssistKind::None),
30 "Ignore this test",
31 attr.syntax().text_range(),
32 |builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")),
33 )
34}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index e8d81b33d..17e9312db 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -141,6 +141,7 @@ mod handlers {
141 mod generate_function; 141 mod generate_function;
142 mod generate_impl; 142 mod generate_impl;
143 mod generate_new; 143 mod generate_new;
144 mod ignore_test;
144 mod infer_function_return_type; 145 mod infer_function_return_type;
145 mod inline_local_variable; 146 mod inline_local_variable;
146 mod introduce_named_lifetime; 147 mod introduce_named_lifetime;
@@ -189,6 +190,7 @@ mod handlers {
189 generate_function::generate_function, 190 generate_function::generate_function,
190 generate_impl::generate_impl, 191 generate_impl::generate_impl,
191 generate_new::generate_new, 192 generate_new::generate_new,
193 ignore_test::ignore_test,
192 infer_function_return_type::infer_function_return_type, 194 infer_function_return_type::infer_function_return_type,
193 inline_local_variable::inline_local_variable, 195 inline_local_variable::inline_local_variable,
194 introduce_named_lifetime::introduce_named_lifetime, 196 introduce_named_lifetime::introduce_named_lifetime,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index dbf4f21aa..5a9d1a01b 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -474,6 +474,26 @@ impl<T: Clone> Ctx<T> {
474} 474}
475 475
476#[test] 476#[test]
477fn doctest_ignore_test() {
478 check_doc_test(
479 "ignore_test",
480 r#####"
481<|>#[test]
482fn arithmetics {
483 assert_eq!(2 + 2, 5);
484}
485"#####,
486 r#####"
487#[test]
488#[ignore]
489fn arithmetics {
490 assert_eq!(2 + 2, 5);
491}
492"#####,
493 )
494}
495
496#[test]
477fn doctest_infer_function_return_type() { 497fn doctest_infer_function_return_type() {
478 check_doc_test( 498 check_doc_test(
479 "infer_function_return_type", 499 "infer_function_return_type",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 7bd338e99..d1a0a99b1 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -9,6 +9,7 @@ use ide_db::RootDatabase;
9use itertools::Itertools; 9use itertools::Itertools;
10use syntax::{ 10use syntax::{
11 ast::edit::AstNodeEdit, 11 ast::edit::AstNodeEdit,
12 ast::AttrsOwner,
12 ast::NameOwner, 13 ast::NameOwner,
13 ast::{self, edit, make, ArgListOwner}, 14 ast::{self, edit, make, ArgListOwner},
14 AstNode, Direction, 15 AstNode, Direction,
@@ -82,6 +83,23 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
82 None 83 None
83} 84}
84 85
86/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
87/// `#[test_case(...)]`, `#[tokio::test]` and similar.
88/// Also a regular `#[test]` annotation is supported.
89///
90/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
91/// but it's better than not to have the runnables for the tests at all.
92pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
93 fn_def.attrs().find_map(|attr| {
94 let path = attr.path()?;
95 if path.syntax().text().to_string().contains("test") {
96 Some(attr)
97 } else {
98 None
99 }
100 })
101}
102
85#[derive(Copy, Clone, PartialEq)] 103#[derive(Copy, Clone, PartialEq)]
86pub enum DefaultMethods { 104pub enum DefaultMethods {
87 Only, 105 Only,
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs
index 459f201ed..5cbbe306e 100644
--- a/crates/ide/src/fn_references.rs
+++ b/crates/ide/src/fn_references.rs
@@ -1,11 +1,12 @@
1//! This module implements a methods and free functions search in the specified file. 1//! This module implements a methods and free functions search in the specified file.
2//! We have to skip tests, so cannot reuse file_structure module. 2//! We have to skip tests, so cannot reuse file_structure module.
3 3
4use assists::utils::test_related_attribute;
4use hir::Semantics; 5use hir::Semantics;
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
6use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode}; 7use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};
7 8
8use crate::{runnables::has_test_related_attribute, FileId, FileRange}; 9use crate::{FileId, FileRange};
9 10
10pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> { 11pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> {
11 let sema = Semantics::new(db); 12 let sema = Semantics::new(db);
@@ -15,7 +16,7 @@ pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRa
15 16
16fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> { 17fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> {
17 ast::Fn::cast(item).and_then(|fn_def| { 18 ast::Fn::cast(item).and_then(|fn_def| {
18 if has_test_related_attribute(&fn_def) { 19 if test_related_attribute(&fn_def).is_some() {
19 None 20 None
20 } else { 21 } else {
21 fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() }) 22 fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() })
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 2bd0e86e5..e15411777 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -1,5 +1,6 @@
1use std::fmt; 1use std::fmt;
2 2
3use assists::utils::test_related_attribute;
3use cfg::CfgExpr; 4use cfg::CfgExpr;
4use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; 5use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics};
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
@@ -156,7 +157,7 @@ fn runnable_fn(
156 None => TestId::Name(name_string), 157 None => TestId::Name(name_string),
157 }; 158 };
158 159
159 if has_test_related_attribute(&fn_def) { 160 if test_related_attribute(&fn_def).is_some() {
160 let attr = TestAttr::from_fn(&fn_def); 161 let attr = TestAttr::from_fn(&fn_def);
161 RunnableKind::Test { test_id, attr } 162 RunnableKind::Test { test_id, attr }
162 } else if fn_def.has_atom_attr("bench") { 163 } else if fn_def.has_atom_attr("bench") {
@@ -235,20 +236,6 @@ impl TestAttr {
235 } 236 }
236} 237}
237 238
238/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
239/// `#[test_case(...)]`, `#[tokio::test]` and similar.
240/// Also a regular `#[test]` annotation is supported.
241///
242/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
243/// but it's better than not to have the runnables for the tests at all.
244pub(crate) fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
245 fn_def
246 .attrs()
247 .filter_map(|attr| attr.path())
248 .map(|path| path.syntax().to_string().to_lowercase())
249 .any(|attribute_text| attribute_text.contains("test"))
250}
251
252const RUSTDOC_FENCE: &str = "```"; 239const RUSTDOC_FENCE: &str = "```";
253const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = 240const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
254 &["", "rust", "should_panic", "edition2015", "edition2018"]; 241 &["", "rust", "should_panic", "edition2015", "edition2018"];
@@ -307,7 +294,7 @@ fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
307 for item in item_list.items() { 294 for item in item_list.items() {
308 match item { 295 match item {
309 ast::Item::Fn(f) => { 296 ast::Item::Fn(f) => {
310 if has_test_related_attribute(&f) { 297 if test_related_attribute(&f).is_some() {
311 return true; 298 return true;
312 } 299 }
313 } 300 }