From 662b6ee39f47c09a303d3d53cb9c82b2dd783018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 11 Jul 2026 16:18:30 +0200 Subject: [PATCH] fix: validate duplicate language configurations in CHECKCFG The CHECKCFG grammar accepts multiple `for { ... }` blocks for the same language in one configuration, with no defined semantics for how duplicates combine. CheckCfgValidator.checkConfiguredLanguageUnique now reports an error on each ConfiguredLanguageValidator that shares a language name with another, mirroring the existing catalog/check/parameter uniqueness validators and reusing the getDuplicates() helper. Covered by CheckCfgTest.testDuplicateLanguageNotOk. Validation only, no quick-fix: a merge quick-fix cannot preserve generated output. Language-level parameters are inherited by inner catalogs and checks, and the properties generator resolves them first-wins per section, so collapsing two blocks into one silently changes which value inner catalogs inherit. The correct resolution depends on author intent, so the error guides the user to resolve duplicates manually. Language-scoped catalog/check/parameter uniqueness inside a single language block is a pre-existing validation gap left as a follow-up. Closes #103 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_018ANGM7L3BaEGfGUmPVKRt4 --- .../ddk/checkcfg/validation/CheckCfgTest.java | 17 +++++++++++ .../validation/CheckCfgValidator.java | 30 +++++++++++++++++++ .../ddk/checkcfg/validation/IssueCodes.java | 1 + .../ddk/checkcfg/validation/Messages.java | 1 + .../checkcfg/validation/messages.properties | 1 + 5 files changed, 50 insertions(+) diff --git a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java index dbad41e807..96c982960f 100644 --- a/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java +++ b/com.avaloq.tools.ddk.checkcfg.core.test/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgTest.java @@ -58,4 +58,21 @@ public void testUnknownLanguageNotOk() throws Exception { helper.assertError(model, CheckcfgPackage.Literals.CONFIGURED_LANGUAGE_VALIDATOR, IssueCodes.UNKNOWN_LANGUAGE); } + @Test + public void testDuplicateLanguageNotOk() throws Exception { + final CheckConfiguration model = parser.parse(""" + check configuration Test + + for com.avaloq.tools.ddk.^check.TestLanguage { + + } + + for com.avaloq.tools.ddk.^check.TestLanguage { + + } + + """); + helper.assertError(model, CheckcfgPackage.Literals.CONFIGURED_LANGUAGE_VALIDATOR, IssueCodes.DUPLICATE_LANGUAGE_CONFIGURATION); + } + } diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgValidator.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgValidator.java index 61a1b61f38..f65d12c8f6 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgValidator.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/CheckCfgValidator.java @@ -313,6 +313,36 @@ public void checkConfiguredLanguageExists(final ConfiguredLanguageValidator vali } } + /** + * Checks that within a Check Configuration all Configured Language Validators are unique, meaning that + * the same language can only be configured in one place. + * + * @param configuration + * the configuration + */ + @Check + public void checkConfiguredLanguageUnique(final CheckConfiguration configuration) { + if (configuration.getLanguageValidatorConfigurations().size() < 2) { + return; + } + Predicate predicate = new Predicate() { + @Override + public boolean apply(final ConfiguredLanguageValidator validator) { + return validator.getLanguage() != null; + } + }; + Function function = new Function() { + @Override + public String apply(final ConfiguredLanguageValidator from) { + return from.getLanguage(); + } + }; + for (final ConfiguredLanguageValidator v : getDuplicates(predicate, function, configuration.getLanguageValidatorConfigurations())) { + error(Messages.CheckCfgJavaValidator_DUPLICATE_LANGUAGE_CONFIGURATION, v, CheckcfgPackage.Literals.CONFIGURED_LANGUAGE_VALIDATOR__LANGUAGE, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, IssueCodes.DUPLICATE_LANGUAGE_CONFIGURATION); + } + + } + /** * Checks that a Configured Check has unique Configured Parameters. * diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/IssueCodes.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/IssueCodes.java index 2a9818854a..75ae4c4791 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/IssueCodes.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/IssueCodes.java @@ -26,6 +26,7 @@ public final class IssueCodes { public static final String DUPLICATE_CATALOG_CONFIGURATION = ISSUE_CODE_PREFIX + "duplicate_catalog_configuration"; public static final String DUPLICATE_CHECK_CONFIGURATION = ISSUE_CODE_PREFIX + "duplicate_check_configuration"; public static final String UNKNOWN_LANGUAGE = ISSUE_CODE_PREFIX + "unknown_language"; + public static final String DUPLICATE_LANGUAGE_CONFIGURATION = ISSUE_CODE_PREFIX + "duplicate_language_configuration"; public static final String DUPLICATE_PARAMETER_CONFIGURATION = ISSUE_CODE_PREFIX + "duplicate_parameter_configuration"; public static final String SEVERITY_NOT_ALLOWED = ISSUE_CODE_PREFIX + "severity_not_allowed"; public static final String PARAMETER_VALUE_NOT_ALLOWED = ISSUE_CODE_PREFIX + "parameter_value_not_allowed"; diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/Messages.java b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/Messages.java index e96bcdc209..66dfb4bb3c 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/Messages.java +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/Messages.java @@ -25,6 +25,7 @@ public class Messages extends NLS { public static String CheckCfgJavaValidator_CONFIGURED_PARAM_EQUALS_DEFAULT; public static String CheckCfgJavaValidator_DUPLICATE_CATALOG_CONFIGURATION; public static String CheckCfgJavaValidator_DUPLICATE_CHECK_CONFIGURATION; + public static String CheckCfgJavaValidator_DUPLICATE_LANGUAGE_CONFIGURATION; public static String CheckCfgJavaValidator_DUPLICATE_PARAMETER_CONFIGURATION; public static String CheckCfgJavaValidator_SEVERITY_NOT_ALLOWED; diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/messages.properties b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/messages.properties index 63001722ae..1ad5b893dd 100644 --- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/messages.properties +++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/validation/messages.properties @@ -5,5 +5,6 @@ CheckCfgJavaValidator_FINAL_CHECK_NOT_CONFIGURABLE=Final checks may not be confi CheckCfgJavaValidator_CONFIGURED_PARAM_EQUALS_DEFAULT=Configured value for ''{0}'' equals default CheckCfgJavaValidator_DUPLICATE_CATALOG_CONFIGURATION=Duplicate catalog configuration CheckCfgJavaValidator_DUPLICATE_CHECK_CONFIGURATION=Duplicate check configuration +CheckCfgJavaValidator_DUPLICATE_LANGUAGE_CONFIGURATION=Duplicate language configuration CheckCfgJavaValidator_DUPLICATE_PARAMETER_CONFIGURATION=Duplicate parameter configuration CheckCfgJavaValidator_SEVERITY_NOT_ALLOWED=Configured severity is not allowed \ No newline at end of file