From 645c51f7ea035c6531f0a23e101c2b5d2a4d6b48 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Thu, 30 Apr 2026 13:00:21 +0200 Subject: Issue a warning on unused macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miquel Sabaté Solà --- lib/xixanta/src/assembler.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'lib/xixanta') diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index b01777c..c53f143 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -114,6 +114,15 @@ struct Assembler<'a> { pending: Vec, labels_seen: usize, + // List of macro names being used throughout the code. It will be filled at + // at the 'context' stage, and then removed whenever bundle_call() uses the + // given macro. In the end, the check() stage should rely on this vector for + // unused macros. + // + // NOTE: we could've also worked with the 'macros' member, but that would've + // made it more complex with the lifetime argument and all of that. + macro_names: Vec, + // Number of macro statements seen on a given iteration. Note that the // parser guarantees that macros are defined well (no unclosed macros nor // too many .endmacro's). @@ -411,6 +420,7 @@ impl<'a> Assembler<'a> { literal_mode: None, stage: Stage::Context, macros: HashMap::new(), + macro_names: vec![], mappings, current_mapping: 0, current_segment: 0, @@ -672,6 +682,7 @@ impl<'a> Assembler<'a> { // unrolled whenever we have to perform a macro // call. self.macros.entry(name.value.clone()).or_insert(node); + self.macro_names.push(name.value.clone()); } } ControlType::EndMacro @@ -1305,6 +1316,20 @@ impl<'a> Assembler<'a> { } } + // And last but not least, let's perform the check for macros, unless + // stated otherwise. + if !self.allow_unused { + for m in &self.macro_names { + self.warnings.push(Error { + line: 0, + message: format!("macro '{m}' is unused"), + source: self.sources[0].clone(), + expanded_from: self.macro_context.clone(), + global: true, + }); + } + } + if errors.is_empty() { Ok(()) } else { @@ -1424,6 +1449,14 @@ impl<'a> Assembler<'a> { global: false, })?; + // If the macro had not been referenced yet, remove it from the vector + // of pending macros. + if !self.allow_unused { + if let Some(pos) = self.macro_names.iter().position(|x| x == &node.value.value) { + self.macro_names.swap_remove(pos); + } + } + // Detect missmatches between the number of arguments provided and the // ones defined by the macro. let given_args = node.args.as_ref().unwrap_or(&vec![]).len(); -- cgit v1.2.3