aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/diagnostics.rs40
-rw-r--r--crates/ide/src/fn_references.rs5
-rw-r--r--crates/ide/src/runnables.rs19
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;
10use std::cell::RefCell; 10use std::cell::RefCell;
11 11
12use hir::{ 12use hir::{
13 diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, 13 diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
14 Semantics, 14 Semantics,
15}; 15};
16use ide_db::base_db::SourceDatabase; 16use 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
40impl Diagnostic { 41impl 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
151fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { 166fn 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
155fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { 172fn 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
159fn check_unnecessary_braces_in_use_statement( 178fn 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
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 }