From c57b9e0bbe56a8172fb77deb67276e8cb60d5b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Thu, 13 Aug 2026 17:27:08 +0200 Subject: [PATCH 01/11] Prepare CLI options for class2mc without java runtime --- .../java/de/monticore/cdgen/CDGenTool.java | 55 +++++++++++++++---- .../cd/cdgen/AbstractDecoratorTest.java | 2 +- .../cdgen/gradleplugin/CDGenTask.java | 14 +++++ 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java index f101af407..6ae4b1a7e 100644 --- a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java +++ b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java @@ -40,6 +40,7 @@ import java.io.File; import java.io.IOException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -119,7 +120,8 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { final boolean c2mc = cmd.hasOption("c2mc"); - initializeSymbolTable(c2mc); + initializeSymbolTable(c2mc, cmd.hasOption("class2mc-no-java-runtime"), cmd.hasOption( + "use-standard-symbols")); Log.enableFailQuick(false); Collection asts = this.parse(".cd", this.createModelPath(cmd) @@ -212,24 +214,50 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { CD4CodeMill.globalScope().clear(); } - public void initializeSymbolTable(boolean c2mc) { + public void initializeSymbolTable(boolean c2mc, boolean c2mcNoRuntime, + boolean loadStandardSymbolLibrary) { BasicSymbolsMill.initializePrimitives(); MCCollectionSymTypeRelations.init(); if (c2mc) { - initializeClass2MC(); + if (c2mcNoRuntime) { + // TODO: Migrate to " Add toggle for load from jdk " once merged + CD4CodeMill.globalScope().addAdaptedTypeSymbolResolver(new OOClass2MCResolver() { + + @Override + protected Optional loadFromJDK(String name) { + return Optional.empty(); + } + + }); + CD4CodeMill.globalScope().addAdaptedOOTypeSymbolResolver(new OOClass2MCResolver() { + + @Override + protected Optional loadFromJDK(String name) { + return Optional.empty(); + } + + }); + } + else { + CD4CodeMill.globalScope().addAdaptedTypeSymbolResolver(new OOClass2MCResolver()); + CD4CodeMill.globalScope().addAdaptedOOTypeSymbolResolver(new OOClass2MCResolver()); + } + if (loadStandardSymbolLibrary) { + Log.warn( + "Both class2mc and loadStandardSymbolLibrary are enabled. This might lead to duplicate symbols."); + } } else { - BasicSymbolsMill.initializeString(); - BasicSymbolsMill.initializeObject(); + if (loadStandardSymbolLibrary) { + // TODO: Remove me and load the symtab instead + BasicSymbolsMill.initializeString(); + BasicSymbolsMill.initializeObject(); + } + } } - public void initializeClass2MC() { - CD4CodeMill.globalScope().addAdaptedTypeSymbolResolver(new OOClass2MCResolver()); - CD4CodeMill.globalScope().addAdaptedOOTypeSymbolResolver(new OOClass2MCResolver()); - } - public void initializeDecConf(GlobalExtensionManagement glex, DecoratorConfig decConfig, CommandLine cmd, GeneratorSetup setup) { // Setup CLI config overrides @@ -395,6 +423,13 @@ public Options addAdditionalOptions(Options options) { options.addOption(Option.builder("c2mc").longOpt("class2mc").desc( "Enables to resolve java classes in the model path").build()); + options.addOption(Option.builder().longOpt("class2mc-no-java-runtime").desc( + "Does not load the java runtime enviroment into class2mc. Only the symbolpath is used.") + .build()); + + options.addOption(Option.builder().longOpt("use-standard-symbols").desc( + "Loads the standard symbol library into the symbolpath.").build()); + options.addOption(Option.builder("cliconfig").desc("Configures additional").hasArgs().argName( "fqn:key[=value]").build()); diff --git a/cdlang/src/test/java/de/monticore/cd/cdgen/AbstractDecoratorTest.java b/cdlang/src/test/java/de/monticore/cd/cdgen/AbstractDecoratorTest.java index 38780d128..08232bc11 100644 --- a/cdlang/src/test/java/de/monticore/cd/cdgen/AbstractDecoratorTest.java +++ b/cdlang/src/test/java/de/monticore/cd/cdgen/AbstractDecoratorTest.java @@ -64,7 +64,7 @@ public TestResult doTest(ASTCDCompilationUnit cd) { tool.trafoBeforeSymtab(Collections.singletonList(cd)); final boolean class2mc = this.withClass2MC(); - tool.initializeSymbolTable(class2mc); + tool.initializeSymbolTable(class2mc, false, !class2mc); // Create ST tool.createSymbolTable(cd); diff --git a/cdtool/cdgradle/src/main/java/de/monticore/cdgen/gradleplugin/CDGenTask.java b/cdtool/cdgradle/src/main/java/de/monticore/cdgen/gradleplugin/CDGenTask.java index f0ecd7493..8622280c7 100644 --- a/cdtool/cdgradle/src/main/java/de/monticore/cdgen/gradleplugin/CDGenTask.java +++ b/cdtool/cdgradle/src/main/java/de/monticore/cdgen/gradleplugin/CDGenTask.java @@ -35,6 +35,14 @@ public CDGenTask() { @Input abstract Property getClass2MC(); + @Optional + @Input + abstract Property getClass2MCNoJavaRuntime(); + + @Optional + @Input + abstract Property getUseStandardSymbolLibrary(); + /** * Whether CoCos should be checked, default is true * @@ -82,6 +90,12 @@ protected List createArgList(Function handlePath) { if (getClass2MC().isPresent() && getClass2MC().get()) { list.add("--class2mc"); } + if (getClass2MCNoJavaRuntime().isPresent() && getClass2MCNoJavaRuntime().get()) { + list.add("--class2mc-no-java-runtime"); + } + if (getUseStandardSymbolLibrary().isPresent() && getUseStandardSymbolLibrary().get()) { + list.add("--use-standard-symbols"); + } if (!getTargetSymbolPath().isEmpty()) { // model paths List modelPath = new ArrayList<>(); getTargetSymbolPath().forEach(it -> modelPath.add(it.toPath())); From 1e48dc58136eef6d613d474de4914eeb68093804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 09:44:14 +0200 Subject: [PATCH 02/11] Expose _checkFileAndPackageName parser flag --- .../cd4code/_parser/CD4CodeParser.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/cdlang/src/main/java/de/monticore/cd4code/_parser/CD4CodeParser.java b/cdlang/src/main/java/de/monticore/cd4code/_parser/CD4CodeParser.java index dff0b86c1..35dc2d9a1 100644 --- a/cdlang/src/main/java/de/monticore/cd4code/_parser/CD4CodeParser.java +++ b/cdlang/src/main/java/de/monticore/cd4code/_parser/CD4CodeParser.java @@ -8,7 +8,24 @@ public class CD4CodeParser extends CD4CodeParserTOP { - boolean _checkFileAndPackageName = true; + protected boolean _checkFileAndPackageName; + + /** + * The parser for this grammar. + * {@link de.monticore.cd4code.CD4CodeMill#parser()} should be preferred over this constructor, as + * this further enables language composition. + * + * @deprecated new instances of a parser should be retrieved via a language's mill + */ + @Deprecated + public CD4CodeParser() { + this(true); + } + + @SuppressWarnings("deprecation") + public CD4CodeParser(boolean _checkFileAndPackageName) { + this._checkFileAndPackageName = _checkFileAndPackageName; + } @Override public Optional parse(String fileName) throws IOException { From 13b670cf012617c74981e91b7393e1441dd9ff74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:27:40 +0200 Subject: [PATCH 03/11] fix docs --- doc/CDGen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CDGen.md b/doc/CDGen.md index f487d144f..2955d6de0 100644 --- a/doc/CDGen.md +++ b/doc/CDGen.md @@ -16,7 +16,7 @@ all class diagrams in the _cds_ source-directory-set (e.g., _src/main/cds_, _src // build.gradle plugins { id 'java-library' - id 'de.rwth.se.cdgen' version '$mc_version' + id 'de.rwth.se.cdgen' version "$mc_version" } repositories { From 8452c6d13168c419f0b74365396f1b5c70698a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:27:59 +0200 Subject: [PATCH 04/11] setupLog --- cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java index b2f5e2362..6fa0415a9 100644 --- a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java +++ b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java @@ -117,6 +117,9 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { return; } + // set up the log + setupLog(cmd); + final boolean c2mc = cmd.hasOption("c2mc"); initializeSymbolTable(c2mc, cmd.hasOption("class2mc-no-jdk")); From 826b827d28139dd48a155dc807d43274949bd90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:28:38 +0200 Subject: [PATCH 05/11] add RequiredArgsConstructorDecorator --- .../monticore/cd/codegen/DecoratorConfig.java | 4 + .../CardinalityDefaultDecorator.java | 10 ++- .../RequiredArgsConstructorDecorator.java | 88 +++++++++++++++++++ .../main/resources/cd2java/init/CD2Pojo.ftl | 3 +- .../cd2java/init/CD2PojoNoDefaults.ftl | 1 + .../methods/constructor/Constructor.ftl | 8 ++ 6 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 cdlang/src/main/java/de/monticore/cd/codegen/decorators/RequiredArgsConstructorDecorator.java create mode 100644 cdlang/src/main/resources/methods/constructor/Constructor.ftl diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java b/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java index b1f89ed27..16b525552 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java @@ -95,6 +95,10 @@ public ChainableGenSetup withVisitorImplementations() { public ChainableGenSetup withMethodImplementations() { return this.withDecorator(new MethodImplementationDecorator()); } + + public ChainableGenSetup withRequiredArgsConstructors() { + return this.withDecorator(new RequiredArgsConstructorDecorator()); + } @SuppressWarnings("unchecked") public ChainableGenSetup withDecorator(String className) { diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/CardinalityDefaultDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/CardinalityDefaultDecorator.java index 10652ea95..a9c00c94d 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/CardinalityDefaultDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/CardinalityDefaultDecorator.java @@ -3,6 +3,7 @@ import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import com.google.common.collect.Iterables; import de.monticore.cd.codegen.decorators.data.AbstractDecorator; import de.monticore.cd.facade.CDConstructorFacade; import de.monticore.cd4code._visitor.CD4CodeTraverser; @@ -77,7 +78,7 @@ protected void decorateList(ASTCDClass decoratedClazz, ASTCDAttribute attribute) // Setting the initial value of the attribute fails, as // "new"/CreatorExpression is not part of CD4C glex.addAfterTemplate(EMPTY_BODY, c, new TemplateHookPoint("methods.Instantiation", attribute - .getName(), ArrayList.class.getName())))); + .getName(), ArrayList.class.getName() + "<>")))); } protected ASTModifier createModifier(ASTModifier original) { @@ -103,4 +104,11 @@ public void addToTraverser(CD4CodeTraverser traverser) { traverser.add4CDBasis(this); } + @Override + public Iterable> getMustRunAfter() { + // Constructors may be added here + return Iterables.concat(super.getMustRunAfter(), List.of( + RequiredArgsConstructorDecorator.class)); + } + } diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/RequiredArgsConstructorDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/RequiredArgsConstructorDecorator.java new file mode 100644 index 000000000..aa84d79ac --- /dev/null +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/RequiredArgsConstructorDecorator.java @@ -0,0 +1,88 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.cd.codegen.decorators; + +import de.monticore.cd.codegen.decorators.data.AbstractDecorator; +import de.monticore.cd.facade.CDConstructorFacade; +import de.monticore.cd.facade.CDParameterFacade; +import de.monticore.cd.methodtemplates.CD4C; +import de.monticore.cd4code._visitor.CD4CodeTraverser; +import de.monticore.cd4codebasis._ast.ASTCDConstructor; +import de.monticore.cd4codebasis._visitor.CD4CodeBasisVisitor2; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDClass; +import de.monticore.cdbasis._visitor.CDBasisVisitor2; +import de.monticore.generating.templateengine.TemplateHookPoint; +import de.monticore.umlmodifier.UMLModifierMill; +import de.monticore.umlmodifier._ast.ASTModifier; +import de.monticore.umlmodifier._ast.ASTModifierBuilder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * Provides method bodies of (modeled) methods from templates + * TODO: ALu - Add CI tests for this decorator (right now it is for playing around) + */ +public class RequiredArgsConstructorDecorator extends AbstractDecorator + implements CD4CodeBasisVisitor2, CDBasisVisitor2 { + + protected record StackData(List attrs) {} + + protected Stack stack = new Stack<>(); + + @Override + public void visit(ASTCDClass astcdClass) { + stack.push(new StackData(new ArrayList<>())); + } + + @Override + public void visit(ASTCDAttribute attribute) { + if (stack.isEmpty()) + return; + + // TODO: required vs all? + if (!attribute.getModifier().isFinal()) + return; + + if (decoratorData.shouldDecorate(this.getClass(), attribute)) + stack.peek().attrs.add(attribute); + } + + @Override + public void endVisit(ASTCDClass node) { + if (stack.isEmpty()) + return; + if (decoratorData.shouldDecorate(this.getClass(), node)) { + // TODO: Check that method does not already exists! + ASTCDConstructor constructor = CDConstructorFacade.getInstance().createConstructor( + copyVisibility(node.getModifier()), node.getName()); + for (ASTCDAttribute attribute : stack.peek().attrs()) { + constructor.addCDParameter(CDParameterFacade.getInstance().createParameter(attribute)); + } + + decoratorData.getAsDecorated(node).addCDMember(constructor); + + glexOpt.ifPresent(g -> g.replaceTemplate(CD4C.getInstance().getEmptyBodyTemplate(), + constructor, new TemplateHookPoint("methods.constructor.Constructor", stack + .peek().attrs))); + + stack.pop(); + } + } + + protected ASTModifier copyVisibility(ASTModifier orig) { + ASTModifierBuilder vis = UMLModifierMill.modifierBuilder(); + vis.setPublic(orig.isPublic()); + vis.setProtected(orig.isProtected()); + vis.setPrivate(orig.isPrivate()); + return vis.build(); + } + + @Override + public void addToTraverser(CD4CodeTraverser traverser) { + traverser.add4CD4CodeBasis(this); + traverser.add4CDBasis(this); + } + +} diff --git a/cdlang/src/main/resources/cd2java/init/CD2Pojo.ftl b/cdlang/src/main/resources/cd2java/init/CD2Pojo.ftl index 4b8a5620d..9558ebc11 100644 --- a/cdlang/src/main/resources/cd2java/init/CD2Pojo.ftl +++ b/cdlang/src/main/resources/cd2java/init/CD2Pojo.ftl @@ -42,7 +42,8 @@ ${decConfig.withVisitors().applyOnName("visitor").ignoreOnName("noVisitor")} ${decConfig.withVisitorImplementations().applyOnName("visitor").ignoreOnName("noVisitor").ignoreOnName("noDefaultVisitor")} <#-- Similarly, the method implementation from templates decorator is NOT applied by default, unless an element or its parents are marked with impl --> ${decConfig.withMethodImplementations().applyOnName("impl").ignoreOnName("noImpl")} - +<#-- Similarly, the RequiredArgsConstructor decorator is NOT applied by default, unless a class or its parents are marked with requiredArgsConstructor --> +${decConfig.withRequiredArgsConstructors().applyOnName("requiredArgsConstructor").ignoreOnName("noRequiredArgsConstructor")} <#-- You can include & override the defaults by including this template diff --git a/cdlang/src/main/resources/cd2java/init/CD2PojoNoDefaults.ftl b/cdlang/src/main/resources/cd2java/init/CD2PojoNoDefaults.ftl index 1dd0887f1..01646e274 100644 --- a/cdlang/src/main/resources/cd2java/init/CD2PojoNoDefaults.ftl +++ b/cdlang/src/main/resources/cd2java/init/CD2PojoNoDefaults.ftl @@ -21,4 +21,5 @@ ${decConfig.withMethodImplementations().applyOnName("impl").ignoreOnName("noImpl ${decConfig.withVisitors().applyOnName("visitor").ignoreOnName("noVisitor")} ${decConfig.withVisitorImplementations().applyOnName("visitor").ignoreOnName("noVisitor").ignoreOnName("noDefaultVisitor")} ${decConfig.withMethodImplementations().applyOnName("impl").ignoreOnName("noImpl")} +${decConfig.withRequiredArgsConstructors().applyOnName("requiredArgsConstructor").ignoreOnName("noRequiredArgsConstructor")} diff --git a/cdlang/src/main/resources/methods/constructor/Constructor.ftl b/cdlang/src/main/resources/methods/constructor/Constructor.ftl new file mode 100644 index 000000000..55471dd27 --- /dev/null +++ b/cdlang/src/main/resources/methods/constructor/Constructor.ftl @@ -0,0 +1,8 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +<#-- @ftlvariable name="tc" type="de.monticore.generating.templateengine.TemplateController" --> + +${tc.signature("attributes")} +<#list attributes as attr> +<#-- ${tc.includeArgs("methods.Set", attr)} # todo: new list?--> +this.${attr.getName()} = ${attr.getName()}; + From f70d3ba52d996311e2cce99aeeff4c2d3db425fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:29:29 +0200 Subject: [PATCH 06/11] Fix MCTypeFacadeFix --- .../monticore/cd/codegen/MCTypeFacadeFix.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java b/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java new file mode 100644 index 000000000..6ae921e75 --- /dev/null +++ b/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java @@ -0,0 +1,39 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.cd.codegen; + +import com.google.common.collect.Lists; +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; +import de.monticore.types.mccollectiontypes._ast.ASTMCListType; +import de.monticore.types.mccollectiontypes._ast.ASTMCSetType; +import de.monticore.types.mcfullgenerictypes.MCFullGenericTypesMill; + +// TODO: Move this fix upstream if MCFullGenericTypes (?) is initialized +public class MCTypeFacadeFix { + + public static ASTMCListType createListTypeOf(final ASTMCType type) { + // Fix for IElem + var b = MCFullGenericTypesMill.mCListTypeBuilder(); + b.setMCTypeArgument(CD4CodeMill.mCCustomTypeArgumentBuilder().setMCType(type.deepClone()) + .build()); + return b.build(); + } + + public static ASTMCSetType createSetTypeOf(final ASTMCType type) { + // Fix for IElem + var b = MCFullGenericTypesMill.mCSetTypeBuilder(); + b.setMCTypeArgument(CD4CodeMill.mCCustomTypeArgumentBuilder().setMCType(type.deepClone()) + .build()); + return b.build(); + } + + public ASTMCGenericType createCollectionTypeOf(final ASTMCType type) { + var b = MCFullGenericTypesMill.mCBasicGenericTypeBuilder(); + b.setNamesList(Lists.newArrayList("Collection")); + b.addMCTypeArgument(CD4CodeMill.mCCustomTypeArgumentBuilder().setMCType(type.deepClone()) + .build()); + return b.build(); + } + +} From 6994bde61af2dc0f001ca05bf8180546885774f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:29:42 +0200 Subject: [PATCH 07/11] allow underscore attributes --- .../cocos/ebnf/CDAttributeNameLowerCaseIfNotStatic.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cdbasis/cocos/ebnf/CDAttributeNameLowerCaseIfNotStatic.java b/cdlang/src/main/java/de/monticore/cdbasis/cocos/ebnf/CDAttributeNameLowerCaseIfNotStatic.java index 73f1793d2..07720cc5a 100644 --- a/cdlang/src/main/java/de/monticore/cdbasis/cocos/ebnf/CDAttributeNameLowerCaseIfNotStatic.java +++ b/cdlang/src/main/java/de/monticore/cdbasis/cocos/ebnf/CDAttributeNameLowerCaseIfNotStatic.java @@ -5,13 +5,14 @@ import de.monticore.cdbasis._cocos.CDBasisASTCDAttributeCoCo; import de.se_rwth.commons.logging.Log; -/** Checks that attribute names start lower-case. */ +/** Checks that attribute names start lower-case or underscore. */ public class CDAttributeNameLowerCaseIfNotStatic implements CDBasisASTCDAttributeCoCo { /** @see de.monticore.cdbasis._cocos.CDBasisASTCDAttributeCoCo#check(ASTCDAttribute) */ @Override public void check(ASTCDAttribute a) { - if (!a.getModifier().isStatic() && !Character.isLowerCase(a.getName().charAt(0))) { + if (!a.getModifier().isStatic() && !Character.isLowerCase(a.getName().charAt(0)) && a.getName() + .charAt(0) != '_') { Log.error(String.format("0xCDC03: Attribute %s must start in lower-case.", a.getName()), a .get_SourcePositionStart()); } From 39ade332e940855ac88ef409ebd0192028d88495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:31:50 +0200 Subject: [PATCH 08/11] hotfix resolving of generic types --- .../cd/cocos/ImplementOnlyInterfaces.java | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cd/cocos/ImplementOnlyInterfaces.java b/cdlang/src/main/java/de/monticore/cd/cocos/ImplementOnlyInterfaces.java index 21cb17afe..91371d521 100644 --- a/cdlang/src/main/java/de/monticore/cd/cocos/ImplementOnlyInterfaces.java +++ b/cdlang/src/main/java/de/monticore/cd/cocos/ImplementOnlyInterfaces.java @@ -7,6 +7,8 @@ import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; import de.monticore.symbols.oosymbols._symboltable.OOTypeSymbol; import de.monticore.types.mcbasictypes._ast.ASTMCObjectType; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; import de.se_rwth.commons.logging.Log; import java.util.List; import java.util.Optional; @@ -26,14 +28,34 @@ public void check(ASTCDClass node) { return; } final List interfaceList = node.getCDInterfaceUsage().getInterfaceList(); - interfaceList.stream().map(s -> symbol.getEnclosingScope().resolveOOType(s.printType())).filter( - Optional::isPresent).map(Optional::get).filter(e -> !e.isIsInterface()).forEach(e -> Log - .error(String.format( + interfaceList.stream().map(s -> symbol.getEnclosingScope().resolveOOType(getObjectName(s))) + .filter(Optional::isPresent).map(Optional::get).filter(e -> !e.isIsInterface()).forEach( + e -> Log.error(String.format( "0xCDCF4: Class %s cannot implement %s %s. A class may only implement interfaces.", node.getName(), CDMill.cDTypeKindPrinter().print(e), e.getName()), node .get_SourcePositionStart())); } + protected String getObjectName(ASTMCObjectType type) { + // TODO: This is a fix for the following types: + // class State_Pat implements IState, IElem + // class Opt implements IElem + // interface IElem { } + // -> this tries to resolve "IElem.class", which fails HARD due to illegal chars! + // TODO: Discuss where to place such a thing + + if (type instanceof ASTMCQualifiedType qualifiedType) { + return qualifiedType.getMCQualifiedName().getQName(); + } + else if (type instanceof ASTMCGenericType genericType) { + return genericType.printWithoutTypeArguments(); + } + else { + throw new IllegalStateException("Unhandled MCObjectType " + type.getClass() + " of `" + type + .printType() + "` when trying to resolve source"); + } + } + /** * Actual check that the enums interfaces are really interfaces. * From eacf390c2dd42e06b131bf8284571d15a995d896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:32:13 +0200 Subject: [PATCH 09/11] implDecorator args --- .../decorators/MethodImplementationDecorator.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/MethodImplementationDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/MethodImplementationDecorator.java index 70e8ae4df..f381f9a99 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/MethodImplementationDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/MethodImplementationDecorator.java @@ -29,11 +29,16 @@ public void visit(ASTCDMethod method) { } // TODO: ALu: Create shared get-marked value source (not only for stereotypes) - String template = method.getModifier().getStereotype().getValue("impl"); + + // TODO: Discuss if split via # or separate stereo is better for params? + String[] sp = method.getModifier().getStereotype().getValue("impl").split("#"); + String template = sp[0]; + Object[] templateParams = new Object[sp.length - 1]; + System.arraycopy(sp, 1, templateParams, 0, sp.length - 1); // And finally. replace the empty body template with the given template glexOpt.ifPresent(g -> g.replaceTemplate(CD4C.getInstance().getEmptyBodyTemplate(), - decoratorData.getAsDecorated(method), new TemplateHookPoint(template))); + decoratorData.getAsDecorated(method), new TemplateHookPoint(template, templateParams))); } } From c9b90028a3ce0f65ea66878a0318349cc9adc070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:32:31 +0200 Subject: [PATCH 10/11] fix visitor decorator for interfaces --- .../codegen/decorators/VisitorDecorator.java | 20 ++++++++--------- .../VisitorImplementationDecorator.java | 22 ++++++++++++++++++- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java index 80a4b44c9..bb185dd7e 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java @@ -11,8 +11,7 @@ import de.monticore.cd4codebasis._ast.ASTCDInterface; import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.cd4codebasis._ast.ASTCDParameter; -import de.monticore.cdbasis._ast.ASTCDClass; -import de.monticore.cdbasis._ast.ASTCDDefinition; +import de.monticore.cdbasis._ast.ASTCDType; import de.monticore.cdbasis._visitor.CDBasisVisitor2; import de.monticore.generating.templateengine.TemplateHookPoint; import de.monticore.types.MCTypeFacade; @@ -78,10 +77,10 @@ public void endVisit(ASTCDDefinition clazz) { } @Override - public void visit(ASTCDClass clazz) { - if (decoratorData.shouldDecorate(this.getClass(), clazz)) { - ASTCDClass decClazz = decoratorData.getAsDecorated(clazz); - String packageName = clazz.getSymbol().getPackageName(); + public void visit(ASTCDType type) { + if (decoratorData.shouldDecorate(this.getClass(), type)) { + ASTCDType decClazz = decoratorData.getAsDecorated(type); + String packageName = type.getSymbol().getPackageName(); ASTCDInterface visitorInterface = getVisitorInterface(); @@ -93,7 +92,7 @@ public void visit(ASTCDClass clazz) { ASTCDParameter visitorParameter = CD4CodeMill.cDParameterBuilder().setName("visitor") .setMCType(visitorInterfaceQualifiedType).build(); //create a type of the class - ASTMCType classType = MCTypeFacade.getInstance().createQualifiedType(clazz.getName()); + ASTMCType classType = MCTypeFacade.getInstance().createQualifiedType(type.getName()); ASTCDParameter classParameter = CD4CodeMill.cDParameterBuilder().setName("node").setMCType( classType).build(); @@ -104,8 +103,7 @@ public void visit(ASTCDClass clazz) { // add the interface methods to the pojo class addToClass(decClazz, acceptMethod); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, acceptMethod, - new TemplateHookPoint("methods.visitor.Accept", clazz.getName()))); - // new StringHookPoint("visitor.visit ((" + clazz.getName() + ")this);"))); + new TemplateHookPoint("methods.visitor.Accept", type.getName()))); CD4C.getInstance().addImport(decClazz, visitorInterfaceName); this.decParent.push(decClazz); @@ -118,13 +116,13 @@ public void visit(ASTCDClass clazz) { } @Override - public void endVisit(ASTCDClass clazz) { + public void endVisit(ASTCDType clazz) { if (decoratorData.shouldDecorate(this.getClass(), clazz)) { decParent.pop(); } } - protected Stack decParent = new Stack<>(); + protected Stack decParent = new Stack<>(); @Override public void addToTraverser(CD4CodeTraverser traverser) { diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorImplementationDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorImplementationDecorator.java index e94ac686a..9047a11dc 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorImplementationDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorImplementationDecorator.java @@ -9,8 +9,10 @@ import de.monticore.cd.facade.CDMethodFacade; import de.monticore.cd4code.CD4CodeMill; import de.monticore.cd4code._visitor.CD4CodeTraverser; +import de.monticore.cd4codebasis._ast.ASTCDInterface; import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cd4codebasis._visitor.CD4CodeBasisVisitor2; import de.monticore.cdbasis._ast.ASTCDAttribute; import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDDefinition; @@ -34,7 +36,7 @@ * Applies the Visitor-Pattern to the CD */ public class VisitorImplementationDecorator extends AbstractDecorator - implements CDBasisVisitor2 { + implements CDBasisVisitor2, CD4CodeBasisVisitor2 { protected GetterDecorator.GetterData getterData; @@ -217,12 +219,30 @@ public void endVisit(ASTCDClass clazz) { } } + @Override + public void visit(ASTCDInterface cdInterface) { + if (decoratorData.shouldDecorate(this.getClass(), cdInterface)) { + ASTMCType classType = MCTypeFacade.getInstance().createQualifiedType(cdInterface.getName()); + ASTCDParameter classParameter = CD4CodeMill.cDParameterBuilder().setName("node").setMCType( + classType).build(); + + // add visit method + ASTCDMethod visitMethod = CDMethodFacade.getInstance().createMethod(CD4CodeMill + .modifierBuilder().PUBLIC().build(), "visit", classParameter); + getVisitorImplementationClass().addCDMember(visitMethod); + glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, visitMethod, new TemplateHookPoint( + "methods.visitor.DefaultVisit", (Object) null))); + + } + } + protected Stack visitMethodStack = new Stack<>(); protected Stack decParent = new Stack<>(); @Override public void addToTraverser(CD4CodeTraverser traverser) { traverser.add4CDBasis(this); + traverser.add4CD4CodeBasis(this); } } From e3de4f51eaa03a0941ceaf0df3254553dfc9ed67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Mon, 7 Sep 2026 10:34:32 +0200 Subject: [PATCH 11/11] MCTypeFacade hotfix --- .../main/java/de/monticore/cd/codegen/DecoratorConfig.java | 2 +- .../main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java | 2 +- .../de/monticore/cd/codegen/decorators/GetterDecorator.java | 5 +++-- .../monticore/cd/codegen/decorators/ObserverDecorator.java | 3 ++- .../de/monticore/cd/codegen/decorators/VisitorDecorator.java | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java b/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java index 16b525552..b30a8c10f 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/DecoratorConfig.java @@ -95,7 +95,7 @@ public ChainableGenSetup withVisitorImplementations() { public ChainableGenSetup withMethodImplementations() { return this.withDecorator(new MethodImplementationDecorator()); } - + public ChainableGenSetup withRequiredArgsConstructors() { return this.withDecorator(new RequiredArgsConstructorDecorator()); } diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java b/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java index 6ae921e75..97d156d85 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/MCTypeFacadeFix.java @@ -9,7 +9,7 @@ import de.monticore.types.mccollectiontypes._ast.ASTMCSetType; import de.monticore.types.mcfullgenerictypes.MCFullGenericTypesMill; -// TODO: Move this fix upstream if MCFullGenericTypes (?) is initialized +// TODO: Move this fix upstream if MCFullGenericTypes (?) is initialized public class MCTypeFacadeFix { public static ASTMCListType createListTypeOf(final ASTMCType type) { diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java index 284aea2ce..525bfbf29 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/GetterDecorator.java @@ -3,6 +3,7 @@ import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import de.monticore.cd.codegen.MCTypeFacadeFix; import de.monticore.cd.codegen.decorators.data.AbstractDecorator; import de.monticore.cd.codegen.decorators.data.DecoratorData; import de.monticore.cd.facade.CDMethodFacade; @@ -130,7 +131,7 @@ protected MethodInformation decorateSet(ASTCDType decoratedType, ASTCDAttribute ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone(); ASTCDMethod getListMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), MCTypeFacade.getInstance().createSetTypeOf(type), name); + .deepClone(), MCTypeFacadeFix.createSetTypeOf(type), name); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, getListMethod, new TemplateHookPoint( "methods.Get", attribute))); getListMethod.getModifier().setAbstract(attribute.getModifier().isDerived()); @@ -147,7 +148,7 @@ protected MethodInformation decorateList(ASTCDType decoratedType, ASTCDAttribute ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone(); ASTCDMethod getListMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier() - .deepClone(), MCTypeFacade.getInstance().createListTypeOf(type), name); + .deepClone(), MCTypeFacadeFix.createListTypeOf(type), name); glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, getListMethod, new TemplateHookPoint( "methods.Get", attribute))); getListMethod.getModifier().setAbstract(attribute.getModifier().isDerived()); diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/ObserverDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/ObserverDecorator.java index f678c9de4..eaf1ec9fc 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/ObserverDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/ObserverDecorator.java @@ -3,6 +3,7 @@ import com.google.common.collect.Iterables; import de.monticore.ast.ASTNode; +import de.monticore.cd.codegen.MCTypeFacadeFix; import de.monticore.cd.codegen.decorators.data.AbstractDecorator; import de.monticore.cd.facade.CDMethodFacade; import de.monticore.cd.facade.CDParameterFacade; @@ -72,7 +73,7 @@ public void visit(ASTCDClass clazz) { { //create an attribute of the type and the name of an observer ASTCDAttribute observerList = CD4CodeMill.cDAttributeBuilder().setName(OBS_LIST_ATTR) - .setMCType(MCTypeFacade.getInstance().createListTypeOf(observerInterfaceQualifiedType)) + .setMCType(MCTypeFacadeFix.createListTypeOf(observerInterfaceQualifiedType)) .setModifier(CD4CodeMill.modifierBuilder().PROTECTED().build()).build(); decClazz.addCDMember(observerList); diff --git a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java index bb185dd7e..988d735ba 100644 --- a/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java +++ b/cdlang/src/main/java/de/monticore/cd/codegen/decorators/VisitorDecorator.java @@ -11,6 +11,7 @@ import de.monticore.cd4codebasis._ast.ASTCDInterface; import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.ASTCDDefinition; import de.monticore.cdbasis._ast.ASTCDType; import de.monticore.cdbasis._visitor.CDBasisVisitor2; import de.monticore.generating.templateengine.TemplateHookPoint;