From 47597d371947303aa1737fd55111bf33d99ffec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Wed, 12 Aug 2026 10:25:58 +0200 Subject: [PATCH 1/2] Prepare CDGeneratorTool for removal --- .../java/de/monticore/CDGeneratorTool.java | 2 +- .../java/de/monticore/cdgen/CDGenTool.java | 261 +++++++++++++----- .../de/monticore/CDGeneratorToolTest.java | 44 +-- 3 files changed, 215 insertions(+), 92 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/CDGeneratorTool.java b/cdlang/src/main/java/de/monticore/CDGeneratorTool.java index 356bfa7f9..d6c0bec73 100644 --- a/cdlang/src/main/java/de/monticore/CDGeneratorTool.java +++ b/cdlang/src/main/java/de/monticore/CDGeneratorTool.java @@ -62,7 +62,7 @@ * This class is scheduled for removal/replacement by the decorating {@link * de.monticore.cdgen.CDGenTool} */ -@Deprecated +@Deprecated(forRemoval = true) public class CDGeneratorTool extends CD4CodeTool { /** diff --git a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java index 7daa5c494..8ceadaca9 100644 --- a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java +++ b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java @@ -1,7 +1,6 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.cdgen; -import de.monticore.CDGeneratorTool; import de.monticore.cd.codegen.CDGenService; import de.monticore.cd.codegen.CDGenerator; import de.monticore.cd.codegen.CdUtilsPrinter; @@ -13,42 +12,51 @@ import de.monticore.cd4analysis.trafo.CDAssociationCreateFieldsFromAllRoles; import de.monticore.cd4analysis.trafo.CDAssociationCreateFieldsFromNavigableRoles; import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cd4code.CD4CodeTool; +import de.monticore.cd4code._cocos.CD4CodeCoCoChecker; +import de.monticore.cd4code._symboltable.CD4CodeScopesGenitorDelegatorTOP; +import de.monticore.cd4code._symboltable.CD4CodeSymbolTableCompleter; import de.monticore.cd4code._symboltable.ICD4CodeArtifactScope; import de.monticore.cd4code._visitor.CD4CodeTraverser; +import de.monticore.cd4code.cocos.CD4CodeCoCosDelegator; +import de.monticore.cd4code.trafo.CD4CodeAfterParseTrafo; import de.monticore.cdbasis.CDBasisMill; import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.cdbasis.trafo.CDBasisDefaultPackageTrafo; import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import de.monticore.class2mc.OOClass2MCResolver; import de.monticore.generating.GeneratorSetup; -import de.monticore.generating.templateengine.GlobalExtensionManagement; -import de.monticore.generating.templateengine.TemplateController; -import de.monticore.generating.templateengine.TemplateHookPoint; +import de.monticore.generating.templateengine.*; import de.monticore.io.paths.MCPath; import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symboltable.ImportStatement; import de.monticore.types.MCTypeFacade; import de.monticore.types.mcbasictypes._ast.ASTMCImportStatement; import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; import de.se_rwth.commons.Names; import de.se_rwth.commons.logging.Log; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.function.Consumer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.cli.*; /** - * This class is a further development of the {@link CDGeneratorTool} and meant as a replacement. It - * provides configurable decorator functionality in addition to generation. This tool is tested via + * This tool provides configurable decorator functionality in addition to generation. This tool is + * tested via * the CDGenGradlePluginTest: * cdtool/cdgradle/src/test/java/de/monticore/cdgen/CDGenGradlePluginTest.java */ -public class CDGenTool extends CDGeneratorTool { - +public class CDGenTool extends CD4CodeTool { + /** * Gradle main method of the CDGenTool * @@ -58,7 +66,7 @@ public static void gradleMain(String[] args) { CDGenTool tool = new CDGenTool(); tool.run(args); } - + /** * main method of the CDGenTool * @@ -66,10 +74,20 @@ public static void gradleMain(String[] args) { */ public static void main(String[] args) { Log.init(); - CDGenTool tool = new CDGenTool(); - tool.run(args); + try { + CD4CodeTool tool = new CDGenTool(); + tool.run(args); + } + catch (Exception exception) { + // ensure a sane exit + Log.error("0xEEEEE an internal error occurred" + " during the execution of the CD4CodeTool." + + System.lineSeparator() + "This error is unexpected" + + " and does not indicate an issue with any provided models.", exception); + } + // properly exit with a code + System.exit(Log.getErrorCount() == 0 ? 0 : 1); } - + /** * executes the arguments stated in the command line like parsing a given model to an ast, * creating and printing out a corresponding symbol table, checking cocos or generating java files @@ -80,13 +98,13 @@ public static void main(String[] args) { public void run(String[] args) { CD4CodeMill.reset(); CD4CodeMill.init(); - + Options options = initOptions(); - + try { CommandLineParser cliParser = new DefaultParser(); CommandLine cmd = cliParser.parse(options, args); - + if (cmd.hasOption("v")) { printVersion(); // do not continue when version is printed @@ -96,31 +114,31 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { printHelp(options); return; } - + final boolean c2mc = cmd.hasOption("c2mc"); - + initializeSymbolTable(c2mc); - + Log.enableFailQuick(false); Collection asts = this.parse(".cd", this.createModelPath(cmd) .getEntries()); Log.enableFailQuick(true); - + // Run CoCos if (cmd.hasOption("c")) { Log.enableFailQuick(false); asts.forEach(this::runBeforeSTCoCos); Log.enableFailQuick(true); } - + // apply trafos needed for symbol table creation asts = this.trafoBeforeSymtab(asts); - + if (cmd.hasOption("path")) { String[] paths = splitPathEntries(cmd.getOptionValues("path")); CD4CodeMill.globalScope().setSymbolPath(new MCPath(paths)); } - + // Create the symbol-table (symbol table creation phase 1) List scopes = new ArrayList<>(asts.size()); for (ASTCDCompilationUnit ast : asts) { @@ -128,28 +146,28 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { scopes.add(this.createSymbolTable(ast, c2mc)); Log.enableFailQuick(true); } - + // Complete the symbol-table (symbol table creation phase 2) for (ASTCDCompilationUnit ast : asts) { Log.enableFailQuick(false); // ST completition might report multiple errors this.completeSymbolTable(ast); Log.enableFailQuick(true); } - + // Run CoCos if (cmd.hasOption("c")) { Log.enableFailQuick(false); asts.forEach(this::runCoCos); Log.enableFailQuick(true); } - + // Export original symbol table if (cmd.hasOption("s")) { for (ICD4CodeArtifactScope scope : scopes) { this.storeSymTab(scope, cmd.getOptionValue("s")); } } - + if (cmd.hasOption("o")) { // Where to load additional templates from List additionalTemplatePaths = cmd.hasOption("fp") ? Arrays.stream(cmd @@ -161,11 +179,11 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { // output directory String outputPath = (cmd.hasOption("o")) ? Paths.get(cmd.getOptionValue("o")).toString() : ""; - + GlobalExtensionManagement glex = new GlobalExtensionManagement(); GeneratorSetup generatorSetup = newConfiguredGeneratorSetup(additionalTemplatePaths, handcodedPath, outputPath, glex); - + // Finally, invoke the decorating generator decorateAndGenerate(glex, // Initialize the decorator config @@ -191,11 +209,11 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { } CD4CodeMill.globalScope().clear(); } - + public void initializeSymbolTable(boolean c2mc) { BasicSymbolsMill.initializePrimitives(); MCCollectionSymTypeRelations.init(); - + if (c2mc) { initializeClass2MC(); } @@ -204,7 +222,12 @@ public void initializeSymbolTable(boolean c2mc) { 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 @@ -220,7 +243,7 @@ public void initializeDecConf(GlobalExtensionManagement glex, DecoratorConfig de TemplateHookPoint hpp = new TemplateHookPoint(configTemplate); hpp.processValue(tc, new ArrayList<>()); } - + public void decorateAndGenerate(GlobalExtensionManagement glex, Consumer initializeDecConf, GeneratorSetup setup, Runnable initDecoratedGlobalScope, Consumer postDecorate, @@ -229,41 +252,41 @@ public void decorateAndGenerate(GlobalExtensionManagement glex, glex.setGlobalValue("mcTypeFacade", MCTypeFacade.getInstance()); // TODO: Remove from templates glex.setGlobalValue("cdGenService", new CDGenService()); glex.setGlobalValue("cd4AnalysisTypeDispatcher", new CD4AnalysisTypeDispatcher()); // TODO: Remove from templates - + CDGenerator generator = new CDGenerator(setup); DecoratorConfig decSetup = new DecoratorConfig(); - + CDAssociationCreateFieldsFromAllRoles roleTrafo = performFieldsFromRolesTrafo(asts); - + // Load the initial decorator config initializeDecConf.accept(decSetup); - + // e.g., prepare the global scope for decorated symbol table initDecoratedGlobalScope.run(); - + for (ASTCDCompilationUnit ast : asts) { var decorated = decSetup.decorate(ast, roleTrafo.getFieldToRoles(), Optional.of(glex)); - + if (decorated.isEmpty()) { Log.error("0xCDD12: Failed generation for " + ast.getCDDefinition().getName()); continue; } - + // Post-Decorate: apply trafos needed for code generation CD4CodeTraverser t = CD4CodeMill.inheritanceTraverser(); t.add4CDBasis(new CDBasisDefaultPackageTrafo()); decorated.get().accept(t); // Post-Decorate: map import statements to classes this.mapCD4CImports(decorated.get()); - + // The following imports (cf. Imports.ftl) have to be added decorated.get().addMCImportStatement(CDBasisMill.mCImportStatementBuilder() .setMCQualifiedName(MCTypeFacade.getInstance().createQualifiedName("java.util")).setStar( true).build()); - + // If required, we can also output the symbol table of the *decorated* AST postDecorate.accept(decorated.get()); - + // Post-Decorate: TOP Decorator // TODO: #4310 - make this TOP transformation configurable via the config // template @@ -273,23 +296,23 @@ public void decorateAndGenerate(GlobalExtensionManagement glex, t = CD4CodeMill.inheritanceTraverser(); topTransformer.addToTraverser(t); decorated.get().accept(t); - + generator.generate(decorated.get()); Log.enableFailQuick(qf); // reset quick-fail } } - + public GeneratorSetup newConfiguredGeneratorSetup(List additionalTemplatePaths, Optional handcodedPath, String outputPath, GlobalExtensionManagement glex) { GeneratorSetup setup = new GeneratorSetup(); - + setup.setAdditionalTemplatePaths(additionalTemplatePaths); handcodedPath.ifPresent(setup::setHandcodedPath); setup.setGlex(glex); setup.setOutputDirectory(new File(outputPath)); return setup; } - + public CDAssociationCreateFieldsFromAllRoles performFieldsFromRolesTrafo( Collection asts) { CDAssociationCreateFieldsFromAllRoles roleTrafo = @@ -300,7 +323,7 @@ public CDAssociationCreateFieldsFromAllRoles performFieldsFromRolesTrafo( asts.forEach(roleTrafo::transform); return roleTrafo; } - + /** * Without Class2MC, we have to load symbols used in the generated CD * @@ -319,13 +342,13 @@ public void initDecoratedGlobalScope(boolean c2mc) { registerFakeType("ICDObserver", "de.monticore.cd.ICDObserver"); } } - + protected void registerFakeType(String simplename, String fullName) { CDBasisMill.globalScope().add(CDBasisMill.typeSymbolBuilder().setName(simplename).setFullName( fullName).setSpannedScope(CDBasisMill.scope()).setEnclosingScope(CDBasisMill.globalScope()) .build()); } - + /** * Create, complete, and export the symbol table of a decorated CD * @@ -336,50 +359,50 @@ public void createAndExportDecoratedSymbolTable(ASTCDCompilationUnit decorated, String symbolOutPath) { // Create the symbol-table (symbol table creation phase 1) var decoratedScope = this.createSymbolTable(decorated, true); - + // Complete the symbol-table (symbol table creation phase 2) this.completeSymbolTable(decorated); - + // Store the decorated symbol table this.storeSymbols(decoratedScope, Paths.get(symbolOutPath, Names.getPathFromPackage( decoratedScope.getFullName()) + ".deccdsym").toString()); } - + /** * adds additional options to the cli tool * * @param options collection of all the possible options */ public Options addAdditionalOptions(Options options) { - + options.addOption(Option.builder("c").longOpt("checkcococs").desc( "Checks all CoCos on the given mode.").build()); - + options.addOption(Option.builder("o").longOpt("output").argName("dir").hasArg().desc( "Sets the output path.").build()); - + options.addOption(Option.builder("ct").longOpt("configtemplate").hasArg().argName("template") .desc("Sets a template for configuration.").build()); - + options.addOption(Option.builder("fp").longOpt("template").hasArg().argName("path").desc( "Sets the path for additional templates.").build()); - + options.addOption(Option.builder("hwc").longOpt("handwrittencode").hasArg().argName("hwcpath") .desc("Sets the path for additional, handwritten classes.").build()); - + options.addOption(Option.builder("c2mc").longOpt("class2mc").desc( "Enables to resolve java classes in the model path").build()); - + options.addOption(Option.builder("cliconfig").desc("Configures additional").hasArgs().argName( "fqn:key[=value]").build()); - + options.addOption(org.apache.commons.cli.Option.builder("sd").longOpt("symboltabledecorated") .argName("file").hasArg().desc( "Serializes the decorated symbol table of the given artifact.").build()); - + return options; } - + /** * checks all cocos on the original ast before the symbol table is created * @@ -388,26 +411,27 @@ public Options addAdditionalOptions(Options options) { public void runBeforeSTCoCos(ASTCDCompilationUnit ast) { // Nothing yet, decide how we expose them } - + /** * checks all cocos on the original ast * * @param ast the original ast */ public void runCoCos(ASTCDCompilationUnit ast) { - super.runCoCos(ast); + CD4CodeCoCoChecker checker = new CD4CodeCoCosDelegator().getCheckerForAllCoCos(); + checker.checkAll(ast); } - - @Override + public Collection trafoBeforeSymtab(Collection asts) { - super.trafoBeforeSymtab(asts); + CD4CodeAfterParseTrafo trafo = new CD4CodeAfterParseTrafo(); + asts.forEach(ast -> ast.accept(trafo.getTraverser())); // TODO: Have this be done via the config-options (#4310) var t = CD4CodeMill.inheritanceTraverser(); t.add4UMLModifier(new DefaultVisibilityPublicTrafo()); asts.forEach(ast -> ast.accept(t)); return asts; } - + /** * Updates the map of cd types to import statement in the given cd4c object, adding the imports * for each cd type (classes, enums, and interfaces) defined in the given ast. @@ -417,7 +441,7 @@ public Collection trafoBeforeSymtab(Collection imports = ast.getMCImportStatementList(); - + for (ASTCDClass cdClass : ast.getCDDefinition().getCDClassesList()) { for (ASTMCImportStatement i : imports) { String qName = i.getQName(); @@ -437,5 +461,102 @@ public void mapCD4CImports(ASTCDCompilationUnit ast) { } } } - + + public MCPath createModelPath(CommandLine cl) { + if (cl.hasOption("i")) { + return new MCPath(splitPathEntries(cl.getOptionValues("i"))); + } + else { + return new MCPath(); + } + } + + public String[] splitPathEntries(String composedPath) { + Objects.requireNonNull(composedPath); + + return composedPath.split(Pattern.quote(File.pathSeparator)); + } + + public final String[] splitPathEntries(String[] composedPaths) { + Objects.requireNonNull(composedPaths); + return Arrays.stream(composedPaths).map(this::splitPathEntries).flatMap(Arrays::stream).toArray( + String[]::new); + } + + public Collection parse(String fileExt, Collection filesAndDirs) { + return filesAndDirs.stream().flatMap(dirOrFile -> this.parse(fileExt, dirOrFile).stream()) + .collect(Collectors.toList()); + } + + /** + * Parses all class diagrams in the given path. + * In case the path is a file, the file is parsed regardless of its extension + * Otherwise, all files within the path-directory are parsed if their extension matches + * + * @param fileExt recursively parses all files with this extension in a directory + * @param fileOrDir directory or file + * @return a collection of nested files + */ + public Collection parse(String fileExt, Path fileOrDir) { + if (Files.isRegularFile(fileOrDir)) { + // In case a file is within the ModelPath: parse the file + return Collections.singleton(this.parse(fileOrDir.toString())); + } + // Otherwise: Traverse the directory & parse all matching files + try ( + Stream paths = Files.walk(fileOrDir) + ) { + return paths.filter(Files::isRegularFile).filter(file -> file.getFileName().toString() + .endsWith(fileExt)).map(Path::toString).map(this::parse).collect(Collectors.toSet()); + } + catch (IOException e) { + Log.error("0xA1063 Error while traversing the file structure `" + fileOrDir + "`.", e); + } + return Collections.emptySet(); + } + + /** + * creates the symboltable for the given ast + * + * @param ast the input ast + * @param java whether to add java default imports + * @return the symbol-table of the ast + */ + public ICD4CodeArtifactScope createSymbolTable(ASTCDCompilationUnit ast, boolean java) { + CD4CodeScopesGenitorDelegatorTOP genitor = CD4CodeMill.scopesGenitorDelegator(); + ICD4CodeArtifactScope scope = genitor.createFromAST(ast); + this.addDefaultImports(scope, java); + return scope; + } + + public void addDefaultImports(ICD4CodeArtifactScope scope, boolean java) { + if (java) + scope.addImports(new ImportStatement("java.lang", true)); + } + + /** + * prints the symboltable of the given scope out to a file + * + * @param scope symboltable to store + * @param path location of the file or directory containing the printed table + */ + public void storeSymTab(ICD4CodeArtifactScope scope, String path) { + if (Path.of(path).toFile().isFile()) { + this.storeSymbols(scope, path); + } + else { + this.storeSymbols(scope, Paths.get(path, Names.getPathFromPackage(scope.getFullName()) + + ".cdsym").toString()); + } + } + + /** + * completes the symboltable for the given ast + * + * @param ast the input ast + */ + public void completeSymbolTable(ASTCDCompilationUnit ast) { + ast.accept(new CD4CodeSymbolTableCompleter(ast).getTraverser()); + } + } diff --git a/cdlang/src/test/java/de/monticore/CDGeneratorToolTest.java b/cdlang/src/test/java/de/monticore/CDGeneratorToolTest.java index 5347bf94b..5320fb61d 100644 --- a/cdlang/src/test/java/de/monticore/CDGeneratorToolTest.java +++ b/cdlang/src/test/java/de/monticore/CDGeneratorToolTest.java @@ -7,6 +7,8 @@ import de.monticore.cd4code.CD4CodeMill; import de.monticore.cd4code._symboltable.CD4CodeSymbols2Json; import de.monticore.cd4code._symboltable.ICD4CodeArtifactScope; +import de.monticore.cdgen.CDGenTool; +import de.monticore.runtime.junit.MCAssertions; import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.se_rwth.commons.logging.LogStub; import java.io.File; @@ -16,6 +18,7 @@ import java.nio.file.Paths; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class CDGeneratorToolTest { @@ -30,14 +33,13 @@ public void before() { @Test public void testGeneratorToolWithCoCos() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-c" }); - assertTrue(true); } @Test public void testGeneratorToolWithSymbolTable() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-s", "target/generated/example/symboltable" }); assertTrue(new File("target/generated/example/symboltable/model/Example.cdsym").isFile()); @@ -45,7 +47,7 @@ public void testGeneratorToolWithSymbolTable() { @Test public void testGeneratorToolWithJavaGeneration() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-o", "target/generated/example/standard", }); assertTrue(new File("target/generated/example/standard/model/Example/A.java").isFile()); @@ -53,7 +55,7 @@ public void testGeneratorToolWithJavaGeneration() { @Test public void testGeneratorToolWithEmptyCDWithPackage() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/EmptyWithPackage.cd", "-c2mc", "-o", "target/generated/example/standard", }); @@ -63,23 +65,25 @@ public void testGeneratorToolWithEmptyCDWithPackage() { @Test public void testGeneratorToolWithEmptyCDWithoutPackage() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/EmptyWithoutPackage.cd", "-c2mc", "-o", "target/generated/example/standard", }); assertTrue(new File("target/generated/example/standard/EmptyWithoutPackage").isDirectory()); } @Test + @Disabled // The new generator has a different configTemplate opinion public void testGeneratorToolWithCustomGeneratorTemplate() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-o", "target/generated/example/ct", "-ct", "de.monticore.cdgentool.NewCustomTemplate" }); assertTrue(new File("target/generated/example/ct/model/Example/A.java").isFile()); } @Test + @Disabled // New generator has a different CLI options public void testGeneratorToolWithAdditionalTemplates() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-o", "target/generated/example/tp", "-tp", "src/test/resources/de/monticore/cdgentool/templates" }); @@ -88,7 +92,7 @@ public void testGeneratorToolWithAdditionalTemplates() { @Test public void testGeneratorToolWithHWC() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-o", "target/generated/example/hwc", "-hwc", "src/test/resources/de/monticore/cdgentool/hwc" }); assertTrue(new File("target/generated/example/hwc/model/Example/ATOP.java").isFile()); @@ -96,20 +100,18 @@ public void testGeneratorToolWithHWC() { @Test public void testToolPrintHelpOptions() { - CDGeneratorTool.main(new String[] { "-h" }); - assertTrue(true); + new CDGenTool().run(new String[] { "-h" }); } @Test public void testToolPrintVersion() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-v" }); - assertTrue(true); } @Test public void testGeneratorToolWithPkgSymTab() throws IOException { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/pkg/ExampleWithPkg.cd", "-c2mc", "-o", "target/generated/example/examplewithpkg", "-s", "target/generated/example/examplewithpkg" }); @@ -120,8 +122,9 @@ public void testGeneratorToolWithPkgSymTab() throws IOException { } @Test + @Disabled // The new generated uses a different set of decorators public void testDefaultConstructorDecorator() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-o", "target/generated/example/defaultctor", "-ct", "de.monticore.cdgentool.DefaultCtorTemplate", }); @@ -131,21 +134,20 @@ public void testDefaultConstructorDecorator() { @Test public void testImportStatements() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-o", "target/generated/example/imports", "-c2mc", "-s", "target/generated/example/imports/" }); - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/ImportTest.cd", "-o", "target/generated/example/imports", "-c2mc", "-path", "target/generated/example/imports/" }); - - assertTrue(true); } @Test + @Disabled // The new generator does not have a "fieldfromrole" option public void testAttributesForAssociations() { - CDGeneratorTool.main(new String[] { "-i", + new CDGenTool().run(new String[] { "-i", "src/test/resources/de/monticore/cdgentool/model/Example.cd", "-c2mc", "-s", "target/generated/example/rolefield/", "-fieldfromrole", "navigable" }); File symtab = new File("target/generated/example/rolefield/model/Example.cdsym"); @@ -159,8 +161,8 @@ public void testAttributesForAssociations() { @AfterEach public void after() { + MCAssertions.assertNoFindings(); CD4CodeMill.globalScope().clear(); - assertTrue(LogStub.getFindings().isEmpty()); } } From ae90c133789140f581750ab754d9395d04f0eb9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Wed, 12 Aug 2026 10:46:57 +0200 Subject: [PATCH 2/2] fmt --- .../java/de/monticore/cdgen/CDGenTool.java | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java index 1b7db8e95..f101af407 100644 --- a/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java +++ b/cdlang/src/main/java/de/monticore/cdgen/CDGenTool.java @@ -58,7 +58,7 @@ * cdtool/cdgradle/src/test/java/de/monticore/cdgen/CDGenGradlePluginTest.java */ public class CDGenTool extends CD4CodeTool { - + /** * Gradle main method of the CDGenTool * @@ -68,7 +68,7 @@ public static void gradleMain(String[] args) { CDGenTool tool = new CDGenTool(); tool.run(args); } - + /** * main method of the CDGenTool * @@ -89,7 +89,7 @@ public static void main(String[] args) { // properly exit with a code System.exit(Log.getErrorCount() == 0 ? 0 : 1); } - + /** * executes the arguments stated in the command line like parsing a given model to an ast, * creating and printing out a corresponding symbol table, checking cocos or generating java files @@ -100,13 +100,13 @@ public static void main(String[] args) { public void run(String[] args) { CD4CodeMill.reset(); CD4CodeMill.init(); - + Options options = initOptions(); - + try { CommandLineParser cliParser = new DefaultParser(); CommandLine cmd = cliParser.parse(options, args); - + if (cmd.hasOption("v")) { printVersion(); // do not continue when version is printed @@ -116,31 +116,31 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { printHelp(options); return; } - + final boolean c2mc = cmd.hasOption("c2mc"); - + initializeSymbolTable(c2mc); - + Log.enableFailQuick(false); Collection asts = this.parse(".cd", this.createModelPath(cmd) .getEntries()); Log.enableFailQuick(true); - + // Run CoCos if (cmd.hasOption("c")) { Log.enableFailQuick(false); asts.forEach(this::runBeforeSTCoCos); Log.enableFailQuick(true); } - + // apply trafos needed for symbol table creation asts = this.trafoBeforeSymtab(asts); - + if (cmd.hasOption("path")) { String[] paths = splitPathEntries(cmd.getOptionValues("path")); CD4CodeMill.globalScope().setSymbolPath(new MCPath(paths)); } - + // Create the symbol-table (symbol table creation phase 1) List scopes = new ArrayList<>(asts.size()); for (ASTCDCompilationUnit ast : asts) { @@ -148,28 +148,28 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { scopes.add(this.createSymbolTable(ast, c2mc)); Log.enableFailQuick(true); } - + // Complete the symbol-table (symbol table creation phase 2) for (ASTCDCompilationUnit ast : asts) { Log.enableFailQuick(false); // ST completition might report multiple errors this.completeSymbolTable(ast); Log.enableFailQuick(true); } - + // Run CoCos if (cmd.hasOption("c")) { Log.enableFailQuick(false); asts.forEach(this::runCoCos); Log.enableFailQuick(true); } - + // Export original symbol table if (cmd.hasOption("s")) { for (ICD4CodeArtifactScope scope : scopes) { this.storeSymTab(scope, cmd.getOptionValue("s")); } } - + if (cmd.hasOption("o")) { // Where to load additional templates from List additionalTemplatePaths = cmd.hasOption("fp") ? Arrays.stream(cmd @@ -181,11 +181,11 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { // output directory String outputPath = (cmd.hasOption("o")) ? Paths.get(cmd.getOptionValue("o")).toString() : ""; - + GlobalExtensionManagement glex = new GlobalExtensionManagement(); GeneratorSetup generatorSetup = newConfiguredGeneratorSetup(additionalTemplatePaths, handcodedPath, outputPath, glex); - + // Finally, invoke the decorating generator decorateAndGenerate(glex, // Initialize the decorator config @@ -211,11 +211,11 @@ else if (!cmd.hasOption("i") || cmd.hasOption("h")) { } CD4CodeMill.globalScope().clear(); } - + public void initializeSymbolTable(boolean c2mc) { BasicSymbolsMill.initializePrimitives(); MCCollectionSymTypeRelations.init(); - + if (c2mc) { initializeClass2MC(); } @@ -224,12 +224,12 @@ public void initializeSymbolTable(boolean c2mc) { 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 @@ -245,7 +245,7 @@ public void initializeDecConf(GlobalExtensionManagement glex, DecoratorConfig de TemplateHookPoint hpp = new TemplateHookPoint(configTemplate); hpp.processValue(tc, new ArrayList<>()); } - + public void decorateAndGenerate(GlobalExtensionManagement glex, Consumer initializeDecConf, GeneratorSetup setup, Runnable initDecoratedGlobalScope, Consumer postDecorate, @@ -254,41 +254,41 @@ public void decorateAndGenerate(GlobalExtensionManagement glex, glex.setGlobalValue("mcTypeFacade", MCTypeFacade.getInstance()); // TODO: Remove from templates glex.setGlobalValue("cdGenService", new CDGenService()); glex.setGlobalValue("cd4AnalysisTypeDispatcher", new CD4AnalysisTypeDispatcher()); // TODO: Remove from templates - + CDGenerator generator = new CDGenerator(setup); DecoratorConfig decSetup = new DecoratorConfig(); - + CDAssociationCreateFieldsFromAllRoles roleTrafo = performFieldsFromRolesTrafo(asts); - + // Load the initial decorator config initializeDecConf.accept(decSetup); - + // e.g., prepare the global scope for decorated symbol table initDecoratedGlobalScope.run(); - + for (ASTCDCompilationUnit ast : asts) { var decorated = decSetup.decorate(ast, roleTrafo.getFieldToRoles(), Optional.of(glex)); - + if (decorated.isEmpty()) { Log.error("0xCDD12: Failed generation for " + ast.getCDDefinition().getName()); continue; } - + // Post-Decorate: apply trafos needed for code generation CD4CodeTraverser t = CD4CodeMill.inheritanceTraverser(); t.add4CDBasis(new CDBasisDefaultPackageTrafo()); decorated.get().accept(t); // Post-Decorate: map import statements to classes this.mapCD4CImports(decorated.get()); - + // The following imports (cf. Imports.ftl) have to be added decorated.get().addMCImportStatement(CDBasisMill.mCImportStatementBuilder() .setMCQualifiedName(MCTypeFacade.getInstance().createQualifiedName("java.util")).setStar( true).build()); - + // If required, we can also output the symbol table of the *decorated* AST postDecorate.accept(decorated.get()); - + // Post-Decorate: TOP Decorator // TODO: #4310 - make this TOP transformation configurable via the config // template @@ -298,23 +298,23 @@ public void decorateAndGenerate(GlobalExtensionManagement glex, t = CD4CodeMill.inheritanceTraverser(); topTransformer.addToTraverser(t); decorated.get().accept(t); - + generator.generate(decorated.get()); Log.enableFailQuick(qf); // reset quick-fail } } - + public GeneratorSetup newConfiguredGeneratorSetup(List additionalTemplatePaths, Optional handcodedPath, String outputPath, GlobalExtensionManagement glex) { GeneratorSetup setup = new GeneratorSetup(); - + setup.setAdditionalTemplatePaths(additionalTemplatePaths); handcodedPath.ifPresent(setup::setHandcodedPath); setup.setGlex(glex); setup.setOutputDirectory(new File(outputPath)); return setup; } - + public CDAssociationCreateFieldsFromAllRoles performFieldsFromRolesTrafo( Collection asts) { CDAssociationCreateFieldsFromAllRoles roleTrafo = @@ -325,7 +325,7 @@ public CDAssociationCreateFieldsFromAllRoles performFieldsFromRolesTrafo( asts.forEach(roleTrafo::transform); return roleTrafo; } - + /** * Without Class2MC, we have to load symbols used in the generated CD * @@ -344,13 +344,13 @@ public void initDecoratedGlobalScope(boolean c2mc) { registerFakeType("ICDObserver", "de.monticore.cd.ICDObserver"); } } - + protected void registerFakeType(String simplename, String fullName) { CDBasisMill.globalScope().add(CDBasisMill.typeSymbolBuilder().setName(simplename).setFullName( fullName).setSpannedScope(CDBasisMill.scope()).setEnclosingScope(CDBasisMill.globalScope()) .build()); } - + /** * Create, complete, and export the symbol table of a decorated CD * @@ -361,50 +361,50 @@ public void createAndExportDecoratedSymbolTable(ASTCDCompilationUnit decorated, String symbolOutPath) { // Create the symbol-table (symbol table creation phase 1) var decoratedScope = this.createSymbolTable(decorated, true); - + // Complete the symbol-table (symbol table creation phase 2) this.completeSymbolTable(decorated); - + // Store the decorated symbol table this.storeSymbols(decoratedScope, Paths.get(symbolOutPath, Names.getPathFromPackage( decoratedScope.getFullName()) + ".deccdsym").toString()); } - + /** * adds additional options to the cli tool * * @param options collection of all the possible options */ public Options addAdditionalOptions(Options options) { - + options.addOption(Option.builder("c").longOpt("checkcococs").desc( "Checks all CoCos on the given mode.").build()); - + options.addOption(Option.builder("o").longOpt("output").argName("dir").hasArg().desc( "Sets the output path.").build()); - + options.addOption(Option.builder("ct").longOpt("configtemplate").hasArg().argName("template") .desc("Sets a template for configuration.").build()); - + options.addOption(Option.builder("fp").longOpt("template").hasArg().argName("path").desc( "Sets the path for additional templates.").build()); - + options.addOption(Option.builder("hwc").longOpt("handwrittencode").hasArg().argName("hwcpath") .desc("Sets the path for additional, handwritten classes.").build()); - + options.addOption(Option.builder("c2mc").longOpt("class2mc").desc( "Enables to resolve java classes in the model path").build()); - + options.addOption(Option.builder("cliconfig").desc("Configures additional").hasArgs().argName( "fqn:key[=value]").build()); - + options.addOption(org.apache.commons.cli.Option.builder("sd").longOpt("symboltabledecorated") .argName("file").hasArg().desc( "Serializes the decorated symbol table of the given artifact.").build()); - + return options; } - + /** * checks all cocos on the original ast before the symbol table is created * @@ -413,7 +413,7 @@ public Options addAdditionalOptions(Options options) { public void runBeforeSTCoCos(ASTCDCompilationUnit ast) { // Nothing yet, decide how we expose them } - + /** * checks all cocos on the original ast * @@ -423,7 +423,7 @@ public void runCoCos(ASTCDCompilationUnit ast) { CD4CodeCoCoChecker checker = new CD4CodeCoCosDelegator().getCheckerForAllCoCos(); checker.checkAll(ast); } - + public Collection trafoBeforeSymtab(Collection asts) { CD4CodeAfterParseTrafo trafo = new CD4CodeAfterParseTrafo(); asts.forEach(ast -> ast.accept(trafo.getTraverser())); @@ -433,7 +433,7 @@ public Collection trafoBeforeSymtab(Collection ast.accept(t)); return asts; } - + /** * Updates the map of cd types to import statement in the given cd4c object, adding the imports * for each cd type (classes, enums, and interfaces) defined in the given ast. @@ -443,7 +443,7 @@ public Collection trafoBeforeSymtab(Collection imports = ast.getMCImportStatementList(); - + for (ASTCDClass cdClass : ast.getCDDefinition().getCDClassesList()) { for (ASTMCImportStatement i : imports) { String qName = i.getQName(); @@ -463,7 +463,7 @@ public void mapCD4CImports(ASTCDCompilationUnit ast) { } } } - + public MCPath createModelPath(CommandLine cl) { if (cl.hasOption("i")) { return new MCPath(splitPathEntries(cl.getOptionValues("i"))); @@ -472,24 +472,24 @@ public MCPath createModelPath(CommandLine cl) { return new MCPath(); } } - + public String[] splitPathEntries(String composedPath) { Objects.requireNonNull(composedPath); - + return composedPath.split(Pattern.quote(File.pathSeparator)); } - + public final String[] splitPathEntries(String[] composedPaths) { Objects.requireNonNull(composedPaths); return Arrays.stream(composedPaths).map(this::splitPathEntries).flatMap(Arrays::stream).toArray( String[]::new); } - + public Collection parse(String fileExt, Collection filesAndDirs) { return filesAndDirs.stream().flatMap(dirOrFile -> this.parse(fileExt, dirOrFile).stream()) .collect(Collectors.toList()); } - + /** * Parses all class diagrams in the given path. * In case the path is a file, the file is parsed regardless of its extension @@ -516,7 +516,7 @@ public Collection parse(String fileExt, Path fileOrDir) { } return Collections.emptySet(); } - + /** * creates the symboltable for the given ast * @@ -530,12 +530,12 @@ public ICD4CodeArtifactScope createSymbolTable(ASTCDCompilationUnit ast, boolean this.addDefaultImports(scope, java); return scope; } - + public void addDefaultImports(ICD4CodeArtifactScope scope, boolean java) { if (java) scope.addImports(new ImportStatement("java.lang", true)); } - + /** * prints the symboltable of the given scope out to a file * @@ -551,7 +551,7 @@ public void storeSymTab(ICD4CodeArtifactScope scope, String path) { + ".cdsym").toString()); } } - + /** * completes the symboltable for the given ast * @@ -560,5 +560,5 @@ public void storeSymTab(ICD4CodeArtifactScope scope, String path) { public void completeSymbolTable(ASTCDCompilationUnit ast) { ast.accept(new CD4CodeSymbolTableCompleter(ast).getTraverser()); } - + }