From e5c7c8ea544f5d2dc4dfbfb4467b82d2e3de8362 Mon Sep 17 00:00:00 2001 From: Dark Date: Thu, 11 Jan 2024 14:13:34 -0500 Subject: [PATCH] add experimental switch call linter to dtacheck --- crates/dtacheck/src/linter.rs | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/crates/dtacheck/src/linter.rs b/crates/dtacheck/src/linter.rs index 5570cd5..91dbdeb 100644 --- a/crates/dtacheck/src/linter.rs +++ b/crates/dtacheck/src/linter.rs @@ -38,6 +38,7 @@ fn lint_node(lints: &mut Vec>, ast: &[Node], funcs: &Function) { if !has_preprocessor_directive { lint_fn_args(lints, array, node.span.clone(), funcs); + lint_switch_fallthrough(lints, array, node.span.clone()); } } _ => (), @@ -211,3 +212,46 @@ fn lint_preprocs(lints: &mut Vec>, tokens: &[Token]) { lints.push(Box::new(PreProcLint::Unmatched(lint.0))); } } + +// switch fallthough + +struct SwitchFallthroughLint(Range, Range); + +impl Lint for SwitchFallthroughLint { + fn to_codespan(&self, id: usize) -> Diagnostic { + Diagnostic::warning() + .with_message("missing fallthrough for switch") + .with_labels(vec![ + Label::primary(id, self.0.clone()), + Label::secondary(id, self.1.clone()) + .with_message("consider adding a fallthrough node here"), + ]) + } +} + +fn lint_switch_fallthrough( + lints: &mut Vec>, + stmt: &[Node], + span: Range, +) { + if stmt.is_empty() { + return; + } + + let NodeKind::Symbol(ref sym) = stmt[0].kind else { + return; + }; + + if sym != "switch" { + return; + } + + let Some(last_node) = stmt.last() else { + return; + }; + + if last_node.kind.is_array() { + let pos = span.end - 1; + lints.push(Box::new(SwitchFallthroughLint(span, pos..pos))) + } +}