Skip to content

Commit

Permalink
sqf: Add lint for unneeded not
Browse files Browse the repository at this point in the history
  • Loading branch information
PabstMirror committed Oct 18, 2024
1 parent 4d93c00 commit e475613
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 0 deletions.
134 changes: 134 additions & 0 deletions libs/sqf/src/analyze/lints/s19_extra_not.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use std::{ops::Range, sync::Arc};

use hemtt_common::config::LintConfig;
use hemtt_workspace::{
lint::{AnyLintRunner, Lint, LintRunner},
reporting::{Code, Codes, Diagnostic, Processed, Severity},
};

use crate::{analyze::SqfLintData, Expression, UnaryCommand};

crate::lint!(LintS19ExtraNot);

impl Lint<SqfLintData> for LintS19ExtraNot {
fn ident(&self) -> &str {
"extra_not"
}

fn sort(&self) -> u32 {
190
}

fn description(&self) -> &str {
"Checks for extra not before a comparison"
}

fn documentation(&self) -> &str {
r"### Example
**Incorrect**
```sqf
! (5 isEqualTo 6)
```
**Correct**
```sqf
(5 isNotEqualTo 6)
```
"
}

fn default_config(&self) -> LintConfig {
LintConfig::help()
}

fn runners(&self) -> Vec<Box<dyn AnyLintRunner<SqfLintData>>> {
vec![Box::new(Runner)]
}
}

struct Runner;
impl LintRunner<SqfLintData> for Runner {
type Target = crate::Expression;

fn run(
&self,
_project: Option<&hemtt_common::config::ProjectConfig>,
config: &LintConfig,
processed: Option<&hemtt_workspace::reporting::Processed>,
target: &Self::Target,
_data: &SqfLintData,
) -> Codes {
const COMPARISON_CMDS: &[&str] = &[
"==",
"!=",
"isEqualTo",
"isNotEqualTo",
"<",
"<=",
">",
">=",
];
let Some(processed) = processed else {
return Vec::new();
};
let Expression::UnaryCommand(UnaryCommand::Not, rhs, range) = target else {
return Vec::new();
};
let Expression::BinaryCommand(ref last_cmd, _, _, _) = **rhs else {
return Vec::new();
};
if !COMPARISON_CMDS.contains(&last_cmd.as_str()) {
return Vec::new();
}

vec![Arc::new(Code19ExtraNot::new(
range.clone(),
processed,
config.severity(),
))]
}
}

#[allow(clippy::module_name_repetitions)]
pub struct Code19ExtraNot {
span: Range<usize>,
severity: Severity,
diagnostic: Option<Diagnostic>,
}

impl Code for Code19ExtraNot {
fn ident(&self) -> &'static str {
"L-S19"
}
fn link(&self) -> Option<&str> {
Some("/analysis/sqf.html#extra_not")
}
fn severity(&self) -> Severity {
self.severity
}
fn message(&self) -> String {
"Unneeded Not".to_string()
}
// fn label_message(&self) -> String {
// "".to_string()
// }
fn diagnostic(&self) -> Option<Diagnostic> {
self.diagnostic.clone()
}
}

impl Code19ExtraNot {
#[must_use]
pub fn new(span: Range<usize>, processed: &Processed, severity: Severity) -> Self {
Self {
span,
severity,
diagnostic: None,
}
.generate_processed(processed)
}
fn generate_processed(mut self, processed: &Processed) -> Self {
self.diagnostic = Diagnostic::new_for_processed(&self, self.span.clone(), processed);
self
}
}
1 change: 1 addition & 0 deletions libs/sqf/tests/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,6 @@ analyze!(s09_banned_command);
analyze!(s11_if_not_else);
analyze!(s17_var_all_caps);
analyze!(s18_in_vehicle_check);
analyze!(s19_extra_not);
analyze!(s20_bool_static_comparison);
analyze!(s21_invalid_comparisons);
1 change: 1 addition & 0 deletions libs/sqf/tests/lints/s19_extra_not/source.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
! (5 isEqualTo 6)
6 changes: 6 additions & 0 deletions libs/sqf/tests/lints/s19_extra_not/stdout.ansi
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
help[L-S19]: Unneeded Not
┌─ source.sqf:1:1
│
1 │ ! (5 isEqualTo 6)
│ ^ Unneeded Not

0 comments on commit e475613

Please sign in to comment.