aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md12
-rw-r--r--mingling_macros/src/lib.rs25
2 files changed, 30 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c36f25..9863596 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,8 @@ Any contributor making changes to the project must record their changes in this
**- Milestone.1 "MVP" -**
-- [Release 0.2.0 (Unreleased)](#release-020-unreleased)
+- [Release 0.2.1 (Unreleased)](#release-021-unreleased)
+- [Release 0.2.0 (2026-06-30)](#release-020-2026-06-30)
- [Release 0.1.9 (2026-05-29)](#release-019-2026-05-29)
- [Release 0.1.8 (2026-05-18)](#release-018-2026-05-18)
- [Release 0.1.7 (2026-05-04)](#release-017-2026-05-04)
@@ -26,11 +27,16 @@ Any contributor making changes to the project must record their changes in this
## Contents
-### Release ? (Unreleased)
+### Release 0.2.1 (Unreleased)
#### Fixes:
-None
+1. **[`macros`]** Fixed false positives in `entry_has_variant` caused by bare substring matching in the third `contains` check.
+ When a longer variant (e.g., `EntryListAlias`) is registered first, followed by a shorter variant that shares the same prefix (e.g., `EntryList`),
+ `"=> EntryList"` would incorrectly match as a substring of `"=> EntryListAlias,"`, causing a false duplicate registration detection.
+ Now changed to use `find` + trailing character boundary validation, ensuring the character immediately after the match is not an identifier character (letter/digit/underscore).
+
+ Affected scope: Deduplication logic for `#[chain]`, `#[renderer]`, `#[help]`, and `#[completion]` registration.
#### Optimizations:
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 546416d..c82466d 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -241,10 +241,27 @@ pub(crate) fn check_duplicate_variant(
/// Checks if a stored entry string contains the given variant name.
/// Handles both "StructName => Variant," and "Self::Variant => ..." formats.
fn entry_has_variant(entry: &str, variant_name: &str) -> bool {
- entry.contains(&format!("=> {variant_name},"))
- || entry.contains(&format!("=> {variant_name} "))
- || entry.contains(&format!("=> {variant_name}"))
- || entry.contains(&format!(":: {variant_name} =>"))
+ let variant_match = format!("=> {variant_name}");
+
+ // "StructName => Variant," — exact match with trailing comma
+ if entry.contains(&format!("{variant_match},")) {
+ return true;
+ }
+ // "StructName => Variant " — exact match with trailing space
+ if entry.contains(&format!("{variant_match} ")) {
+ return true;
+ }
+ // "StructName => Variant" (fallback) — must NOT be followed by identifier chars
+ if let Some(idx) = entry.find(&variant_match) {
+ let after = idx + variant_match.len();
+ if after >= entry.len()
+ || !entry[after..].starts_with(|c: char| c.is_alphanumeric() || c == '_')
+ {
+ return true;
+ }
+ }
+ // "Self::Variant => ..." — match-arm existence check format
+ entry.contains(&format!(":: {variant_name} =>"))
}
/// Registers an outside-type as a member of a program group without modifying its definition.