forge_lint/sol/info/
screaming_snake_case.rs1use super::ScreamingSnakeCase;
2use crate::{
3 linter::{EarlyLintPass, LintContext, Suggestion},
4 sol::{Severity, SolLint},
5};
6use solar::ast::{VarMut, VariableDefinition};
7
8declare_forge_lint!(
9 SCREAMING_SNAKE_CASE_CONSTANT,
10 Severity::Info,
11 "screaming-snake-case-const",
12 "constants should use SCREAMING_SNAKE_CASE"
13);
14
15declare_forge_lint!(
16 SCREAMING_SNAKE_CASE_IMMUTABLE,
17 Severity::Info,
18 "screaming-snake-case-immutable",
19 "immutables should use SCREAMING_SNAKE_CASE"
20);
21
22impl<'ast> EarlyLintPass<'ast> for ScreamingSnakeCase {
23 fn check_variable_definition(
24 &mut self,
25 ctx: &LintContext,
26 var: &'ast VariableDefinition<'ast>,
27 ) {
28 if let (Some(name), Some(mutability)) = (var.name, var.mutability)
29 && let Some(expected) = check_screaming_snake_case(name.as_str())
30 {
31 let suggestion = Suggestion::fix(
32 expected,
33 solar::interface::diagnostics::Applicability::MachineApplicable,
34 )
35 .with_desc("consider using");
36
37 match mutability {
38 VarMut::Constant => {
39 ctx.emit_with_suggestion(&SCREAMING_SNAKE_CASE_CONSTANT, name.span, suggestion)
40 }
41 VarMut::Immutable => {
42 ctx.emit_with_suggestion(&SCREAMING_SNAKE_CASE_IMMUTABLE, name.span, suggestion)
43 }
44 }
45 }
46 }
47}
48
49pub fn check_screaming_snake_case(s: &str) -> Option<String> {
52 if s.len() <= 1 {
53 return None;
54 }
55
56 let expected = format!(
58 "{prefix}{name}{suffix}",
59 prefix = if s.starts_with("_") { "_" } else { "" },
60 name = heck::AsShoutySnakeCase(s),
61 suffix = if s.ends_with("_") { "_" } else { "" }
62 );
63 if s == expected { None } else { Some(expected) }
64}