diff options
author | Igor Aleksanov <[email protected]> | 2020-10-03 10:48:02 +0100 |
---|---|---|
committer | Igor Aleksanov <[email protected]> | 2020-10-12 08:59:54 +0100 |
commit | 4039176ec63e5c75d76398f2debe26ac6fa59cbc (patch) | |
tree | 8f2f2b6d22c57985fc6a8f1b40d84663d40b09f6 /crates/hir_ty/src/diagnostics.rs | |
parent | 518f6d772482c7c58e59081f340947087a9b4800 (diff) |
Create basic support for names case checks and implement function name case check
Diffstat (limited to 'crates/hir_ty/src/diagnostics.rs')
-rw-r--r-- | crates/hir_ty/src/diagnostics.rs | 81 |
1 files changed, 78 insertions, 3 deletions
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 9ba005fab..7227e7010 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -2,10 +2,11 @@ | |||
2 | mod expr; | 2 | mod expr; |
3 | mod match_check; | 3 | mod match_check; |
4 | mod unsafe_check; | 4 | mod unsafe_check; |
5 | mod decl_check; | ||
5 | 6 | ||
6 | use std::any::Any; | 7 | use std::{any::Any, fmt}; |
7 | 8 | ||
8 | use hir_def::DefWithBodyId; | 9 | use hir_def::{DefWithBodyId, ModuleDefId}; |
9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; | 10 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; |
10 | use hir_expand::{name::Name, HirFileId, InFile}; | 11 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use stdx::format_to; | 12 | use stdx::format_to; |
@@ -15,6 +16,16 @@ use crate::db::HirDatabase; | |||
15 | 16 | ||
16 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | 17 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; |
17 | 18 | ||
19 | pub fn validate_module_item( | ||
20 | db: &dyn HirDatabase, | ||
21 | owner: ModuleDefId, | ||
22 | sink: &mut DiagnosticSink<'_>, | ||
23 | ) { | ||
24 | let _p = profile::span("validate_body"); | ||
25 | let mut validator = decl_check::DeclValidator::new(owner, sink); | ||
26 | validator.validate_item(db); | ||
27 | } | ||
28 | |||
18 | pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { | 29 | pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { |
19 | let _p = profile::span("validate_body"); | 30 | let _p = profile::span("validate_body"); |
20 | let infer = db.infer(owner); | 31 | let infer = db.infer(owner); |
@@ -231,6 +242,64 @@ impl Diagnostic for MismatchedArgCount { | |||
231 | } | 242 | } |
232 | } | 243 | } |
233 | 244 | ||
245 | #[derive(Debug)] | ||
246 | pub enum CaseType { | ||
247 | // `some_var` | ||
248 | LowerSnakeCase, | ||
249 | // `SOME_CONST` | ||
250 | UpperSnakeCase, | ||
251 | // `SomeStruct` | ||
252 | UpperCamelCase, | ||
253 | } | ||
254 | |||
255 | impl fmt::Display for CaseType { | ||
256 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
257 | let repr = match self { | ||
258 | CaseType::LowerSnakeCase => "snake_case", | ||
259 | CaseType::UpperSnakeCase => "UPPER_SNAKE_CASE", | ||
260 | CaseType::UpperCamelCase => "UpperCamelCase", | ||
261 | }; | ||
262 | |||
263 | write!(f, "{}", repr) | ||
264 | } | ||
265 | } | ||
266 | |||
267 | #[derive(Debug)] | ||
268 | pub struct IncorrectCase { | ||
269 | pub file: HirFileId, | ||
270 | pub ident: SyntaxNodePtr, | ||
271 | pub expected_case: CaseType, | ||
272 | pub ident_text: String, | ||
273 | pub suggested_text: String, | ||
274 | } | ||
275 | |||
276 | impl Diagnostic for IncorrectCase { | ||
277 | fn code(&self) -> DiagnosticCode { | ||
278 | DiagnosticCode("incorrect-ident-case") | ||
279 | } | ||
280 | |||
281 | fn message(&self) -> String { | ||
282 | format!( | ||
283 | "Argument `{}` should have a {} name, e.g. `{}`", | ||
284 | self.ident_text, | ||
285 | self.expected_case.to_string(), | ||
286 | self.suggested_text | ||
287 | ) | ||
288 | } | ||
289 | |||
290 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
291 | InFile::new(self.file, self.ident.clone()) | ||
292 | } | ||
293 | |||
294 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
295 | self | ||
296 | } | ||
297 | |||
298 | fn is_experimental(&self) -> bool { | ||
299 | true | ||
300 | } | ||
301 | } | ||
302 | |||
234 | #[cfg(test)] | 303 | #[cfg(test)] |
235 | mod tests { | 304 | mod tests { |
236 | use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | 305 | use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; |
@@ -242,7 +311,10 @@ mod tests { | |||
242 | use rustc_hash::FxHashMap; | 311 | use rustc_hash::FxHashMap; |
243 | use syntax::{TextRange, TextSize}; | 312 | use syntax::{TextRange, TextSize}; |
244 | 313 | ||
245 | use crate::{diagnostics::validate_body, test_db::TestDB}; | 314 | use crate::{ |
315 | diagnostics::{validate_body, validate_module_item}, | ||
316 | test_db::TestDB, | ||
317 | }; | ||
246 | 318 | ||
247 | impl TestDB { | 319 | impl TestDB { |
248 | fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | 320 | fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { |
@@ -253,6 +325,9 @@ mod tests { | |||
253 | let mut fns = Vec::new(); | 325 | let mut fns = Vec::new(); |
254 | for (module_id, _) in crate_def_map.modules.iter() { | 326 | for (module_id, _) in crate_def_map.modules.iter() { |
255 | for decl in crate_def_map[module_id].scope.declarations() { | 327 | for decl in crate_def_map[module_id].scope.declarations() { |
328 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | ||
329 | validate_module_item(self, decl, &mut sink); | ||
330 | |||
256 | if let ModuleDefId::FunctionId(f) = decl { | 331 | if let ModuleDefId::FunctionId(f) = decl { |
257 | fns.push(f) | 332 | fns.push(f) |
258 | } | 333 | } |