aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-06-13 19:09:03 +0100
committerAleksey Kladov <[email protected]>2021-06-13 19:09:03 +0100
commitfc30c5ccbeba2a102922da497809dd3f812544c4 (patch)
treeed3067580e998f04e94bfb93508fe3f12c851c3b
parent2ad78924621420cb323efdeb3d875ca3f47d940f (diff)
internal: refactor incorrect case diagnostics
-rw-r--r--crates/hir/src/diagnostics.rs29
-rw-r--r--crates/hir/src/lib.rs18
-rw-r--r--crates/hir_ty/src/diagnostics.rs3
-rw-r--r--crates/ide/src/diagnostics.rs16
-rw-r--r--crates/ide/src/diagnostics/fixes.rs1
-rw-r--r--crates/ide/src/diagnostics/incorrect_case.rs (renamed from crates/ide/src/diagnostics/fixes/change_case.rs)61
6 files changed, 49 insertions, 79 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index c294a803b..c2d608eb5 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -34,6 +34,7 @@ macro_rules! diagnostics {
34diagnostics![ 34diagnostics![
35 BreakOutsideOfLoop, 35 BreakOutsideOfLoop,
36 InactiveCode, 36 InactiveCode,
37 IncorrectCase,
37 MacroError, 38 MacroError,
38 MismatchedArgCount, 39 MismatchedArgCount,
39 MissingFields, 40 MissingFields,
@@ -195,31 +196,3 @@ impl Diagnostic for InternalBailedOut {
195} 196}
196 197
197pub use hir_ty::diagnostics::IncorrectCase; 198pub use hir_ty::diagnostics::IncorrectCase;
198
199impl Diagnostic for IncorrectCase {
200 fn code(&self) -> DiagnosticCode {
201 DiagnosticCode("incorrect-ident-case")
202 }
203
204 fn message(&self) -> String {
205 format!(
206 "{} `{}` should have {} name, e.g. `{}`",
207 self.ident_type,
208 self.ident_text,
209 self.expected_case.to_string(),
210 self.suggested_text
211 )
212 }
213
214 fn display_source(&self) -> InFile<SyntaxNodePtr> {
215 InFile::new(self.file, self.ident.clone().into())
216 }
217
218 fn as_any(&self) -> &(dyn Any + Send + 'static) {
219 self
220 }
221
222 fn is_experimental(&self) -> bool {
223 true
224 }
225}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b2731b62f..fc147ade3 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -86,8 +86,8 @@ use crate::{
86pub use crate::{ 86pub use crate::{
87 attrs::{HasAttrs, Namespace}, 87 attrs::{HasAttrs, Namespace},
88 diagnostics::{ 88 diagnostics::{
89 AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, 89 AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InternalBailedOut,
90 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 90 MacroError, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
91 MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, 91 MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
92 UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, 92 UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
93 UnresolvedModule, UnresolvedProcMacro, 93 UnresolvedModule, UnresolvedProcMacro,
@@ -340,7 +340,7 @@ impl ModuleDef {
340 } 340 }
341 } 341 }
342 342
343 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 343 pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
344 let id = match self { 344 let id = match self {
345 ModuleDef::Adt(it) => match it { 345 ModuleDef::Adt(it) => match it {
346 Adt::Struct(it) => it.id.into(), 346 Adt::Struct(it) => it.id.into(),
@@ -353,17 +353,19 @@ impl ModuleDef {
353 ModuleDef::Module(it) => it.id.into(), 353 ModuleDef::Module(it) => it.id.into(),
354 ModuleDef::Const(it) => it.id.into(), 354 ModuleDef::Const(it) => it.id.into(),
355 ModuleDef::Static(it) => it.id.into(), 355 ModuleDef::Static(it) => it.id.into(),
356 _ => return, 356 _ => return Vec::new(),
357 }; 357 };
358 358
359 let module = match self.module(db) { 359 let module = match self.module(db) {
360 Some(it) => it, 360 Some(it) => it,
361 None => return, 361 None => return Vec::new(),
362 }; 362 };
363 363
364 let mut acc = Vec::new();
364 for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) { 365 for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) {
365 sink.push(diag) 366 acc.push(diag.into())
366 } 367 }
368 acc
367 } 369 }
368} 370}
369 371
@@ -624,7 +626,7 @@ impl Module {
624 acc.extend(m.diagnostics(db, sink, internal_diagnostics)) 626 acc.extend(m.diagnostics(db, sink, internal_diagnostics))
625 } 627 }
626 } 628 }
627 _ => decl.diagnostics(db, sink), 629 _ => acc.extend(decl.diagnostics(db)),
628 } 630 }
629 } 631 }
630 632
@@ -1234,7 +1236,7 @@ impl Function {
1234 } 1236 }
1235 1237
1236 for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) { 1238 for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) {
1237 sink.push(diag) 1239 acc.push(diag.into())
1238 } 1240 }
1239 acc 1241 acc
1240 } 1242 }
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 407273943..6339c9687 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -84,9 +84,6 @@ impl fmt::Display for IdentType {
84 } 84 }
85} 85}
86 86
87// Diagnostic: incorrect-ident-case
88//
89// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
90#[derive(Debug)] 87#[derive(Debug)]
91pub struct IncorrectCase { 88pub struct IncorrectCase {
92 pub file: HirFileId, 89 pub file: HirFileId,
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 814e64ae4..f084f7b06 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -6,6 +6,7 @@
6 6
7mod break_outside_of_loop; 7mod break_outside_of_loop;
8mod inactive_code; 8mod inactive_code;
9mod incorrect_case;
9mod macro_error; 10mod macro_error;
10mod mismatched_arg_count; 11mod mismatched_arg_count;
11mod missing_fields; 12mod missing_fields;
@@ -135,7 +136,6 @@ pub struct DiagnosticsConfig {
135struct DiagnosticsContext<'a> { 136struct DiagnosticsContext<'a> {
136 config: &'a DiagnosticsConfig, 137 config: &'a DiagnosticsConfig,
137 sema: Semantics<'a, RootDatabase>, 138 sema: Semantics<'a, RootDatabase>,
138 #[allow(unused)]
139 resolve: &'a AssistResolveStrategy, 139 resolve: &'a AssistResolveStrategy,
140} 140}
141 141
@@ -165,9 +165,6 @@ pub(crate) fn diagnostics(
165 } 165 }
166 let res = RefCell::new(res); 166 let res = RefCell::new(res);
167 let sink_builder = DiagnosticSinkBuilder::new() 167 let sink_builder = DiagnosticSinkBuilder::new()
168 .on::<hir::diagnostics::IncorrectCase, _>(|d| {
169 res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
170 })
171 .on::<UnlinkedFile, _>(|d| { 168 .on::<UnlinkedFile, _>(|d| {
172 // Limit diagnostic to the first few characters in the file. This matches how VS Code 169 // Limit diagnostic to the first few characters in the file. This matches how VS Code
173 // renders it with the full span, but on other editors, and is less invasive. 170 // renders it with the full span, but on other editors, and is less invasive.
@@ -216,6 +213,7 @@ pub(crate) fn diagnostics(
216 #[rustfmt::skip] 213 #[rustfmt::skip]
217 let d = match diag { 214 let d = match diag {
218 AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), 215 AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d),
216 AnyDiagnostic::IncorrectCase(d) => incorrect_case::incorrect_case(&ctx, &d),
219 AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), 217 AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d),
220 AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), 218 AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d),
221 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), 219 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
@@ -250,16 +248,6 @@ pub(crate) fn diagnostics(
250 res 248 res
251} 249}
252 250
253fn warning_with_fix<D: DiagnosticWithFixes>(
254 d: &D,
255 sema: &Semantics<RootDatabase>,
256 resolve: &AssistResolveStrategy,
257) -> Diagnostic {
258 Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
259 .with_fixes(d.fixes(sema, resolve))
260 .with_code(Some(d.code()))
261}
262
263fn check_unnecessary_braces_in_use_statement( 251fn check_unnecessary_braces_in_use_statement(
264 acc: &mut Vec<Diagnostic>, 252 acc: &mut Vec<Diagnostic>,
265 file_id: FileId, 253 file_id: FileId,
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index e4bd90c3f..d763dca93 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -1,6 +1,5 @@
1//! Provides a way to attach fixes to the diagnostics. 1//! Provides a way to attach fixes to the diagnostics.
2//! The same module also has all curret custom fixes for the diagnostics implemented. 2//! The same module also has all curret custom fixes for the diagnostics implemented.
3mod change_case;
4 3
5use hir::{diagnostics::Diagnostic, Semantics}; 4use hir::{diagnostics::Diagnostic, Semantics};
6use ide_assists::AssistResolveStrategy; 5use ide_assists::AssistResolveStrategy;
diff --git a/crates/ide/src/diagnostics/fixes/change_case.rs b/crates/ide/src/diagnostics/incorrect_case.rs
index db1a37cd6..56283b58b 100644
--- a/crates/ide/src/diagnostics/fixes/change_case.rs
+++ b/crates/ide/src/diagnostics/incorrect_case.rs
@@ -1,35 +1,46 @@
1use hir::{db::AstDatabase, diagnostics::IncorrectCase, InFile, Semantics}; 1use hir::{db::AstDatabase, InFile};
2use ide_assists::{Assist, AssistResolveStrategy}; 2use ide_assists::Assist;
3use ide_db::{base_db::FilePosition, RootDatabase}; 3use ide_db::base_db::FilePosition;
4use syntax::AstNode; 4use syntax::AstNode;
5 5
6use crate::{ 6use crate::{
7 diagnostics::{unresolved_fix, DiagnosticWithFixes}, 7 diagnostics::{unresolved_fix, Diagnostic, DiagnosticsContext},
8 references::rename::rename_with_semantics, 8 references::rename::rename_with_semantics,
9 Severity,
9}; 10};
10 11
11impl DiagnosticWithFixes for IncorrectCase { 12// Diagnostic: incorrect-ident-case
12 fn fixes( 13//
13 &self, 14// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
14 sema: &Semantics<RootDatabase>, 15pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
15 resolve: &AssistResolveStrategy, 16 Diagnostic::new(
16 ) -> Option<Vec<Assist>> { 17 "incorrect-ident-case",
17 let root = sema.db.parse_or_expand(self.file)?; 18 format!(
18 let name_node = self.ident.to_node(&root); 19 "{} `{}` should have {} name, e.g. `{}`",
19 20 d.ident_type, d.ident_text, d.expected_case, d.suggested_text
20 let name_node = InFile::new(self.file, name_node.syntax()); 21 ),
21 let frange = name_node.original_file_range(sema.db); 22 ctx.sema.diagnostics_display_range(InFile::new(d.file, d.ident.clone().into())).range,
22 let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; 23 )
23 24 .severity(Severity::WeakWarning)
24 let label = format!("Rename to {}", self.suggested_text); 25 .with_fixes(fixes(ctx, d))
25 let mut res = unresolved_fix("change_case", &label, frange.range); 26}
26 if resolve.should_resolve(&res.id) { 27
27 let source_change = rename_with_semantics(sema, file_position, &self.suggested_text); 28fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> {
28 res.source_change = Some(source_change.ok().unwrap_or_default()); 29 let root = ctx.sema.db.parse_or_expand(d.file)?;
29 } 30 let name_node = d.ident.to_node(&root);
30 31
31 Some(vec![res]) 32 let name_node = InFile::new(d.file, name_node.syntax());
33 let frange = name_node.original_file_range(ctx.sema.db);
34 let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
35
36 let label = format!("Rename to {}", d.suggested_text);
37 let mut res = unresolved_fix("change_case", &label, frange.range);
38 if ctx.resolve.should_resolve(&res.id) {
39 let source_change = rename_with_semantics(&ctx.sema, file_position, &d.suggested_text);
40 res.source_change = Some(source_change.ok().unwrap_or_default());
32 } 41 }
42
43 Some(vec![res])
33} 44}
34 45
35#[cfg(test)] 46#[cfg(test)]