diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 40 | ||||
-rw-r--r-- | crates/ide/src/fn_references.rs | 5 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 19 |
3 files changed, 38 insertions, 26 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 1c7f02763..3df73ed4f 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -10,7 +10,7 @@ mod field_shorthand; | |||
10 | use std::cell::RefCell; | 10 | use std::cell::RefCell; |
11 | 11 | ||
12 | use hir::{ | 12 | use hir::{ |
13 | diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, | 13 | diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder}, |
14 | Semantics, | 14 | Semantics, |
15 | }; | 15 | }; |
16 | use ide_db::base_db::SourceDatabase; | 16 | use ide_db::base_db::SourceDatabase; |
@@ -35,15 +35,23 @@ pub struct Diagnostic { | |||
35 | pub severity: Severity, | 35 | pub severity: Severity, |
36 | pub fix: Option<Fix>, | 36 | pub fix: Option<Fix>, |
37 | pub unused: bool, | 37 | pub unused: bool, |
38 | pub code: Option<DiagnosticCode>, | ||
38 | } | 39 | } |
39 | 40 | ||
40 | impl Diagnostic { | 41 | impl Diagnostic { |
41 | fn error(range: TextRange, message: String) -> Self { | 42 | fn error(range: TextRange, message: String) -> Self { |
42 | Self { message, range, severity: Severity::Error, fix: None, unused: false } | 43 | Self { message, range, severity: Severity::Error, fix: None, unused: false, code: None } |
43 | } | 44 | } |
44 | 45 | ||
45 | fn hint(range: TextRange, message: String) -> Self { | 46 | fn hint(range: TextRange, message: String) -> Self { |
46 | Self { message, range, severity: Severity::WeakWarning, fix: None, unused: false } | 47 | Self { |
48 | message, | ||
49 | range, | ||
50 | severity: Severity::WeakWarning, | ||
51 | fix: None, | ||
52 | unused: false, | ||
53 | code: None, | ||
54 | } | ||
47 | } | 55 | } |
48 | 56 | ||
49 | fn with_fix(self, fix: Option<Fix>) -> Self { | 57 | fn with_fix(self, fix: Option<Fix>) -> Self { |
@@ -53,6 +61,10 @@ impl Diagnostic { | |||
53 | fn with_unused(self, unused: bool) -> Self { | 61 | fn with_unused(self, unused: bool) -> Self { |
54 | Self { unused, ..self } | 62 | Self { unused, ..self } |
55 | } | 63 | } |
64 | |||
65 | fn with_code(self, code: Option<DiagnosticCode>) -> Self { | ||
66 | Self { code, ..self } | ||
67 | } | ||
56 | } | 68 | } |
57 | 69 | ||
58 | #[derive(Debug)] | 70 | #[derive(Debug)] |
@@ -126,7 +138,8 @@ pub(crate) fn diagnostics( | |||
126 | // Override severity and mark as unused. | 138 | // Override severity and mark as unused. |
127 | res.borrow_mut().push( | 139 | res.borrow_mut().push( |
128 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) | 140 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) |
129 | .with_unused(true), | 141 | .with_unused(true) |
142 | .with_code(Some(d.code())), | ||
130 | ); | 143 | ); |
131 | }) | 144 | }) |
132 | // Only collect experimental diagnostics when they're enabled. | 145 | // Only collect experimental diagnostics when they're enabled. |
@@ -137,8 +150,10 @@ pub(crate) fn diagnostics( | |||
137 | let mut sink = sink_builder | 150 | let mut sink = sink_builder |
138 | // Diagnostics not handled above get no fix and default treatment. | 151 | // Diagnostics not handled above get no fix and default treatment. |
139 | .build(|d| { | 152 | .build(|d| { |
140 | res.borrow_mut() | 153 | res.borrow_mut().push( |
141 | .push(Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())); | 154 | Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()) |
155 | .with_code(Some(d.code())), | ||
156 | ); | ||
142 | }); | 157 | }); |
143 | 158 | ||
144 | if let Some(m) = sema.to_module_def(file_id) { | 159 | if let Some(m) = sema.to_module_def(file_id) { |
@@ -149,11 +164,15 @@ pub(crate) fn diagnostics( | |||
149 | } | 164 | } |
150 | 165 | ||
151 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 166 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { |
152 | Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema)) | 167 | Diagnostic::error(sema.diagnostics_display_range(d).range, d.message()) |
168 | .with_fix(d.fix(&sema)) | ||
169 | .with_code(Some(d.code())) | ||
153 | } | 170 | } |
154 | 171 | ||
155 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 172 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { |
156 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()).with_fix(d.fix(&sema)) | 173 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) |
174 | .with_fix(d.fix(&sema)) | ||
175 | .with_code(Some(d.code())) | ||
157 | } | 176 | } |
158 | 177 | ||
159 | fn check_unnecessary_braces_in_use_statement( | 178 | fn check_unnecessary_braces_in_use_statement( |
@@ -589,6 +608,11 @@ fn test_fn() { | |||
589 | }, | 608 | }, |
590 | ), | 609 | ), |
591 | unused: false, | 610 | unused: false, |
611 | code: Some( | ||
612 | DiagnosticCode( | ||
613 | "unresolved-module", | ||
614 | ), | ||
615 | ), | ||
592 | }, | 616 | }, |
593 | ] | 617 | ] |
594 | "#]], | 618 | "#]], |
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 | ||
4 | use assists::utils::test_related_attribute; | ||
4 | use hir::Semantics; | 5 | use hir::Semantics; |
5 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
6 | use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode}; | 7 | use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode}; |
7 | 8 | ||
8 | use crate::{runnables::has_test_related_attribute, FileId, FileRange}; | 9 | use crate::{FileId, FileRange}; |
9 | 10 | ||
10 | pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> { | 11 | pub(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 | ||
16 | fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> { | 17 | fn 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 @@ | |||
1 | use std::fmt; | 1 | use std::fmt; |
2 | 2 | ||
3 | use assists::utils::test_related_attribute; | ||
3 | use cfg::CfgExpr; | 4 | use cfg::CfgExpr; |
4 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; | 5 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; |
5 | use ide_db::RootDatabase; | 6 | use 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. | ||
244 | pub(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 | |||
252 | const RUSTDOC_FENCE: &str = "```"; | 239 | const RUSTDOC_FENCE: &str = "```"; |
253 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 240 | const 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 | } |