diff --git a/Cargo.lock b/Cargo.lock index 8a1134b..80ba68f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,7 +286,7 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "logic_lint" -version = "0.1.3" +version = "0.1.4" dependencies = [ "lazy-regex", "tag_code", @@ -301,7 +301,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.15.5" +version = "0.15.6" dependencies = [ "display_source", "logic_lint", diff --git a/Cargo.toml b/Cargo.toml index b9e7f98..db6f937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.15.5" +version = "0.15.6" edition = "2021" authors = ["A4-Tacks "] diff --git a/tools/logic_lint/Cargo.toml b/tools/logic_lint/Cargo.toml index 35e49c2..49ebe0b 100644 --- a/tools/logic_lint/Cargo.toml +++ b/tools/logic_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "logic_lint" -version = "0.1.3" +version = "0.1.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/tools/logic_lint/src/lib.rs b/tools/logic_lint/src/lib.rs index d67f221..1eb7373 100644 --- a/tools/logic_lint/src/lib.rs +++ b/tools/logic_lint/src/lib.rs @@ -1,7 +1,7 @@ pub mod lints; use core::fmt; -use std::{borrow::Cow, collections::HashSet, ops::Deref}; +use std::{borrow::Cow, collections::HashMap, ops::Deref}; use lints::get_useds; use tag_code::mdt_logic_split_unwraped; @@ -66,21 +66,32 @@ impl<'a> Line<'a> { #[derive(Debug)] pub struct Source<'a> { lines: Vec>, - used_vars: HashSet<&'a str>, + used_vars: HashMap<&'a str, Vec>>, } impl<'a> Source<'a> { pub fn from_str(s: &'a str) -> Self { + let env_assignables = &[ + "@counter", + ][..]; let lines = s.lines().enumerate() .map(|(lineno, line)| Line::from_line(lineno, line)) .collect::>(); - let used_vars = FromIterator::from_iter(lines.iter() + let mut used_vars: HashMap<&str, Vec>> = HashMap::new(); + lines.iter() .filter_map(get_useds) .flatten() - .filter_map(|used| used.as_read().map(Var::value)) - .chain([ - "@counter", - ])); + .filter_map(|used| ( + used.as_read().map(Var::value)?, + *used.as_read().unwrap() + ).into()) + .chain(env_assignables.iter() + .map(|&var| (var, Var::new_nonlocation(var)))) + .for_each(|(key, var)| { + used_vars.entry(key) + .or_default() + .push(var) + }); Self { lines, @@ -147,6 +158,10 @@ impl<'a> Var<'a> { Self { lineno, arg_idx, value } } + pub fn new_nonlocation(value: &'a str) -> Self { + Self { lineno: usize::MAX, arg_idx: 0, value } + } + pub fn value(&self) -> &'a str { self.value } diff --git a/tools/logic_lint/src/lints.rs b/tools/logic_lint/src/lints.rs index 29545e6..da6578b 100644 --- a/tools/logic_lint/src/lints.rs +++ b/tools/logic_lint/src/lints.rs @@ -71,7 +71,7 @@ impl VarUsedMethod { } } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct VarUsed<'a> { method: VarUsedMethod, var: Var<'a>, @@ -230,9 +230,17 @@ fn check_assign_var<'a>( VarType::Var(_) => { let mut lints = Vec::new(); lints.extend(check_var(src, line, var)); - if !src.used_vars.contains(var.value()) - && !regex_is_match!(r"^_(?:$|[^_])", var.value()) - { + 'x: { + if let Some(useds) = src.used_vars.get(var.value()) { + if useds.iter() + .any(|used| used.lineno() != var.lineno()) + { + break 'x; + } + } + if regex_is_match!(r"^_(?:$|[^_])", var.value()) { + break 'x; + } lints.push(Lint::new(var, WarningLint::NeverUsed)); } vec_optiter(lints.into())