diff --git a/build.gradle b/build.gradle index 9e08e3be..4e53400f 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ allprojects { subprojects { apply plugin: "java-library" apply plugin: "maven-publish" - apply plugin: "monticore" + apply plugin: "de.monticore.generator" java { toolchain { @@ -36,13 +36,13 @@ subprojects { withSourcesJar() } - tasks.withType(JavaCompile) { - dependsOn(tasks.withType(MCTask)) + tasks.withType(JavaCompile).configureEach { + dependsOn(tasks.withType(MCGenTask)) options.encoding = "UTF-8" } - tasks.withType(Test) { + tasks.withType(Test).configureEach { useJUnitPlatform() testLogging { diff --git a/gradle.properties b/gradle.properties index cf2f60f0..867780ae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ repo=https://nexus.se.rwth-aachen.de/content/groups/public useLocalRepo=false -version=7.4.0-SNAPSHOT +version=7.7.0-SNAPSHOT org.gradle.caching=true -org.gradle.welcome=never \ No newline at end of file +org.gradle.welcome=never diff --git a/gradle/corpus.versions.toml b/gradle/corpus.versions.toml new file mode 100644 index 00000000..4cc8c8ab --- /dev/null +++ b/gradle/corpus.versions.toml @@ -0,0 +1,20 @@ +# +# The corpus of libraries is used to test the generated infrastructure. For this +# purpose, a variety of open-source libraries targeting different Java versions +# are used. Only the sources of these libraries are used during testing. Their +# versions must not necessarily align with the project's dependencies. +# +# Read more in javaDSL/src/main/grammars/de/monticore/java/JavaDSL.md +# +[libraries] +# com.osmerion.quitte - Quitte +# https://github.com/Osmerion/Quitte - Java 17 +quitte = { module = "com.osmerion.quitte:quitte", version = "0.7.0" } + +# com.google.guava - Guava +# https://github.com/google/guava - Java 8 +guava = { module = "com.google.guava:guava", version = "31.1-jre" } + +# de.monticore - MontiCore +# https://github.com/MontiCore/monticore - Java 11 +monticore-runtime = { module = "de.monticore:monticore-runtime", version = "7.6.0-SNAPSHOT" } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fa4b6fd3..d60ad87a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ emf = "2.15.0" gradle-shadow-plugin = "7.1.2" guava = "31.1-jre" junit = "5.9.0" -monticore = "7.5.0-SNAPSHOT" +monticore = "7.7.0-SNAPSHOT" [libraries] diff --git a/javaDSL-emf/build.gradle b/javaDSL-emf/build.gradle index 540f9b87..63784b50 100644 --- a/javaDSL-emf/build.gradle +++ b/javaDSL-emf/build.gradle @@ -33,11 +33,26 @@ task copyTestSources(type: Copy) { from "${project(':javaDSL').projectDir}/src/main" } -task generate(type: MCTask) { +tasks.register("generateTextBlock", MCTask) { + dependsOn(copyMainSources, copyTestSources) + + grammar = file "$grammarsDir/de/monticore/java/TextBlock.mc4" + outputDir = file "$buildDir/generated-sources/monticore/sourcecode" + handcodedPath "$srcMainDir/java" + + script = "de/monticore/monticore_emf.groovy" + + def upToDate = incCheck("de/monticore/java/TextBlock.mc4") + outputs.upToDateWhen { upToDate } +} + +tasks.register("generate", MCTask) { + dependsOn(tasks.generateTextBlock) dependsOn(copyMainSources, copyTestSources) grammar = file "$grammarsDir/de/monticore/java/JavaDSL.mc4" outputDir = file "$buildDir/generated-sources/monticore/sourcecode" + modelPath "$grammarsDir" handcodedPath "$srcMainDir/java" script = "de/monticore/monticore_emf.groovy" @@ -48,6 +63,7 @@ task generate(type: MCTask) { dependencies { implementation(platform(libs.junit.bom)) + implementation "de.monticore.lang:cd4analysis:7.7.0-SNAPSHOT" api(libs.monticore.grammar.emf) api(libs.monticore.runtime.emf) @@ -63,5 +79,6 @@ dependencies { } testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit.jupiter.params) testRuntimeOnly(libs.junit.jupiter.engine) } \ No newline at end of file diff --git a/javaDSL/build.gradle b/javaDSL/build.gradle index 2d1516ab..139344bd 100644 --- a/javaDSL/build.gradle +++ b/javaDSL/build.gradle @@ -4,13 +4,20 @@ def grammarsDir = "src/main/grammars" configurations { corpus { + canBeConsumed = false + canBeResolved = true + transitive = false + + resolutionStrategy.dependencySubstitution.all { + artifactSelection { + selectArtifact("jar", "jar", "sources") + } + } } } sourceSets { - main.java.srcDir("$buildDir/generated-sources/monticore/sourcecode") - grammars { resources { srcDir(grammarsDir) @@ -25,15 +32,6 @@ java { } } -tasks.register('generate', MCTask) { - grammar = file "$projectDir/$grammarsDir/de/monticore/java/JavaDSL.mc4" - outputDir = file "$buildDir/generated-sources/monticore/sourcecode" - handcodedPath "$projectDir/src/main/java" - - def upToDate = incCheck("de/monticore/java/JavaDSL.mc4") - outputs.upToDateWhen { upToDate } -} - tasks.register('extractCorpus') { dependsOn(configurations.corpus) @@ -65,6 +63,7 @@ tasks.withType(Test).configureEach { dependencies { implementation(platform(libs.junit.bom)) + implementation "de.monticore.lang:cd4analysis:$version" api(libs.monticore.grammar) api(libs.monticore.runtime) @@ -79,6 +78,8 @@ dependencies { testImplementation(libs.junit.jupiter.params) testRuntimeOnly(libs.junit.jupiter.engine) - corpus(libs.guava) { artifact { classifier = "sources" } } - corpus(libs.monticore.runtime) { artifact { classifier = "sources" } } + corpus(corpus.guava) + corpus(corpus.monticore.runtime) + // TODO: fix parser for Java 17 and enable + //corpus(corpus.quitte) } \ No newline at end of file diff --git a/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.mc4 b/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.mc4 index 1b9bee04..12fa5901 100644 --- a/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.mc4 +++ b/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.mc4 @@ -58,27 +58,35 @@ package de.monticore.java; * |-> de.monticore.types.MCSimpleGenericTypes * |-> de.monticore.types.MCCollectionTypes * |-> de.monticore.types.MCBasicTypes (*) + * |-> de.monticore.types.TypeParameters + * |-> de.monticore.symbols.BasicSymbols + * |-> de.monticore.MCBasics (*) + * |-> de.monticore.types.MCBasicTypes + * |-> de.monticore.MCBasics (*) * - * (*) Dependencies are emitted because they have been listed previously. + * (*) Repeated Dependencies are omitted. */ -grammar JavaDSL extends de.monticore.JavaLight, +grammar JavaDSL extends + de.monticore.java.TextBlock, + de.monticore.JavaLight, de.monticore.expressions.BitExpressions, de.monticore.expressions.LambdaExpressions, // TODO: move to JavaLight? de.monticore.literals.MCJavaLiterals, de.monticore.statements.MCFullJavaStatements, de.monticore.types.MCArrayTypes, - de.monticore.types.MCFullGenericTypes { + de.monticore.types.MCFullGenericTypes, + de.monticore.types.TypeParameters { start CompilationUnit; // starting point for parsing a java file -interface scope CompilationUnit; +interface CompilationUnit; -scope OrdinaryCompilationUnit implements CompilationUnit +OrdinaryCompilationUnit implements CompilationUnit = PackageDeclaration? ImportDeclaration* TypeDeclaration* ; -scope ModularCompilationUnit implements CompilationUnit +ModularCompilationUnit implements CompilationUnit = ImportDeclaration* ModuleDeclaration ; @@ -158,7 +166,40 @@ symbolrule ClassDeclaration = ClassBody = "{" ClassBodyDeclaration* "}" ; - + +/* + * Records Classes + * + * https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.10 + */ + +symbol scope RecordDeclaration extends TypeDeclaration + = JavaModifier* "record" Name TypeParameters? RecordHeader + ("implements" implementedInterface:(MCType || ",")+)? + RecordBody + ; + +RecordHeader + = "(" (RecordComponent || ",")* ")" + ; + +RecordComponent + = JavaModifier* MCType (arrayAnnotations:Annotation* variableArity:"...")? Name + ; + +astrule RecordComponent = + method public boolean isHasVariableArity() { + return this.isPresentVariableArity(); + }; + +RecordBody + = "{" (ClassBodyDeclaration | CompactConstructorDeclaration)* "}" + ; + +CompactConstructorDeclaration + = JavaModifier* Name body:MCJavaBlock + ; + symbol scope InterfaceDeclaration extends TypeDeclaration = JavaModifier* "interface" Name TypeParameters? ("extends" extendedInterface:(MCType || ",")+)? @@ -187,18 +228,6 @@ EnumBody = ";" ClassBodyDeclaration* ; -TypeParameters - = "<" (TypeParameter || ",")+ ">" - ; - -symbol TypeParameter - = Name ("extends" TypeBound)? - ; - -TypeBound - = (MCType || "&")+ - ; - ClassBlock implements ClassBodyDeclaration = (["static"])? JavaBlock ; @@ -260,8 +289,12 @@ AnnotatedName = Annotation* Name; @Override MCArrayType implements MCType - = MCType (AnnotatedDimension {_builder.setDimensions(_builder.getDimensions()+1);} )+ + = MCType (AnnotatedDimension)+ ; +astrule MCArrayType = + method public int getDimensions() { + return this.sizeAnnotatedDimensions(); + }; @Override MCBasicGenericType implements MCGenericType <20> @@ -330,17 +363,6 @@ ClassCreatorRest = Arguments ClassBody? ; -@Override ExtType = MCType; - -ExtLiteral = Literal; - -@Override ExtReturnType = MCReturnType; - -@Override ExtTypeArgument = MCTypeArgument; - -ExtTypeParameter = TypeParameter; -@Override ExtTypeParameters = TypeParameters; - /* * TODO Remove this * This is a workaround to a questionable behavior in the core grammar JavaLight @@ -355,9 +377,8 @@ JavaAnnotation extends JavaModifier implements ElementValue ( "(" AnnotationArguments? ")" )? ; -@Override AnonymousClass implements Creator - = ExtType Arguments ClassBody? + = MCType Arguments ClassBody? ; @@ -375,5 +396,22 @@ interface MethodReferenceTarget; ConstructorReferenceTarget implements MethodReferenceTarget = "new"; MethodNameReferenceTarget implements MethodReferenceTarget = Name; +TextBlockLiteral implements Literal, SignedLiteral + = source:TextBlock + ; + +/*========================================================================*/ +/*============================ LEXER RULES ===============================*/ +/*========================================================================*/ + +token TextBlock + = TextBlockDelimiter (TextBlockCharacters)? TextBlockDelimiter + : {setText(de.monticore.java.utils.TextBlockUtils.preprocessTextBlock(getText().substring(3, getText().length() - 4)));}; + +fragment token TextBlockCharacters + = (' ' | '\t')* ('\r' | '\n') (. | EscapeSequence)*; + +fragment token TextBlockCharacter + = '"' | '\\' | EscapeSequence; } diff --git a/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.md b/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.md index 30f8de28..ad663f94 100644 --- a/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.md +++ b/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.md @@ -1,24 +1,27 @@ # JavaDSL -JavaDSL offers a full parser for Java (Spec 1.7), many context conditions and -a pretty printer. -The grammar file is [`de.monticore.java.JavaDSL`][JavaDSL]. +JavaDSL provides a full spec-compliant parser for Java 17, a pretty printer and +additional tools for working with Java source artifacts. -## Handwritten Extensions -### AST +The core grammar definition can be found in [`de.monticore.java.JavaDSL`][JavaDSL]. -## Parser -## Symboltable -## Functionality -### CoCos +## Testing -### PrettyPrinter +### Corpus Tests -### Helper +To ensure that the parser covers the entire specification, it is tested on a +large corpus of open-source libraries. _Corpus Tests_ are executed as part of +the regular unit tests. + +To add a library to the corpus, modifications should be made in two places: + +1. The dependency should be added to the [corpus' version catalog](../../../../../../../gradle/corpus.versions.toml), and +2. the dependency should be added to the "corpus" configuration in the [build script](../../../../../../build.gradle). + +Note, that the libraries in the corpus must not be kept up-to-date. Instead, a +variety of libraries targeting different Java language versions and use-cases +should be used to cover different code-styles and language features. -### Reporting - -### CLI Application [JavaDSL]: https://git.rwth-aachen.de/monticore/javaDSL/blob/dev/javaDSL/src/main/grammars/de/monticore/java/JavaDSL.mc4 diff --git a/javaDSL/src/main/grammars/de/monticore/java/TextBlock.mc4 b/javaDSL/src/main/grammars/de/monticore/java/TextBlock.mc4 new file mode 100644 index 00000000..58db26d4 --- /dev/null +++ b/javaDSL/src/main/grammars/de/monticore/java/TextBlock.mc4 @@ -0,0 +1,7 @@ +package de.monticore.java; + +component grammar TextBlock { + + token TextBlockDelimiter = '"' '"' '"'; + +} \ No newline at end of file diff --git a/javaDSL/src/main/java/de/monticore/java/JavaDSLParseUtil.java b/javaDSL/src/main/java/de/monticore/java/JavaDSLParseUtil.java deleted file mode 100644 index 380f9198..00000000 --- a/javaDSL/src/main/java/de/monticore/java/JavaDSLParseUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.monticore.java; - -import de.se_rwth.commons.logging.Finding; -import de.se_rwth.commons.logging.Log; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.stream.Collectors; - -public class JavaDSLParseUtil { - - public static void main(String[] args) throws IOException { - Log.enableFailQuick(false); - List paths = Files - .walk(Paths.get(args[0])) - .filter(p -> p.toFile().isFile()) - .filter(p -> p.toFile().getName().endsWith(".java")) - .collect(Collectors.toList()); - - int errors = 0; - for (Path path : paths) { - try { - Log.getFindings().clear(); - System.out.println("Parsing " + path); - JavaDSLTool.loadArtifact(path); - if (!Log.getFindings().isEmpty()) { - errors++; - } - }catch (Exception e){ - e.printStackTrace(); - errors++; - }finally { - System.out.println("Findings: " + Log.getFindings().size()); - for (Finding finding : Log.getFindings()) { - System.out.println(finding.toString()); - } - } - } - - System.out.println("\nErrors: " + errors + " of " + paths.size()); - } - -} diff --git a/javaDSL/src/main/java/de/monticore/java/JavaDSLTool.java b/javaDSL/src/main/java/de/monticore/java/JavaDSLTool.java index 9cd30819..1a13475d 100644 --- a/javaDSL/src/main/java/de/monticore/java/JavaDSLTool.java +++ b/javaDSL/src/main/java/de/monticore/java/JavaDSLTool.java @@ -1,76 +1,280 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.java; -import java.io.IOException; -import java.nio.file.Path; - +import de.monticore.cd.codegen.CDGenerator; +import de.monticore.cd.codegen.CdUtilsPrinter; +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.io.paths.MCPath; +import de.monticore.java.java2cd.Java2CDConverter; import de.monticore.java.javadsl.JavaDSLMill; -import de.monticore.java.javadsl._symboltable.IJavaDSLArtifactScope; -import de.monticore.java.javadsl._symboltable.IJavaDSLGlobalScope; -import de.monticore.java.javadsl._symboltable.JavaDSLScopesGenitor; -import de.monticore.java.javadsl._visitor.JavaDSLTraverser; - import de.monticore.java.javadsl._ast.ASTCompilationUnit; -import de.monticore.java.javadsl._parser.JavaDSLParser; -import de.monticore.java.prettyprint.JavaDSLPrettyPrinter; -import de.monticore.prettyprint.IndentPrinter; +import de.monticore.java.javadsl._symboltable.IJavaDSLArtifactScope; +import de.monticore.java.javadsl._symboltable.JavaDSLScopesGenitorDelegator; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symboltable.ImportStatement; +import de.se_rwth.commons.Names; import de.se_rwth.commons.logging.Log; +import org.apache.commons.cli.*; -public class JavaDSLTool { +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.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class JavaDSLTool extends de.monticore.java.javadsl.JavaDSLTool { + + /** + * main method of the JavaDSL + * + * @param args array of the command line arguments + */ public static void main(String[] args) { - Log.enableFailQuick(false); - if (args.length != 1) { - Log.error("Please specify only one single path to the input model."); - return; + JavaDSLTool tool = new JavaDSLTool(); + tool.run(args); + } + + /** + * executes the arguments stated in the command line like parsing a given model to an ast, + * creating and printing out a corresponding symbol table or generating java files + * based of additional configuration templates or handwritten code + * + * @param args array of the command line arguments + */ + + @Override + public void run(String[] args) { + Options options = initOptions(); + + try { + CommandLineParser cliParser = new DefaultParser(); + CommandLine cmd = cliParser.parse(options, args); + + if (!cmd.hasOption("i") || cmd.hasOption("h")) { + printHelp(options); + return; + } + + if (cmd.hasOption("v")) { + printVersion(); + } + + Log.init(); + JavaDSLMill.init(); + + BasicSymbolsMill.initializePrimitives(); + BasicSymbolsMill.initializeString(); + + Log.enableFailQuick(false); + Collection asts = + this.parse(".java", this.createModelPath(cmd).getEntries()); + Log.enableFailQuick(true); + + if (cmd.hasOption("path")) { + String[] paths = splitPathEntries(cmd.getOptionValue("path")); + JavaDSLMill.globalScope().setSymbolPath(new MCPath(paths)); + } + + Collection scopes = + asts.stream() + .map(ast -> createSymbolTable(ast, cmd)) + .collect(Collectors.toList()); + + if (cmd.hasOption("s")) { + for (IJavaDSLArtifactScope scope : scopes) { + this.storeSymTab(scope, cmd.getOptionValue("s")); + } + } + + if (cmd.hasOption("o")) { + GlobalExtensionManagement glex = new GlobalExtensionManagement(); + glex.setGlobalValue("cdPrinter", new CdUtilsPrinter()); + GeneratorSetup setup = new GeneratorSetup(); + + if (cmd.hasOption("tp")) { + setup.setAdditionalTemplatePaths( + Arrays.stream(cmd.getOptionValues("tp")) + .map(Paths::get) + .map(Path::toFile) + .collect(Collectors.toList())); + } + + String outputPath = Paths.get(cmd.getOptionValue("o")).toString(); + + setup.setGlex(glex); + setup.setOutputDirectory(new File(outputPath)); + + CDGenerator generator = new CDGenerator(setup); + String configTemplate = cmd.getOptionValue("ct", "java2cd.Java2CD"); + TemplateController tc = setup.getNewTemplateController(configTemplate); + TemplateHookPoint hpp = new TemplateHookPoint(configTemplate); + + Java2CDConverter converter = new Java2CDConverter(); + List configTemplateArgs = Arrays.asList(glex, converter, setup.getHandcodedPath(), generator); + + asts.forEach(ast -> hpp.processValue(tc, ast, configTemplateArgs)); + } + + } catch (ParseException e) { + JavaDSLMill.globalScope().clear(); + Log.error(String.format("0xA7114 Could not process parameters: %s", e.getMessage())); } - Log.info("JavaDSL Tool", JavaDSLTool.class.getName()); - Log.info("----------", JavaDSLTool.class.getName()); - String model = args[0]; + } + + /** + * adds additional options to the cli tool + * + * @param options collection of all the possible options + */ - // parse the model and create the AST representation - final ASTCompilationUnit ast = loadArtifact(Path.of(model)); - Log.info(model + " parsed successfully!", JavaDSLTool.class.getName()); + public Options addAdditionalOptions(Options options) { - // execute default context conditions + options.addOption( + Option.builder("o") + .longOpt("output") + .argName("dir") + .hasArg() + .desc("Sets the output path.") + .build()); - // execute a custom set of context conditions - // TODO reimplement CoCos -// Log.info("Running customized set of context conditions", JavaDSLTool.class.getName()); -// JavaDSLCoCoChecker customCoCos = new JavaDSLCoCoChecker(); -// customCoCos.checkAll(ast); + options.addOption( + Option.builder("ct") + .longOpt("configtemplate") + .hasArg() + .argName("template") + .desc("Sets a template for configuration.") + .build()); - // analyze the model with a visitor + options.addOption( + Option.builder("tp") + .longOpt("template") + .hasArg() + .argName("path") + .desc("Sets the path for additional templates.") + .build()); - // execute a pretty printer - JavaDSLPrettyPrinter pp = new JavaDSLPrettyPrinter(new IndentPrinter()); - Log.info("Pretty printing the parsed JavaDSL into console:", JavaDSLTool.class.getName()); - System.out.println(pp.prettyprint(ast)); + options.addOption( + Option.builder("c2mc") + .longOpt("class2mc") + .desc("Enables to resolve java classes in the model path") + .build()); + + return options; } - public static ASTCompilationUnit loadArtifact(Path source) { - IJavaDSLGlobalScope globalScope = JavaDSLMill.globalScope(); + /** + * gets the paths of all input models + * + * @param cmd cli arguments + * @return path of all models + */ + public MCPath createModelPath(CommandLine cmd) { + if (cmd.hasOption("i")) { + return new MCPath(splitPathEntries(cmd.getOptionValues("i"))); + } else { + return new MCPath(); + } + } - JavaDSLParser parser = JavaDSLMill.parser(); - ASTCompilationUnit compilationUnit; + /** + * splits the compound paths of all input models + * + * @param composedPath combined path of all models + * @return seperated paths of input models + */ + public String[] splitPathEntries(String composedPath) { + return composedPath.split(Pattern.quote(File.pathSeparator)); + } - try { - compilationUnit = parser.parseCompilationUnit(source.toAbsolutePath().toString()).orElseThrow(NullPointerException::new); + /** + * splits the compound paths of all input models + * + * @param composedPaths combined paths of all models + * @return seperated paths of input models + */ + public final String[] splitPathEntries(String[] composedPaths) { + return Arrays.stream(composedPaths) + .map(this::splitPathEntries) + .flatMap(Arrays::stream) + .toArray(String[]::new); + } + + /** + * parses all input models with a given file ending + * + * @param file file ending of the files to parse + * @param dirs input directories + * @return collection of asts of all parsed models + */ + public Collection parse(String file, Collection dirs) { + return dirs.stream() + .flatMap(directory -> this.parse(file, directory).stream()) + .collect(Collectors.toList()); + } + + /** + * parses all input models with a given file ending + * + * @param fileExt file ending of the files to parse + * @param directory input directory + * @return collection of asts of all parsed models + */ + public Collection parse(String fileExt, Path directory) { + try (Stream paths = Files.walk(directory)) { + return paths + .filter(Files::isRegularFile) + .filter(file -> file.getFileName().toString().endsWith(fileExt)) + .map(Path::toString) + .map(this::parse) + .collect(Collectors.toSet()); } catch (IOException e) { - throw new RuntimeException(e); + Log.error("0xA1063 Error while traversing the file structure `" + directory + "`.", e); } + return Collections.emptySet(); + } - JavaDSLScopesGenitor genitor = JavaDSLMill.scopesGenitor(); - JavaDSLTraverser traverser = JavaDSLMill.traverser(); - traverser.setJavaDSLHandler(genitor); - traverser.add4JavaDSL(genitor); - genitor.putOnStack(globalScope); + /** + * creates the symboltable for the given ast + * + * @param ast the input ast + * @param cmd cli arguments + * @return the symbol-table of the ast + */ - IJavaDSLArtifactScope artifactScope = genitor.createFromAST(compilationUnit); - globalScope.addSubScope(artifactScope); + public IJavaDSLArtifactScope createSymbolTable(ASTCompilationUnit ast, CommandLine cmd) { + JavaDSLScopesGenitorDelegator genitor = JavaDSLMill.scopesGenitorDelegator(); + IJavaDSLArtifactScope scope = genitor.createFromAST(ast); + if (cmd.hasOption("c2mc")) { + scope.addImports(new ImportStatement("java.lang", true)); + } + return scope; + } - return compilationUnit; + /** + * 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(IJavaDSLArtifactScope scope, String path) { + if (Path.of(path).toFile().isFile()) { + this.storeSymbols(scope, path); + } else { + this.storeSymbols(scope, Paths.get( + path, Names.getPathFromPackage(scope.getFullName()) + ".javasym").toString()); + } } - + } diff --git a/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDConverter.java b/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDConverter.java new file mode 100644 index 00000000..bf3c7f17 --- /dev/null +++ b/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDConverter.java @@ -0,0 +1,25 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.java.java2cd; + +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTCompilationUnit; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; + +public class Java2CDConverter { + + public Java2CDData doConvert(ASTCompilationUnit ast, GlobalExtensionManagement glex) { + + Java2CDVisitor visitor = new Java2CDVisitor(glex); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(visitor); + traverser.add4JavaLight(visitor); + + CD4CodeMill.init(); + ast.accept(traverser); + + return new Java2CDData(visitor.getCompilationUnit()); + } + +} diff --git a/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDData.java b/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDData.java new file mode 100644 index 00000000..baf0f88d --- /dev/null +++ b/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDData.java @@ -0,0 +1,17 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.java.java2cd; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; + +public class Java2CDData { + + protected final ASTCDCompilationUnit compilationUnit; + + public Java2CDData(ASTCDCompilationUnit compilationUnit) { + this.compilationUnit = compilationUnit; + } + + public ASTCDCompilationUnit getCompilationUnit() { + return compilationUnit; + } +} diff --git a/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDVisitor.java b/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDVisitor.java new file mode 100644 index 00000000..6dbc02a5 --- /dev/null +++ b/javaDSL/src/main/java/de/monticore/java/java2cd/Java2CDVisitor.java @@ -0,0 +1,402 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.java.java2cd; + +import de.monticore.cd.facade.*; +import de.monticore.cd.methodtemplates.CD4C; +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cd4codebasis._ast.ASTCDConstructor; +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDMethodSignature; +import de.monticore.cd4codebasis._ast.ASTCDParameter; +import de.monticore.cdbasis._ast.*; +import de.monticore.cdinterfaceandenum._ast.ASTCDEnum; +import de.monticore.cdinterfaceandenum._ast.ASTCDInterface; +import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.monticore.generating.templateengine.StringHookPoint; +import de.monticore.java.javadsl._ast.*; +import de.monticore.java.javadsl._prettyprint.JavaDSLFullPrettyPrinter; +import de.monticore.java.javadsl._visitor.JavaDSLVisitor2; +import de.monticore.javalight._ast.ASTConstructorDeclaration; +import de.monticore.javalight._ast.ASTFormalParameterListing; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.javalight._visitor.JavaLightVisitor2; +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.statements.mccommonstatements._ast.ASTConstantsMCCommonStatements; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mccommonstatements._ast.ASTJavaModifier; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTVariableDeclarator; +import de.monticore.types.MCTypeFacade; +import de.monticore.types.mcbasictypes._ast.ASTMCImportStatement; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; +import de.monticore.types.mccollectiontypes._ast.ASTMCTypeArgument; +import de.monticore.umlmodifier._ast.ASTModifier; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import static de.monticore.cd.codegen.CD2JavaTemplates.VALUE; +import static de.monticore.cd.facade.CDModifier.*; + +public class Java2CDVisitor implements JavaDSLVisitor2, JavaLightVisitor2 { + + protected ASTCDCompilationUnit cdCompilationUnit; + protected ASTCDPackage cdPackage; + protected ASTCDType currentType; + + protected List imports; + + protected final GlobalExtensionManagement glex; + + protected final CD4C cd4C; + + public Java2CDVisitor(GlobalExtensionManagement glex) { + this.glex = glex; + this.cd4C = CD4C.getInstance(); + imports = new ArrayList<>(); + } + + @Override + public void visit(ASTOrdinaryCompilationUnit ast) { + ASTCDDefinition definition = CD4CodeMill.cDDefinitionBuilder() + .setModifier(PUBLIC.build()) + .setName("Generated") + .build(); + + cdPackage = CD4CodeMill.cDPackageBuilder() + .setMCQualifiedName(ast.isPresentPackageDeclaration() + ? ast.getPackageDeclaration().getMCQualifiedName() + : MCQualifiedNameFacade.createQualifiedName("generated")) + .build(); + + definition.addCDElement(cdPackage); + + this.cdCompilationUnit = CD4CodeMill.cDCompilationUnitBuilder() + .setCDDefinition(definition) + .build(); + } + + @Override + public void visit(ASTImportDeclaration ast) { + imports.add(CD4CodeMill.mCImportStatementBuilder() + .setMCQualifiedName(ast.getMCQualifiedName()) + .build()); + } + + @Override + public void visit(ASTClassDeclaration ast) { + ASTCDClassBuilder classBuilder = CD4CodeMill.cDClassBuilder() + .setModifier(getModifier(ast.getJavaModifierList())) + .setName(ast.getName()); + + if (!ast.isEmptyImplementedInterface()) { + List interfaces = new ArrayList<>(); + for (ASTMCType i : ast.getImplementedInterfaceList()) { + if (i instanceof ASTMCQualifiedType) { + interfaces.add(((ASTMCQualifiedType) i).getMCQualifiedName().getQName()); + } else { + interfaces.add(i.printType()); + } + } + } + + if (ast.isPresentSuperClass()) { + classBuilder = classBuilder + .setCDExtendUsage(CDExtendUsageFacade.getInstance() + .createCDExtendUsage(getMCType(ast.getSuperClass()).printType())); + } + + ASTCDClass cdClass = classBuilder.build(); + currentType = cdClass; + cdPackage.addCDElement(cdClass); + + imports.forEach(i -> cd4C.addImport(currentType, i.getQName())); + } + + @Override + public void visit(ASTRecordDeclaration ast) { + ASTCDClassBuilder classBuilder = CD4CodeMill.cDClassBuilder() + .setModifier(getModifier(ast.getJavaModifierList())) + .setName(ast.getName()); + + if (!ast.isEmptyImplementedInterface()) { + classBuilder.setCDInterfaceUsage(CDInterfaceUsageFacade.getInstance() + .createCDInterfaceUsage( + ast.getImplementedInterfaceList() + .stream() + .map(ASTMCType::printType) + .toArray(String[]::new))); + } + + ASTCDClass cdClass = classBuilder.build(); + currentType = cdClass; + cdPackage.addCDElement(cdClass); + } + + @Override + public void visit(ASTRecordComponent ast) { + currentType.addCDMember(CDAttributeFacade.getInstance().createAttribute( + getModifier(ast.getJavaModifierList()), + ast.getMCType(), + ast.getName())); + } + + @Override + public void visit(ASTCompactConstructorDeclaration ast) { + ASTCDConstructor constructor = CDConstructorFacade.getInstance() + .createConstructor(getModifier(ast.getJavaModifierList()), ast.getName()); + + StringBuilder methodBody = new StringBuilder(); + ast.getBody().getMCBlockStatementList().stream() + .map(s -> CD4CodeMill.prettyPrint(s, true)) + .forEach(s -> methodBody.append(s).append("\n")); + + glex.replaceTemplate(EMPTY_BODY, constructor, + new StringHookPoint(methodBody.toString())); + currentType.addCDMember(constructor); + } + + @Override + public void visit(ASTInterfaceDeclaration ast) { + ASTCDInterface cdInterface = CD4CodeMill.cDInterfaceBuilder() + .setModifier(getModifier(ast.getJavaModifierList())) + .setName(ast.getName()) + .setCDExtendUsage(CDExtendUsageFacade.getInstance() + .createCDExtendUsage( + ast.getExtendedInterfaceList() + .stream() + .map(ASTMCType::printType) + .toArray(String[]::new))) + .build(); + + currentType = cdInterface; + cdPackage.addCDElement(cdInterface); + } + + @Override + public void visit(ASTEnumDeclaration ast) { + ASTCDEnum cdEnum = CD4CodeMill.cDEnumBuilder() + .setModifier(getModifier(ast.getJavaModifierList())) + .setName(ast.getName()) + .setCDInterfaceUsage(CDInterfaceUsageFacade.getInstance() + .createCDInterfaceUsage( + ast.getImplementedInterfaceList() + .stream() + .map(ASTMCType::printType) + .toArray(String[]::new))) + .build(); + + currentType = cdEnum; + cdPackage.addCDElement(cdEnum); + } + + @Override + public void visit(ASTEnumConstantDeclaration ast) { + ((ASTCDEnum) currentType).addCDEnumConstant( + CD4CodeMill.cDEnumConstantBuilder() + .setName(ast.getName()) + .build() + ); + } + + @Override + public void visit(ASTFieldDeclaration ast) { + ASTMCType type = getMCType(ast.getMCType()); + + for (ASTVariableDeclarator variable : ast.getVariableDeclaratorList()) { + ASTCDAttribute attribute = CDAttributeFacade.getInstance() + .createAttribute( + getModifier(ast.getJavaModifierList()), + type, + variable.getDeclarator().getName()); + + if (variable.isPresentVariableInit()) { + String initial = new JavaDSLFullPrettyPrinter(new IndentPrinter()).prettyprint(variable.getVariableInit()); + glex.replaceTemplate(VALUE, attribute, new StringHookPoint(" = " + initial)); + } + currentType.addCDMember(attribute); + } + } + + protected ASTMCType getMCType(ASTMCType mcType) { + ASTMCType type; + if (mcType instanceof ASTMCQualifiedType) { + type = MCTypeFacade.getInstance() + .createQualifiedType( + ((ASTMCQualifiedType) mcType).getMCQualifiedName().getQName()); + } else if (mcType instanceof ASTMCArrayType) { + ASTMCArrayType arrayType = (ASTMCArrayType) mcType; + type = MCTypeFacade.getInstance() + .createArrayType( + getMCType(arrayType.getMCType()), arrayType.getAnnotatedDimensionList().size()); + } else if (mcType instanceof ASTMCGenericType) { + ASTMCGenericType genericType = (ASTMCGenericType) mcType; + + List typeArguments = genericType.getMCTypeArgumentList().stream() + .map(ASTMCTypeArgument::getMCTypeOpt) + .filter(Optional::isPresent) + .map(Optional::get) + .map(this::getMCType) + .map(t -> CD4CodeMill.mCBasicTypeArgumentBuilder() + .setMCQualifiedType((de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType) t) + .build()) + .collect(Collectors.toList()); + + type = MCTypeFacade.getInstance() + .createBasicGenericTypeOf( + genericType.getNameList(), typeArguments); + } else { + type = mcType.deepClone(); + } + return type; + } + + @Override + public void visit(ASTMethodDeclaration ast) { + ASTCDMethod method = CDMethodFacade.getInstance().createMethod( + getModifier(ast.getMCModifierList().stream().map(m -> (ASTJavaModifier) m).collect(Collectors.toList())), + ast.getName()); + + if (ast.getMCReturnType().isPresentMCType()) { + method.setMCReturnType( + CD4CodeMill.mCReturnTypeBuilder() + .setMCType(getMCType(ast.getMCReturnType().getMCType())) + .build()); + } + + if (ast.getFormalParameters().isPresentFormalParameterListing()) { + addParameters(ast.getFormalParameters().getFormalParameterListing(), method); + } + + JavaDSLFullPrettyPrinter printer = new JavaDSLFullPrettyPrinter(new IndentPrinter()); + StringBuilder methodBody = new StringBuilder(); + ast.getMCJavaBlock().getMCBlockStatementList().stream() + .map(printer::prettyprint) + .forEach(methodBody::append); + + glex.replaceTemplate(EMPTY_BODY, method, new StringHookPoint(methodBody.toString())); + currentType.addCDMember(method); + } + + protected void addParameters(ASTFormalParameterListing ast, ASTCDMethodSignature method) { + List list = new ArrayList<>(); + for (ASTFormalParameter p : ast.getFormalParameterList()) { + ASTMCType type = getMCType(p.getMCType()); + ASTCDParameter parameter = CDParameterFacade.getInstance() + .createParameter( + type, p.getDeclarator().getName()); + list.add(parameter); + } + + method.addAllCDParameters(list); + } + + @Override + public void visit(ASTConstructorDeclaration ast) { + ASTCDConstructor method = CDConstructorFacade.getInstance().createConstructor( + getModifier(ast.getMCModifierList().stream().map(m -> (ASTJavaModifier) m).collect(Collectors.toList())), + ast.getName()); + + if (ast.getFormalParameters().isPresentFormalParameterListing()) { + addParameters(ast.getFormalParameters().getFormalParameterListing(), method); + } + + JavaDSLFullPrettyPrinter printer = new JavaDSLFullPrettyPrinter(new IndentPrinter()); + StringBuilder methodBody = new StringBuilder(); + ast.getMCJavaBlock().getMCBlockStatementList().stream() + .map(printer::prettyprint) + .forEach(methodBody::append); + + glex.replaceTemplate(EMPTY_BODY, method, new StringHookPoint(methodBody.toString())); + currentType.addCDMember(method); + } + + protected ASTModifier getModifier(List modifiers) { + List digits = modifiers.stream() + .map(ASTJavaModifier::getModifier) + .collect(Collectors.toList()); + + if (digits.isEmpty()) { + return PACKAGE_PRIVATE.build(); + } + if (digits.size() == 1) { + if (digits.contains(ASTConstantsMCCommonStatements.PUBLIC)) { + return PUBLIC.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.PRIVATE)) { + return PRIVATE.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.PROTECTED)) { + return PROTECTED.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.ABSTRACT)) { + return PACKAGE_PRIVATE_ABSTRACT.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PACKAGE_PRIVATE_FINAL.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.STATIC)) { + return PACKAGE_PRIVATE_STATIC.build(); + } + } else if (digits.size() == 2) { + if (digits.contains(ASTConstantsMCCommonStatements.PUBLIC)) { + if (digits.contains(ASTConstantsMCCommonStatements.ABSTRACT)) { + return PUBLIC_ABSTRACT.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PUBLIC_FINAL.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.STATIC)) { + return PUBLIC_STATIC.build(); + } + } + if (digits.contains(ASTConstantsMCCommonStatements.PROTECTED)) { + if (digits.contains(ASTConstantsMCCommonStatements.ABSTRACT)) { + return PROTECTED_ABSTRACT.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PROTECTED_FINAL.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.STATIC)) { + return PROTECTED_STATIC.build(); + } + } + if (digits.contains(ASTConstantsMCCommonStatements.PRIVATE)) { + if (digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PRIVATE_FINAL.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.STATIC)) { + return PRIVATE_STATIC.build(); + } + } + if (digits.contains(ASTConstantsMCCommonStatements.STATIC) && + digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PACKAGE_PRIVATE_STATIC_FINAL.build(); + } + } else if (modifiers.size() == 3) { + if (digits.contains(ASTConstantsMCCommonStatements.PUBLIC) && + digits.contains(ASTConstantsMCCommonStatements.STATIC) && + digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PUBLIC_STATIC_FINAL.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.PROTECTED) && + digits.contains(ASTConstantsMCCommonStatements.STATIC) && + digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PROTECTED_STATIC_FINAL.build(); + } + if (digits.contains(ASTConstantsMCCommonStatements.PRIVATE) && + digits.contains(ASTConstantsMCCommonStatements.STATIC) && + digits.contains(ASTConstantsMCCommonStatements.FINAL)) { + return PRIVATE_STATIC_FINAL.build(); + } + } + return PUBLIC.build(); + } + + public ASTCDCompilationUnit getCompilationUnit() { + return cdCompilationUnit; + } +} diff --git a/javaDSL/src/main/java/de/monticore/java/javadsl/_ast/ASTMCQualifiedType.java b/javaDSL/src/main/java/de/monticore/java/javadsl/_ast/ASTMCQualifiedType.java new file mode 100644 index 00000000..7af69e7d --- /dev/null +++ b/javaDSL/src/main/java/de/monticore/java/javadsl/_ast/ASTMCQualifiedType.java @@ -0,0 +1,17 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.java.javadsl._ast; + +import de.monticore.cd.facade.MCQualifiedNameFacade; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedName; + +public class ASTMCQualifiedType extends ASTMCQualifiedTypeTOP { + + public ASTMCQualifiedName getMCQualifiedName() { + StringBuilder name = new StringBuilder(); + annotatedNames.stream() + .map(ASTAnnotatedName::getName) + .forEach(n -> name.append(n).append(".")); + return MCQualifiedNameFacade.createQualifiedName(name.toString()); + } + +} diff --git a/javaDSL/src/main/java/de/monticore/java/prettyprint/JavaDSLFullPrettyPrinter.java b/javaDSL/src/main/java/de/monticore/java/prettyprint/JavaDSLFullPrettyPrinter.java deleted file mode 100644 index e191ee1d..00000000 --- a/javaDSL/src/main/java/de/monticore/java/prettyprint/JavaDSLFullPrettyPrinter.java +++ /dev/null @@ -1,145 +0,0 @@ -package de.monticore.java.prettyprint; - -import de.monticore.expressions.prettyprint.*; -import de.monticore.java.javadsl.JavaDSLMill; -import de.monticore.java.javadsl._ast.ASTJavaDSLNode; -import de.monticore.java.javadsl._visitor.JavaDSLTraverser; -import de.monticore.literals.prettyprint.MCCommonLiteralsPrettyPrinter; -import de.monticore.literals.prettyprint.MCJavaLiteralsPrettyPrinter; -import de.monticore.prettyprint.IndentPrinter; -import de.monticore.prettyprint.JavaLightPrettyPrinter; -import de.monticore.prettyprint.MCBasicsPrettyPrinter; -import de.monticore.statements.prettyprint.*; -import de.monticore.types.prettyprint.*; - -public class JavaDSLFullPrettyPrinter { - - protected final IndentPrinter printer; - protected JavaDSLTraverser traverser; - - public JavaDSLFullPrettyPrinter() { - this(new IndentPrinter()); - } - - public JavaDSLFullPrettyPrinter(IndentPrinter printer) { - this.printer = printer; - this.traverser = JavaDSLMill.traverser(); - - AssignmentExpressionsPrettyPrinter assignmentExpressions = new AssignmentExpressionsPrettyPrinter(printer); - this.traverser.add4AssignmentExpressions(assignmentExpressions); - this.traverser.setAssignmentExpressionsHandler(assignmentExpressions); - - BitExpressionsPrettyPrinter bitExpressions = new BitExpressionsPrettyPrinter(printer); - this.traverser.add4BitExpressions(bitExpressions); - this.traverser.setBitExpressionsHandler(bitExpressions); - - CommonExpressionsPrettyPrinter commonExpressions = new CommonExpressionsPrettyPrinter(printer); - this.traverser.add4CommonExpressions(commonExpressions); - this.traverser.setCommonExpressionsHandler(commonExpressions); - - ExpressionsBasisPrettyPrinter expressionsBasis = new ExpressionsBasisPrettyPrinter(printer); - this.traverser.add4ExpressionsBasis(expressionsBasis); - this.traverser.setExpressionsBasisHandler(expressionsBasis); - - JavaClassExpressionsPrettyPrinter javaClassExpressions = new JavaClassExpressionsPrettyPrinter(printer); - this.traverser.add4JavaClassExpressions(javaClassExpressions); - this.traverser.setJavaClassExpressionsHandler(javaClassExpressions); - - JavaLightPrettyPrinter javaLight = new JavaLightPrettyPrinter(printer); - this.traverser.add4JavaLight(javaLight); - this.traverser.setJavaLightHandler(javaLight); - - MCArrayStatementsPrettyPrinter mcArrayStatements = new MCArrayStatementsPrettyPrinter(printer); - this.traverser.add4MCArrayStatements(mcArrayStatements); - this.traverser.setMCArrayStatementsHandler(mcArrayStatements); - - MCArrayTypesPrettyPrinter mcArrayTypes = new MCArrayTypesPrettyPrinter(printer); - this.traverser.add4MCArrayTypes(mcArrayTypes); - this.traverser.setMCArrayTypesHandler(mcArrayTypes); - - /* - * TODO - * MCBasicsPrettyPrinter does not implement MCBasicsHandler. Figure out if - * this is a bug or intended. - */ - MCBasicsPrettyPrinter mcBasics = new MCBasicsPrettyPrinter(printer); - this.traverser.add4MCBasics(mcBasics); -// this.traverser.setMCBasicsHandler(mcBasics); - - MCBasicTypesPrettyPrinter mcBasicTypes = new MCBasicTypesPrettyPrinter(printer); - this.traverser.add4MCBasicTypes(mcBasicTypes); - this.traverser.setMCBasicTypesHandler(mcBasicTypes); - - MCCollectionTypesPrettyPrinter mcCollectionTypes = new MCCollectionTypesPrettyPrinter(printer); - this.traverser.add4MCCollectionTypes(mcCollectionTypes); - this.traverser.setMCCollectionTypesHandler(mcCollectionTypes); - - MCCommonLiteralsPrettyPrinter mcCommonLiterals = new MCCommonLiteralsPrettyPrinter(printer); - this.traverser.add4MCCommonLiterals(mcCommonLiterals); - this.traverser.setMCCommonLiteralsHandler(mcCommonLiterals); - - MCCommonStatementsPrettyPrinter mcCommonStatements = new MCCommonStatementsPrettyPrinter(printer); - this.traverser.add4MCCommonStatements(mcCommonStatements); - this.traverser.setMCCommonStatementsHandler(mcCommonStatements); - - MCFullGenericTypesPrettyPrinter mcFullGenericTypes = new MCFullGenericTypesPrettyPrinter(printer); - this.traverser.add4MCFullGenericTypes(mcFullGenericTypes); - this.traverser.setMCFullGenericTypesHandler(mcFullGenericTypes); - - MCAssertStatementsPrettyPrinter mcAssertStatements = new MCAssertStatementsPrettyPrinter(printer); - this.traverser.add4MCAssertStatements(mcAssertStatements); - this.traverser.setMCAssertStatementsHandler(mcAssertStatements); - - MCExceptionStatementsPrettyPrinter mcExceptionStatements = new MCExceptionStatementsPrettyPrinter(printer); - this.traverser.add4MCExceptionStatements(mcExceptionStatements); - this.traverser.setMCExceptionStatementsHandler(mcExceptionStatements); - - MCJavaLiteralsPrettyPrinter mcJavaLiterals = new MCJavaLiteralsPrettyPrinter(printer); - this.traverser.add4MCJavaLiterals(mcJavaLiterals); - this.traverser.setMCJavaLiteralsHandler(mcJavaLiterals); - - MCLowLevelStatementsPrettyPrinter mcLowLevelStatements = new MCLowLevelStatementsPrettyPrinter(printer); - this.traverser.add4MCLowLevelStatements(mcLowLevelStatements); - this.traverser.setMCLowLevelStatementsHandler(mcLowLevelStatements); - - MCReturnStatementsPrettyPrinter mcReturnStatements = new MCReturnStatementsPrettyPrinter(printer); - this.traverser.add4MCReturnStatements(mcReturnStatements); - this.traverser.setMCReturnStatementsHandler(mcReturnStatements); - - MCSimpleGenericTypesPrettyPrinter mcSimpleGenericTypes = new MCSimpleGenericTypesPrettyPrinter(printer); - this.traverser.add4MCSimpleGenericTypes(mcSimpleGenericTypes); - this.traverser.setMCSimpleGenericTypesHandler(mcSimpleGenericTypes); - - MCSynchronizedStatementsPrettyPrinter mcSynchronizedStatements = new MCSynchronizedStatementsPrettyPrinter(printer); - this.traverser.add4MCSynchronizedStatements(mcSynchronizedStatements); - this.traverser.setMCSynchronizedStatementsHandler(mcSynchronizedStatements); - - MCVarDeclarationStatementsPrettyPrinter mcVarDeclarationStatements = new MCVarDeclarationStatementsPrettyPrinter(printer); - this.traverser.add4MCVarDeclarationStatements(mcVarDeclarationStatements); - this.traverser.setMCVarDeclarationStatementsHandler(mcVarDeclarationStatements); - - - JavaDSLPrettyPrinter javaDSL = new JavaDSLPrettyPrinter(printer); - this.traverser.add4JavaDSL(javaDSL); - this.traverser.setJavaDSLHandler(javaDSL); - } - - public IndentPrinter getPrinter() { - return this.printer; - } - - public JavaDSLTraverser getTraverser() { - return this.traverser; - } - - public void setTraverser(JavaDSLTraverser traverser) { - this.traverser = traverser; - } - - public String prettyprint(ASTJavaDSLNode node) { - getPrinter().clearBuffer(); - node.accept(getTraverser()); - return getPrinter().getContent(); - } - -} \ No newline at end of file diff --git a/javaDSL/src/main/java/de/monticore/java/prettyprint/JavaDSLPrettyPrinter.java b/javaDSL/src/main/java/de/monticore/java/prettyprint/JavaDSLPrettyPrinter.java deleted file mode 100644 index ce3b39e5..00000000 --- a/javaDSL/src/main/java/de/monticore/java/prettyprint/JavaDSLPrettyPrinter.java +++ /dev/null @@ -1,671 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ - -package de.monticore.java.prettyprint; - -import java.util.Iterator; - -import de.monticore.ast.ASTNode; -import de.monticore.java.javadsl._ast.*; -import de.monticore.java.javadsl._visitor.JavaDSLHandler; -import de.monticore.java.javadsl._visitor.JavaDSLTraverser; -import de.monticore.java.javadsl._visitor.JavaDSLVisitor2; -import de.monticore.prettyprint.CommentPrettyPrinter; -import de.monticore.prettyprint.IndentPrinter; - -import de.monticore.statements.mccommonstatements._ast.ASTConstantsMCCommonStatements; -import de.monticore.types.mcbasictypes._ast.ASTMCBasicTypesNode; -import de.monticore.types.mccollectiontypes._ast.ASTMCTypeArgument; -import de.se_rwth.commons.Names; - -public class JavaDSLPrettyPrinter implements JavaDSLVisitor2, JavaDSLHandler { - - private JavaDSLTraverser traverser; - - @Override - public JavaDSLTraverser getTraverser() { - return this.traverser; - } - - @Override - public void setTraverser(JavaDSLTraverser traverser) { - this.traverser = traverser; - } - - private boolean WRITE_COMMENTS = false; - - protected IndentPrinter printer; - - public JavaDSLPrettyPrinter(IndentPrinter printer) { - this.printer = printer; - } - - public IndentPrinter getPrinter() { - return this.printer; - } - - public void setPrinter(IndentPrinter printer) { - this.printer = printer; - } - - protected void printNode(String s) { - getPrinter().print(s); - } - - protected void printList(Iterator iter, String seperator) { - // print by iterate through all items - String sep = ""; - while (iter.hasNext()) { - getPrinter().print(sep); - iter.next().accept(getTraverser()); - sep = seperator; - } - } - - @Override - public void handle(ASTOrdinaryCompilationUnit a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - if (a.isPresentPackageDeclaration()) { - a.getPackageDeclaration().accept(getTraverser()); - } - printSeparated(a.getImportDeclarationList().iterator(), ""); - printSeparated(a.getTypeDeclarationList().iterator(), ""); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTModularCompilationUnit node) { - CommentPrettyPrinter.printPreComments(node, getPrinter()); - printSeparated(node.getImportDeclarationList().iterator(), ""); - node.getModuleDeclaration().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(node, getPrinter()); - } - - @Override - public void handle(ASTPackageDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getAnnotationList().iterator(), ""); - getPrinter().print("package "); - getPrinter().print(Names.getQualifiedName(a.getMCQualifiedName().getPartsList())); - getPrinter().println(";"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTInterfaceDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - getPrinter().print("interface "); - printNode(a.getName()); - if (a.isPresentTypeParameters()) { - a.getTypeParameters().accept(getTraverser()); - } - if (!a.getExtendedInterfaceList().isEmpty()) { - getPrinter().print(" extends "); - printList(a.getExtendedInterfaceList().iterator(), ", "); - } - a.getInterfaceBody().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTInterfaceBody a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println(" {"); - getPrinter().indent(); - printSeparated(a.getInterfaceBodyDeclarationList().iterator(), ""); - getPrinter().unindent(); - getPrinter().println("}"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTClassBlock a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - if (a.isStatic()) { - getPrinter().print("static "); - } - a.getJavaBlock().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTClassDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - getPrinter().print("class "); - printNode(a.getName()); - if (a.isPresentTypeParameters()) { - a.getTypeParameters().accept(getTraverser()); - } - if (a.isPresentSuperClass()) { - getPrinter().print(" extends "); - a.getSuperClass().accept(getTraverser()); - } - if (!a.getImplementedInterfaceList().isEmpty()) { - getPrinter().print(" implements "); - printList(a.getImplementedInterfaceList().iterator(), ", "); - } - - a.getClassBody().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTClassBody a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println("{"); - getPrinter().indent(); - printSeparated(a.getClassBodyDeclarationList().iterator(), ""); - getPrinter().unindent(); - getPrinter().println("}"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTAnnotationTypeDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - getPrinter().print("@ interface "); - printNode(a.getName()); - a.getAnnotationTypeBody().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTAnnotationTypeBody a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println(" {"); - getPrinter().indent(); - printSeparated(a.getAnnotationTypeElementDeclarationList().iterator(), ""); - getPrinter().unindent(); - getPrinter().println("}"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTEnumDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - getPrinter().print("enum "); - printNode(a.getName()); - if (!a.getImplementedInterfaceList().isEmpty()) { - getPrinter().print(" implements "); - printList(a.getImplementedInterfaceList().iterator(), ""); - } - - getPrinter().println(" {"); - getPrinter().indent(); - printSeparated(a.getEnumConstantDeclarationList().iterator(), ", "); - if (a.isPresentEnumBody()) { - a.getEnumBody().accept(getTraverser()); - } - getPrinter().unindent(); - getPrinter().println("}"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTEnumBody a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println(";"); - printSeparated(a.getClassBodyDeclarationList().iterator(), ""); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTEnumConstantDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getAnnotationList().iterator(), ""); - printNode(a.getName()); - if (a.isPresentArguments()) { - a.getArguments().accept(getTraverser()); - } - if (a.isPresentClassBody()) { - a.getClassBody().accept(getTraverser()); - } - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTArrayInitializer a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().print("{"); - printSeparated(a.getVariableInititializerOrExpressionList().iterator(), ", "); - getPrinter().print("}"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTAnnotationMethod a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - a.getMCType().accept(getTraverser()); - getPrinter().print(" "); - printNode(a.getName()); - getPrinter().print("()"); - if (a.isPresentDefaultValue()) { - a.getDefaultValue().accept(getTraverser()); - } - getPrinter().print(";"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTAnnotationConstant a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - a.getMCType().accept(getTraverser()); - printSeparated(a.getVariableDeclaratorList().iterator(), ", "); - getPrinter().println(""); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTDefaultValue a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().print(" default "); - a.getElementValueOrExpr().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTJavaBlock a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println("{"); - getPrinter().indent(); - printSeparated(a.getMCBlockStatementList().iterator(), ""); - getPrinter().unindent(); - getPrinter().println("}"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTLabeledStatement a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printNode(a.getLabel()); - getPrinter().print(": "); - a.getStatement().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTTryStatement a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println("try "); - a.getJavaBlock().accept(getTraverser()); - getPrinter().println(); - a.getExceptionHandler().accept(getTraverser()); - getPrinter().println(); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTCatchExceptionsHandler a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getCatchClauseList().iterator(), ""); - if (a.isPresentFinallyBlock()) { - getPrinter().println(); - getPrinter().println("finally"); - getPrinter().indent(); - a.getFinallyBlock().accept(getTraverser()); - getPrinter().unindent(); - } - getPrinter().println(); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTFinallyBlockOnlyHandler a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().println("finally"); - getPrinter().indent(); - a.getFinallyBlock().accept(getTraverser()); - getPrinter().unindent(); - getPrinter().println(); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTTryStatementWithResources a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().print("try ("); - printSeparated(a.getResourceList().iterator(), ";"); - getPrinter().println(") "); - a.getJavaBlock().accept(getTraverser()); - printSeparated(a.getCatchClauseList().iterator(), ""); - if (a.isPresentFinallyBlock()) { - getPrinter().println(); - getPrinter().println("finally"); - getPrinter().indent(); - a.getFinallyBlock().accept(getTraverser()); - getPrinter().unindent(); - } - getPrinter().println(); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTResource a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - a.getMCType().accept(getTraverser()); - a.getDeclaratorId().accept(getTraverser()); - getPrinter().print(" = "); - a.getExpression().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTIdentifierAndTypeArgument a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printNode(a.getName()); - if (a.isPresentTypeArguments()) { - a.getTypeArguments().accept(getTraverser()); - } - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTTypeArguments a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().print(("<")); - String sep = ""; - for (ASTMCTypeArgument typeArg : a.getMCTypeArgumentList()) { - getPrinter().print(sep); - typeArg.accept(getTraverser()); - } - getPrinter().print((">")); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTFieldDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getJavaModifierList().iterator(), " "); - a.getMCType().accept(getTraverser()); - getPrinter().print(" "); - printSeparated(a.getVariableDeclaratorList().iterator(), ", "); - getPrinter().println(";"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTConstantDeclarator a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printNode(a.getName()); - for (int i = 0; i < a.getDimList().size(); i++) { - getPrinter().print("[] "); - } - getPrinter().print(" = "); - a.getVariableInititializerOrExpression().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTImportDeclaration a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().print("import "); - if (a.isStatic()) { - getPrinter().print("static "); - } - a.getMCQualifiedName().accept(getTraverser()); - if (a.isSTAR()) { - getPrinter().print(".*"); - } - getPrinter().println(";"); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - -// @Override -// public void handle(ASTEmptyDeclaration a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// getPrinter().print(");"); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } - -// @Override -// public void handle(ASTAssertStatement a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// getPrinter().print("assert "); -// a.getAssertion().accept(getTraverser()); -// if (a.isPresentMessage()) { -// getPrinter().print(" : "); -// a.getMessage().accept(getTraverser()); -// } -// getPrinter().println(";"); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } - -// @Override -// public void handle(ASTContinueStatement a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// getPrinter().print("continue"); -// if (a.isPresentLabel()) { -// printNode(a.getLabel()); -// } -// getPrinter().println(";"); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } - -// @Override -// public void handle(ASTSynchronizedStatement a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// getPrinter().print("synchronized ("); -// a.getExpression().accept(getTraverser()); -// getPrinter().print(") "); -// a.getJavaBlock().accept(getTraverser()); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } - -// @Override -// public void handle(ASTThrowStatement a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// getPrinter().print("throw "); -// a.getExpression().accept(getTraverser()); -// getPrinter().println(";"); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } - -// @Override -// public void handle(ASTCatchClause a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// getPrinter().print("catch ("); -// printSeparated(a.getPrimitiveModifierList().iterator(), " "); -// a.getCatchType().accept(getTraverser()); -// getPrinter().print(" "); -// printNode(a.getName()); -// getPrinter().print(") "); -// a.getJavaBlock().accept(getTraverser()); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } -// -// @Override -// public void handle(ASTCatchType a) { -// CommentPrettyPrinter.printPreComments(a, getPrinter()); -// printList(a.getMCQualifiedNameList().iterator(), "|"); -// CommentPrettyPrinter.printPostComments(a, getPrinter()); -// } - - @Override - public void handle(ASTCreatedName a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - printSeparated(a.getIdentifierAndTypeArgumentList().iterator(), "."); - if (a.isPresentMCPrimitiveType()) { - a.getMCPrimitiveType().accept(getTraverser()); - } - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTInnerCreator a) { - CommentPrettyPrinter.printPreComments(a, getPrinter()); - getPrinter().print("new "); - if (a.isPresentFirstTypeArguments()) { - a.getFirstTypeArguments().accept(getTraverser()); - } - printNode(a.getName()); - if (a.isPresentSecondTypeArguments()) { - a.getSecondTypeArguments().accept(getTraverser()); - } - a.getClassCreatorRest().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(a, getPrinter()); - } - - @Override - public void handle(ASTAnnotatedDimension node) { - printSeparated(node.getAnnotationList().iterator(), " "); - getPrinter().print("[]"); - } - - @Override - public void handle(ASTAnnotatedName node) { - printSeparated(node.getAnnotationList().iterator(), " "); - getPrinter().print(node.getName()); - } - - @Override - public void handle(ASTMCArrayType node) { - node.getMCType().accept(getTraverser()); - - if (!node.isEmptyAnnotatedDimensions()) { - printSeparated(node.getAnnotatedDimensionList().iterator(), " "); - } else { - for (int i = 0; i < node.getDimensions(); i++) { - getPrinter().print("[]"); - } - } - } - - @Override - public void handle(ASTMCBasicGenericType node) { - if (!node.isEmptyAnnotatedNames()) { - printSeparated(node.getAnnotatedNameList().iterator(), "."); - } else { - getPrinter().print(String.join(".", node.getNameList())); - } - - getPrinter().print("<"); - printSeparated(node.getMCTypeArgumentList().iterator(), ", "); - getPrinter().print(">"); - } - - @Override - public void handle(ASTMCQualifiedType node) { - if (!node.isEmptyAnnotatedNames()) { - printSeparated(node.getAnnotatedNameList().iterator(), "."); - } else { - node.getMCQualifiedName().accept(getTraverser()); - } - } - - @Override - public void handle(ASTExtType node) { - CommentPrettyPrinter.printPreComments(node, getPrinter()); - node.getMCType().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(node, getPrinter()); - } - - @Override - public void handle(ASTExtLiteral node) { - CommentPrettyPrinter.printPreComments(node, getPrinter()); - node.getLiteral().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(node, getPrinter()); - } - - @Override - public void handle(ASTExtReturnType node) { - CommentPrettyPrinter.printPreComments(node, getPrinter()); - node.getMCReturnType().accept(getTraverser()); - CommentPrettyPrinter.printPostComments(node, getPrinter()); - } - - @Override - public void handle(ASTMethodReferenceExpression node) { - if (node.isPresentExpression()) { - node.getExpression().accept(getTraverser()); - } else if (node.isPresentMCType()) { - node.getMCType().accept(getTraverser()); - } - - getPrinter().print("::"); - - if (node.isPresentTypeArguments()) { - node.getTypeArguments().accept(getTraverser()); - } - - node.getMethodReferenceTarget().accept(getTraverser()); - } - - @Override - public void visit(ASTConstructorReferenceTarget node) { - getPrinter().print("new"); - } - - @Override - public void handle(ASTMethodNameReferenceTarget node) { - getPrinter().print(node.getName()); - } - - protected void printSeparated(Iterator iter, String separator) { - // print by iterate through all items - String sep = ""; - while (iter.hasNext()) { - getPrinter().print(sep); - iter.next().accept(getTraverser()); - sep = separator; - } - } - - public void setWriteComments(boolean wc) { - WRITE_COMMENTS = wc; - } - - public boolean isWriteCommentsEnabeled() { - return WRITE_COMMENTS; - } - - /** - * This method prettyprints a given node from Java. - * - * @param a A node from Java. - * @return String representation. - */ - public String prettyprint(ASTJavaDSLNode a) { - getPrinter().clearBuffer(); - a.accept(getTraverser()); - return getPrinter().getContent(); - } - - private String printModifier(int constant) { - switch (constant) { - case ASTConstantsMCCommonStatements.PRIVATE: - return "private"; - case ASTConstantsMCCommonStatements.PUBLIC: - return "public"; - case ASTConstantsMCCommonStatements.PROTECTED: - return "protected"; - case ASTConstantsMCCommonStatements.STATIC: - return "static"; - case ASTConstantsMCCommonStatements.TRANSIENT: - return "transient"; - case ASTConstantsMCCommonStatements.FINAL: - return "final"; - case ASTConstantsMCCommonStatements.ABSTRACT: - return "abstract"; - case ASTConstantsMCCommonStatements.NATIVE: - return "native"; - case ASTConstantsMCCommonStatements.THREADSAFE: - return "threadsafe"; - case ASTConstantsMCCommonStatements.SYNCHRONIZED: - return "synchronized"; - case ASTConstantsMCCommonStatements.VOLATILE: - return "volatile"; - case ASTConstantsMCCommonStatements.STRICTFP: - return "strictfp"; - default: - return null; - } - - } - -} diff --git a/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSL2ODDelegator.java b/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSL2ODDelegator.java index 2dde4869..e3c10b3d 100644 --- a/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSL2ODDelegator.java +++ b/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSL2ODDelegator.java @@ -10,15 +10,11 @@ import de.monticore.java.javadsl._ast.ASTCompilationUnit; import de.monticore.java.javadsl._od.JavaDSL2OD; import de.monticore.java.javadsl._visitor.JavaDSLTraverser; -import de.monticore.java.prettyprint.JavaDSLPrettyPrinter; import de.monticore.javalight._od.JavaLight2OD; import de.monticore.literals.mccommonliterals._od.MCCommonLiterals2OD; import de.monticore.literals.mcjavaliterals._od.MCJavaLiterals2OD; -import de.monticore.literals.prettyprint.MCCommonLiteralsPrettyPrinter; -import de.monticore.literals.prettyprint.MCJavaLiteralsPrettyPrinter; import de.monticore.mcbasics._od.MCBasics2OD; import de.monticore.prettyprint.IndentPrinter; -import de.monticore.prettyprint.MCBasicsPrettyPrinter; import de.monticore.statements.mcarraystatements._od.MCArrayStatements2OD; import de.monticore.statements.mcassertstatements._od.MCAssertStatements2OD; import de.monticore.statements.mccommonstatements._od.MCCommonStatements2OD; @@ -27,13 +23,11 @@ import de.monticore.statements.mcreturnstatements._od.MCReturnStatements2OD; import de.monticore.statements.mcsynchronizedstatements._od.MCSynchronizedStatements2OD; import de.monticore.statements.mcvardeclarationstatements._od.MCVarDeclarationStatements2OD; -import de.monticore.statements.prettyprint.*; import de.monticore.types.mcarraytypes._od.MCArrayTypes2OD; import de.monticore.types.mcbasictypes._od.MCBasicTypes2OD; import de.monticore.types.mccollectiontypes._od.MCCollectionTypes2OD; import de.monticore.types.mcfullgenerictypes._od.MCFullGenericTypes2OD; import de.monticore.types.mcsimplegenerictypes._od.MCSimpleGenericTypes2OD; -import de.monticore.types.prettyprint.*; public final class JavaDSL2ODDelegator { diff --git a/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSLNodeIdentHelper.java b/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSLNodeIdentHelper.java index b21bdbce..90ac2169 100644 --- a/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSLNodeIdentHelper.java +++ b/javaDSL/src/main/java/de/monticore/java/reporting/JavaDSLNodeIdentHelper.java @@ -19,6 +19,7 @@ import de.monticore.types.mcbasictypes.MCBasicTypesMill; import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedName; +import de.monticore.types.typeparameters._ast.ASTTypeParameters; public class JavaDSLNodeIdentHelper extends ASTNodeIdentHelper { @@ -138,7 +139,7 @@ public String getIdent(ASTMCQualifiedName node) { public String getIdent(ASTMCPrimitiveType node) { String type = Layouter.nodeName(node); - String name = node.printType(MCBasicTypesMill.mcBasicTypesPrettyPrinter()); + String name = node.printType(); return format(name, type); } diff --git a/javaDSL/src/main/java/de/monticore/java/utils/TextBlockUtils.java b/javaDSL/src/main/java/de/monticore/java/utils/TextBlockUtils.java new file mode 100644 index 00000000..2f401061 --- /dev/null +++ b/javaDSL/src/main/java/de/monticore/java/utils/TextBlockUtils.java @@ -0,0 +1,169 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.java.utils; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** Utilities for text blocks. */ +public class TextBlockUtils { + + /* + * These methods are implemented according to JEP378. In Java 15+, there are + * built-in methods that provide the same functionality. Namely: + * - String#stripIndent(), and + * - String#translateEscapes(). + * + * The code below can be considered a port of these to Java 11 and can be + * replaced once we make the jump past 15. + * + * See also: https://openjdk.org/jeps/378 + */ + + /** + * Reformats the given {@code String} by performing the same processing steps + * as the compiler does for text blocks. + * + * @param s the input string + * @return the processed text block + */ + public static String preprocessTextBlock(String s) { + return translateEscapes(stripIndent(s)); + } + + private static String stripIndent(String string) { + int length = string.length(); + if (length == 0) return ""; + + char lastChar = string.charAt(length - 1); + boolean optOut = lastChar == '\n' || lastChar == '\r'; + + /* + * Note: Additionally make sure to skip the first line. + * This is happening in the compiler but not in String#stripIndent(). + */ + List lines = string.lines().skip(1).collect(Collectors.toUnmodifiableList()); + + final int outdent = optOut ? 0 : outdent(lines); + return lines.stream() + .map(line -> { + int firstNonWhitespace = indexOfNonWhitespace(line); + int lastNonWhitespace = lastIndexOfNonWhitespace(line); + int incidentalWhitespace = Math.min(outdent, firstNonWhitespace); + return firstNonWhitespace > lastNonWhitespace + ? "" : line.substring(incidentalWhitespace, lastNonWhitespace); + }) + .collect(Collectors.joining("\n", "", optOut ? "\n" : "")); + } + + private static int outdent(List lines) { + System.out.println(lines); + + // Note: outdent is guaranteed to be zero or positive number. + // If there isn't a non-blank line then the last must be blank + int outdent = Integer.MAX_VALUE; + + for (String line : lines) { + int leadingWhitespace = indexOfNonWhitespace(line); + + if (leadingWhitespace != line.length()) { + outdent = Integer.min(outdent, leadingWhitespace); + } + } + + String lastLine = lines.get(lines.size() - 1); + + if (lastLine.isBlank()) { + outdent = Integer.min(outdent, lastLine.length()); + } + + return outdent; + } + + private static int indexOfNonWhitespace(String string) { + return string.codePoints() + .takeWhile(cp -> cp == ' ' || cp == '\t' || Character.isWhitespace(cp)) + .map(Character::charCount) + .sum(); + } + + private static int lastIndexOfNonWhitespace(String string) { + List cps = string.codePoints().boxed().collect(Collectors.toUnmodifiableList()); + + return string.length() - IntStream.range(0, cps.size()) + .map(i -> cps.get(cps.size() - i - 1)) + .takeWhile(cp -> cp == ' ' || cp == '\t' || Character.isWhitespace(cp)) + .map(Character::charCount) + .sum(); + } + + private static String translateEscapes(String string) { + if (string.isEmpty()) return ""; + + char[] chars = string.toCharArray(); + int length = chars.length; + int from = 0; + int to = 0; + + while (from < length) { + char ch = chars[from++]; + + if (ch == '\\') { + ch = from < length ? chars[from++] : '\0'; + + switch (ch) { + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 's': + ch = ' '; + break; + case 't': + ch = '\t'; + break; + case '\'': + case '\"': + case '\\': + // as is + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + int limit = Integer.min(from + (ch <= '3' ? 2 : 1), length); + int code = ch - '0'; + while (from < limit) { + ch = chars[from]; + if (ch < '0' || '7' < ch) break; + + from++; + code = (code << 3) | (ch - '0'); + } + ch = (char) code; + break; + case '\n': + continue; + case '\r': + if (from < length && chars[from] == '\n') from++; + continue; + default: { + String msg = String.format("Invalid escape sequence: \\%c \\\\u%04X", ch, (int) ch); + throw new IllegalArgumentException(msg); + } + } + } + + chars[to++] = ch; + } + + return new String(chars, 0, to); + } + +} diff --git a/javaDSL/src/main/resources/java2cd/Java2CD.ftl b/javaDSL/src/main/resources/java2cd/Java2CD.ftl new file mode 100644 index 00000000..d90f0ca4 --- /dev/null +++ b/javaDSL/src/main/resources/java2cd/Java2CD.ftl @@ -0,0 +1,18 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("glex", "converter", "hwPath", "generator")} + + +<#assign cdData=converter.doConvert(ast, glex)> + + +<#--<#assign topDecorator = tc.instantiate("de.monticore.cd.codegen.TopDecorator", [hwPath])> +${topDecorator.decorate(cdata.getCompilationUnit())}--> + + +${generator.generate(cdData.getCompilationUnit())} diff --git a/javaDSL/src/test/java/de/monticore/java/CorpusTest.java b/javaDSL/src/test/java/de/monticore/java/CorpusTest.java index fcc773e2..0a4e63ee 100644 --- a/javaDSL/src/test/java/de/monticore/java/CorpusTest.java +++ b/javaDSL/src/test/java/de/monticore/java/CorpusTest.java @@ -24,6 +24,11 @@ */ public final class CorpusTest extends AbstractTest { + /* + * To learn more about corpus tests, please refer to: + * /src/main/grammars/de/monticore/java/JavaDSL.md + */ + private static List provideFilesForCorpusTests() throws IOException { try (Stream stream = Files.walk(Path.of("target/corpus"))) { return stream.map(path -> Files.isRegularFile(path) ? path.toAbsolutePath().toString() : null) diff --git a/javaDSL/src/test/java/de/monticore/java/ExperimentalTest.java b/javaDSL/src/test/java/de/monticore/java/ExperimentalTest.java deleted file mode 100644 index d729547d..00000000 --- a/javaDSL/src/test/java/de/monticore/java/ExperimentalTest.java +++ /dev/null @@ -1,15 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.java; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -public class ExperimentalTest extends AbstractTest { - - @Disabled // TODO This fails because of a core grammar issue. Need to decide on how to handle this - @Test - public void testMyModel() { - JavaDSLTool.main(new String[] { "src/test/resources/experimentalTestModels/MyModel.java" }); - } - -} diff --git a/javaDSL/src/test/java/de/monticore/java/JavaDSLParserTest.java b/javaDSL/src/test/java/de/monticore/java/JavaDSLParserTest.java index 775aef77..218ff097 100644 --- a/javaDSL/src/test/java/de/monticore/java/JavaDSLParserTest.java +++ b/javaDSL/src/test/java/de/monticore/java/JavaDSLParserTest.java @@ -4,7 +4,9 @@ import de.monticore.expressions.expressionsbasis._ast.ASTExpression; import de.monticore.java.javadsl._ast.ASTCompilationUnit; import de.monticore.java.javadsl._ast.ASTJavaBlock; +import de.monticore.java.javadsl._ast.ASTTextBlockLiteral; import de.monticore.java.javadsl._parser.JavaDSLParser; +import de.monticore.literals.mcliteralsbasis._ast.ASTLiteral; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -113,4 +115,24 @@ public void testModuleDeclaration() { assertParsingSuccess("src/test/resources/moduleDeclaration/module-info.java"); } + @Test + public void testTextBlocks() throws IOException { + String textBlock = "\"\"\"" + "\n" + + "\t\tHello World" + "\n" + + "\t\t\tIndented" + "\n" + + "\"\"\""; + + JavaDSLParser parser = new JavaDSLParser(); + Optional optLiteral = parser.parse_StringLiteral(textBlock); + + assertTrue(optLiteral.isPresent()); + + ASTLiteral literal = optLiteral.get(); + assertInstanceOf(ASTTextBlockLiteral.class, literal); + assertEquals( + "Hello World\n\tIndented", + ((ASTTextBlockLiteral) literal).getSource() + ); + } + } diff --git a/javaDSL/src/test/java/de/monticore/java/JavaDSLPrettyPrinterTest.java b/javaDSL/src/test/java/de/monticore/java/JavaDSLPrettyPrinterTest.java index 6f447c54..30c95425 100644 --- a/javaDSL/src/test/java/de/monticore/java/JavaDSLPrettyPrinterTest.java +++ b/javaDSL/src/test/java/de/monticore/java/JavaDSLPrettyPrinterTest.java @@ -1,11 +1,10 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.java; +import de.monticore.java.javadsl.JavaDSLMill; import de.monticore.java.javadsl._ast.ASTCompilationUnit; import de.monticore.java.javadsl._ast.ASTJavaDSLNode; import de.monticore.java.javadsl._parser.JavaDSLParser; -import de.monticore.java.prettyprint.JavaDSLFullPrettyPrinter; -import de.monticore.prettyprint.IndentPrinter; import java.io.IOException; import java.io.StringReader; @@ -42,8 +41,7 @@ public void test1() throws IOException { ASTJavaDSLNode ast = parse("src/test/resources/de/monticore/java/parser/ASTClassDeclaration.java"); // Prettyprinting input - JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); - String output = prettyPrinter.prettyprint(ast); + String output = JavaDSLMill.prettyPrint(ast, false); // Parsing printed input ASTJavaDSLNode printedAST = parse(new StringReader(output)); @@ -56,8 +54,7 @@ public void test2() throws IOException { ASTJavaDSLNode ast = parse("src/test/resources/de/monticore/java/parser/ParseException.java"); // Prettyprinting input - JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); - String output = prettyPrinter.prettyprint(ast); + String output = JavaDSLMill.prettyPrint(ast, false); // Parsing printed input ASTJavaDSLNode printedAST = parse(new StringReader(output)); @@ -70,8 +67,7 @@ public void test3() throws IOException { ASTJavaDSLNode ast = parse("src/test/resources/de/monticore/java/parser/TokenMgrError.java"); // Prettyprinting input - JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); - String output = prettyPrinter.prettyprint(ast); + String output = JavaDSLMill.prettyPrint(ast, false); // Parsing printed input ASTJavaDSLNode printedAST = parse(new StringReader(output)); @@ -84,8 +80,7 @@ public void test4() throws IOException { ASTJavaDSLNode ast = parse("src/test/resources/parsableAndCompilableModels/simpleTestClasses/HelloWorld.java"); // Prettyprinting input - JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); - String output = prettyPrinter.prettyprint(ast); + String output = JavaDSLMill.prettyPrint(ast, false); // Parsing printed input ASTJavaDSLNode printedAST = parse(new StringReader(output)); diff --git a/javaDSL/src/test/java/de/monticore/java/JavaDSLToolTest.java b/javaDSL/src/test/java/de/monticore/java/JavaDSLToolTest.java new file mode 100644 index 00000000..9563fc00 --- /dev/null +++ b/javaDSL/src/test/java/de/monticore/java/JavaDSLToolTest.java @@ -0,0 +1,42 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.java; + +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cd4code._parser.CD4CodeParser; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTMCQualifiedType; +import de.monticore.java.javadsl._parser.JavaDSLParser; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JavaDSLToolTest { + + @Test + public void testToolWithTestClass() { + JavaDSLTool.main(new String[] { + "-i", + "src/test/resources/de/monticore/java/parser/Test.java", + "-o", + "target/generator-output" + }); + } + + @Test + public void testToolWithASTClassDeclarationClass() { + JavaDSLTool.main(new String[] { + "-i", + "src/test/resources/de/monticore/java/parser/ASTClassDeclaration.java", + "-o", + "target/generator-output" + }); + } + +} diff --git a/javaDSL/src/test/resources/de/monticore/java/parser/Test.java b/javaDSL/src/test/resources/de/monticore/java/parser/Test.java new file mode 100644 index 00000000..9fb337a7 --- /dev/null +++ b/javaDSL/src/test/resources/de/monticore/java/parser/Test.java @@ -0,0 +1,82 @@ +package de.monticore.foo.bla; + +import java.util.List; +import java.math.BigInteger; + +import de.monticore.cd4code.CD4CodeMill; + +public class Test { + + public String text = "Hello World!"; + + public static String text1 = "Hello World!"; + + public final String text2 = "Hello World!"; + + public static final String text3 = "Hello World!"; + + protected String text4 = "Hello World!"; + + protected static String text5 = "Hello World!"; + + protected final String text6 = "Hello World!"; + + protected static final String text7 = "Hello World!"; + + private String text8 = "Hello World!"; + + private static String text9 = "Hello World!"; + + private final String text10 = "Hello World!"; + + private static final String text11 = "Hello World!"; + + String text12 = "Hello World!"; + + static String text13 = "Hello World!"; + + final String text14 = "Hello World!"; + + static final String text15 = "Hello World!"; + + public int[][] myArray = {{1, 2, 3}, {4, 5, 6}}, mySecondArray = {{1, 2}, {3, 4}, {5, 6, 7, 8}}; + + public void hello() { + System.out.println(text); + } + + public static void hello1() { + System.out.println(text1); + } + + private void hello2() { + System.out.println(text); + } + + private static void hello3() { + System.out.println(text1); + } + + protected void hello4() { + System.out.println(text); + } + + protected static void hello5() { + System.out.println(text1); + } + + void hello6() { + System.out.println(text); + } + + static void hello7() { + System.out.println(text1); + } + + public Test(final int a, String b, List c) { + a++; + b = b.substring(2, 3); + c.add(true); + } + +} \ No newline at end of file diff --git a/javaDSL/src/test/resources/experimentalTestModels/MyModel.java b/javaDSL/src/test/resources/experimentalTestModels/MyModel.java deleted file mode 100644 index 556102be..00000000 --- a/javaDSL/src/test/resources/experimentalTestModels/MyModel.java +++ /dev/null @@ -1,13 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ - -package experimentalTestModels; - -class HelloWorld { - public static void main(String[] args) { - System.out.println("Hello World!"); - } - - void method(Integer blub[], Integer... ints[]) { - - } -} diff --git a/ref-code-adaptation/.gitignore b/ref-code-adaptation/.gitignore new file mode 100644 index 00000000..ff1b88c1 --- /dev/null +++ b/ref-code-adaptation/.gitignore @@ -0,0 +1,44 @@ +/out +/target +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/ref-code-adaptation/build.gradle b/ref-code-adaptation/build.gradle new file mode 100644 index 00000000..09a7c560 --- /dev/null +++ b/ref-code-adaptation/build.gradle @@ -0,0 +1,98 @@ +import com.github.sherter.googlejavaformatgradleplugin.VerifyGoogleJavaFormat + +plugins { + id 'java' + id 'java-gradle-plugin' + + id 'monticore' version "$version" + id 'com.github.johnrengelman.shadow' version "7.1.2" + id 'maven-publish' + id "com.github.sherter.google-java-format" version "0.9" // Task "verifyGoogleJavaFormat" and "googleJavaFormat" + +} + +dependencies { + + implementation group: 'de.se_rwth.commons', name: 'se-commons-logging', version:version + implementation group: 'de.monticore', name: 'monticore-runtime', version: version + implementation group: 'de.monticore', name: 'monticore-grammar', version: version + implementation group: 'de.monticore', name: 'class2mc', version: version + implementation group: 'de.monticore.lang', name: 'cd4analysis', version: version + implementation group: 'de.monticore', name: 'javaDSL', version: version + implementation group: 'de.monticore.lang', name: 'od',version: version + implementation group: 'com.google.guava', name: 'guava', version: '31.1-jre' + implementation 'fr.inria.gforge.spoon:spoon-core:10.2.0' + + + + implementation "org.apache.commons:commons-lang3:3.9" + + implementation 'org.junit.jupiter:junit-jupiter:5.9.0' + implementation 'de.monticore.lang:cd4analysis:$version:cddiff' + implementation 'de.monticore.lang:cd4analysis:$version:tool' + + + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit.jupiter.params) + testRuntimeOnly(libs.junit.jupiter.engine) + + + + + //implementation "org.codehaus.groovy:groovy:$groovy_version" + //implementation "de.se_rwth.commons:se-commons-groovy:3.0.7" + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' + grammar("de.monticore.lang:cd4analysis:$version") { + } + grammar("de.monticore:monticore-grammar:$version") { + } +} + +shadowJar { // all in one jar + manifest { + attributes "Main-Class": "de.monticore.codeAdaption.CodeAdapterTool" + } + archiveClassifier = 'cli' + archiveFileName = "CodeAdapter.jar" + zip64 = true +// minimize() + duplicatesStrategy DuplicatesStrategy.INCLUDE +} + +test { + useJUnitPlatform() +} + +group = 'refCodeAdaptation' +repositories { + if(("true").equals(getProperty('useLocalRepo'))) { + mavenLocal() + } + maven { + credentials.username mavenUser + credentials.password mavenPassword + url repo + } + mavenCentral() +} + +description = 'CoEvolution' +buildDir = file("$projectDir/target") + + +googleJavaFormat { + exclude '**/target/**' + exclude '**/test/resources/**' + exclude '***/test/java/model/reference/hwc/Application' +} + +verifyGoogleJavaFormat{ + ignoreFailures true + exclude "**" +} // do not check format in "build" + +tasks.register('checkfmt', VerifyGoogleJavaFormat) {} + +tasks.register('fmt') { + dependsOn tasks.named("googleJavaFormat") +} \ No newline at end of file diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java new file mode 100644 index 00000000..0aadee79 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapter.java @@ -0,0 +1,129 @@ +package de.monticore.codeAdaption; + +import static de.monticore.codeAdaption.utils.AdapterUtils.getFileName; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.codeAdaption.handler.BasicUpdateHandler; +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.updater.spoonUpdater.SpoonUpdater; +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.visitors.AnnotationRemover; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.nio.file.Path; +import java.util.*; + +public class CodeAdapter { + protected Set adapterParams; + protected Set confParams; + + public CodeAdapter(Set adapterParams, Set confParams) { + this.confParams = confParams; + this.adapterParams = adapterParams; + } + + /*** + * + * @param referenceCD the reference class diagram. + * @param concreteCD, the concrete class diagram. + * @param refHwcPath the handwritten reference-code. + * @param conHwcPath path to the concrete code, + * @param mappings different maping names. + * @param outputPath the output path + */ + public void adapt( + File referenceCD, + File concreteCD, + Set mappings, + Path refHwcPath, + Path conHwcPath, + Path outputPath) { + + // load CD models + ASTCDCompilationUnit refCD = JavaLoader.loadCD(referenceCD); + ASTCDCompilationUnit conCD = JavaLoader.loadCD(concreteCD); + + Set adaptedCode = new HashSet<>(); + + for (String mapping : mappings) { + + // check conformance + CDConformanceChecker checker = new CDConformanceChecker(confParams); + if (!checker.checkConformance(conCD, refCD, mapping)) { + Log.error("The concrete CD is not Conform to the Reference CD"); + } + + // check validity of the reference code + CodeValidator validator = new CodeValidator(refCD, adapterParams); + if (!validator.isValid(refCD, refHwcPath)) { + Log.error("The reference code is not valid for the reference CD"); + } + + // build updater and clean output directory + CodeUpdater updater = new SpoonUpdater(); + updater.setCodePath(refHwcPath); + updater.setOutputDirectory(outputPath); + JavaLoader.removeDirectory(outputPath); + + // update handler + BasicUpdateHandler handler = + new BasicUpdateHandler(refCD, conCD, conHwcPath, checker, updater, validator); + + // perform updates + handler.handleUpdate(JavaLoader.readJavaCode(refHwcPath)); + + // clean code + cleanCode(outputPath); + adaptedCode = mergeAdaptedCode(adaptedCode, JavaLoader.readJavaCode(outputPath)); + } + JavaLoader.printAST(adaptedCode, outputPath); + } + + private Set mergeAdaptedCode( + Set actualCode, Set newAdaptedCode) { + if (actualCode.isEmpty()) { + return newAdaptedCode; + } + + for (ASTOrdinaryCompilationUnit newAdapted : newAdaptedCode) { + Optional actual = + actualCode.stream().filter(f -> getFileName(f).equals(getFileName(newAdapted))).findAny(); + if (actual.isEmpty()) { + + actualCode.add(newAdapted); + } else { + actualCode.add(AdapterUtils.mergeAsts(actual.get(), newAdapted)); + } + } + return actualCode; + } + + /*** + * clean the annotations and further extra information + * in the adapted code. + * @param codePath the code path. + */ + private static void cleanCode(Path codePath) { + + Set asts = JavaLoader.readJavaCode(codePath); + + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + AnnotationRemover remover = new AnnotationRemover(); + traverser.add4JavaDSL(remover); + traverser.add4JavaLight(remover); + traverser.add4MCCommonStatements(remover); + traverser.add4MCVarDeclarationStatements(remover); + + asts.forEach(ast -> ast.accept(traverser)); + + JavaLoader.printAST(asts, codePath); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java new file mode 100644 index 00000000..14666089 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/CodeAdapterTool.java @@ -0,0 +1,102 @@ +package de.monticore.codeAdaption; + +import de.monticore.CD4CodeTool; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.se_rwth.commons.logging.Log; +import java.util.*; +import org.apache.commons.cli.*; + +public class CodeAdapterTool extends CD4CodeTool { + + /** + * Processes user input from command line and delegates to the corresponding tools. + * + * @param args The input parameters for configuring the OCL tool. + */ + @Override + public void run(String[] args) { + init(); + Options options = initOptions(); + /* + java - jar AdapterTool . jar -i " University . cd " \ + 2 -- reference " UserRole . cd " -- rc " code " + */ + + try { + // create CLI parser and parse input options from command line + CommandLineParser cliparser = new DefaultParser(); + CommandLine cmd = cliparser.parse(options, args); + + if (cmd.hasOption("i")) { + // -option developer logging + if (cmd.hasOption("d")) { + Log.initDEBUG(); + } else { + Log.init(); + } + } + + } catch (ParseException e) { + Log.error("0xA7101 Could not process CLI parameters: " + e.getMessage()); + } + } + + /*=================================================================*/ + /* Part 2: Executing arguments + /*=================================================================*/ + + /** + * Parses the contents of a given file as OCL. + * + * @param path The path to the OCL-file as String + * @return parsed AST + */ + @Override + public ASTCDCompilationUnit parse(String path) { + return null; + } + + /** + * Initializes the additional options for the OCL tool. + * + * @return The CLI options with arguments. + */ + @Override + public Options addAdditionalOptions(Options options) { + + // accept VariableSymbols + Option varSymbols = + Option.builder("i") + .longOpt("concrete") + .optionalArg(false) + .argName("concrete class diagram") + .hasArgs() + .desc("introduce the concrete class diagram") + .build(); + options.addOption(varSymbols); + + // accept FunctionSymbols + Option funcSymbols = + Option.builder("rc") + .longOpt("reference-code") + .optionalArg(false) + .argName("reference-code") + .hasArgs() + .desc("Introduce the reference code.") + .build(); + options.addOption(funcSymbols); + + // accept FunctionSymbols + Option ignoreSymbols = + Option.builder("r") + .longOpt("reference") + .optionalArg(false) + .argName("reference class diagram") + .hasArgs() + .desc("introduce the reference class diagram") + .build(); + options.addOption(ignoreSymbols); + + return options; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java new file mode 100644 index 00000000..037c5023 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/handler/BasicUpdateHandler.java @@ -0,0 +1,190 @@ +package de.monticore.codeAdaption.handler; + +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.cdbasis._symboltable.CDTypeSymbol; +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.cddiff.CDDiffUtil; +import de.monticore.codeAdaption.matcher.*; +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.nio.file.Path; +import java.util.*; +// TODO: 20.09.2023 handle concrete handwritten-code + +/*** + * this class is to handle is to handle the update operation. + * - + * 1- iterate over all adaptable code-elements (Type, field, method,local variable,formal parameters-names). + * 2- get the match of each element in the reference class diagram. + * 3- compute the concrete value of each element form the matching using the conformance checker. + * 4- use the updater to update the value in the code. + * - + * this handler assumes that each reference element has a unique incarnation. + */ +public class BasicUpdateHandler { + protected ASTCDCompilationUnit conCD; + protected ASTCDCompilationUnit refCD; + protected CDConformanceChecker checker; + protected CodeUpdater updater; + + protected CodeValidator validator; + + public BasicUpdateHandler( + ASTCDCompilationUnit refCD, + ASTCDCompilationUnit conCD, + Path conHwcPath, + CDConformanceChecker checker, + CodeUpdater updater, + CodeValidator validator) { + this.updater = updater; + this.checker = checker; + this.conCD = conCD; + this.refCD = refCD; + this.validator = validator; + } + + public void handleUpdate(Set javaFiles) { + + // Collect elements of each type + Set typeElements = new HashSet<>(); + for (ASTOrdinaryCompilationUnit ast : javaFiles) { + + // collect code elements + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + ast.accept(traverser); + typeElements.add(collector); + } + + // update local variable and method parameters + typeElements.forEach(this::handleVariableUpdate); + + // update methods and attributes + typeElements.forEach(this::handleTMemberUpdate); + + // update types + typeElements.forEach(this::handleTypeUpdate); + + updater.printCode(); + } + + protected void handleTypeUpdate(JavaAstElemCollector collector) { + // update type present in the reference code + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + Optional matching = validator.getMatchedType(type); + if (matching.isPresent() && matching.get().mustBePerform()) { + String newName = buildConcreteName(matching.get()); + updater.updateType(type, newName); + } + } + + // update type not present in the reference code + for (ASTCDType cdType : CDDiffUtil.getAllCDTypes(refCD)) { + String newName = getConTypeSymbol(cdType.getSymbol()).getName(); + updater.updateCDType(cdType, newName); + } + } + + protected void handleTMemberUpdate(JavaAstElemCollector collector) { + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + + // update method names + for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { + Optional matching = validator.getMatchedMethod(type, method); + if (matching.isPresent() && matching.get().mustBePerform()) { + String newName = buildConcreteName(matching.get()); + updater.updateMethod(type, method, newName); + } + } + + // update type parameters names + for (ASTFieldDeclaration field : collector.getAllFieldDeclarations(type)) { + Optional matching = validator.getMatchedField(type, field); + if (matching.isPresent() && matching.get().mustBePerform()) { + String newName = buildConcreteName(matching.get()); + updater.updateField(type, field, newName); + } + } + + // update type parameters names + for (ASTMCType supertype : collector.getAllFSuperTypeDeclarations(type)) { + Optional matching = validator.getMatchedSupertype(type, supertype); + if (matching.isPresent() && matching.get().mustBePerform()) { + String newName = buildConcreteName(matching.get()); + updater.updateSuperType(type, supertype, newName); + } + } + } + } + + protected void handleVariableUpdate(JavaAstElemCollector collector) { + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { + + // update local variables + for (ASTLocalVariableDeclaration var : collector.getAllLocVariables(type, method)) { + Optional matching = validator.getMatchedLocalVariable(type, method, var); + if (matching.isPresent() && matching.get().mustBePerform()) { + String newName = buildConcreteName(matching.get()); + updater.updateLocalVariable(type, method, var, newName); + } + } + + // update all formal parameters + for (ASTFormalParameter param : collector.getAllParameters(type, method)) { + Optional matching = validator.getMatchedParameter(type, method, param); + if (matching.isPresent() && matching.get().mustBePerform()) { + String newName = buildConcreteName(matching.get()); + updater.updateMethodParameter(type, method, param, newName); + } + } + } + } + } + + /*** + * build concrete name of an element form the matching found in the class diagram + */ + private String buildConcreteName(CodeMatching codeMatching) { + List conReferences = new ArrayList<>(); + + // resolve concrete references + for (ISymbol refSymbol : codeMatching.getReferences()) { + if (refSymbol instanceof CDTypeSymbol) { + conReferences.add(getConTypeSymbol((CDTypeSymbol) refSymbol)); + } else { + conReferences.add(getConAttributeSymbol((FieldSymbol) refSymbol)); + } + } + // fill the template with the references + return MatcherHelper.fillTemplate(codeMatching.getTemplate(), conReferences); + } + + protected ISymbol getConTypeSymbol(CDTypeSymbol symbol) { + return checker.getConElements(symbol.getAstNode()).iterator().next().getSymbol(); + } + + protected ISymbol getConAttributeSymbol(FieldSymbol symbol) { + + return checker + .getConElements((ASTCDAttribute) symbol.getAstNode()) + .iterator() + .next() + .getSymbol(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java new file mode 100644 index 00000000..f557fe9f --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/CodeMatching.java @@ -0,0 +1,57 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.symboltable.ISymbol; +import java.util.ArrayList; +import java.util.List; + +/*** + * Save matching information, each Matching is attached to an element (type,field,method,..) of + * the reference code. + * It saves the necessary implementation to build the concrete name of this element. + */ +public class CodeMatching { + /*** + * is true when the code element has to be ignored during the adaptation. + */ + private boolean ignore = false; + + /*** + * CD-references of the element + */ + private final List references = new ArrayList<>(); + + /*** + * must be field with the concrete as argument reference to build the new name + */ + private String template; + + public CodeMatching(boolean ignore) { + this.ignore = ignore; + } + + public CodeMatching() {} + + public List getReferences() { + return references; + } + + public String getTemplate() { + return template; + } + + public void addReference(ISymbol reference) { + this.references.add(reference); + } + + public void setTemplate(String template) { + this.template = template; + } + + public void setIgnore(boolean ignore) { + this.ignore = ignore; + } + + public boolean mustBePerform() { + return !ignore; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java new file mode 100644 index 00000000..87cd6119 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/MatcherHelper.java @@ -0,0 +1,206 @@ +package de.monticore.codeAdaption.matcher; + +import static de.monticore.codeAdaption.utils.Constants.*; +import static de.monticore.codeAdaption.utils.Constants.PLACE_HOLDER_REGEX; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.matcher.annotMatcher.AnnotElementCollector; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTJavaAnnotation; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.*; +import de.monticore.statements.mccommonstatements._ast.ASTJavaModifier; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/*** + * helper functions of the matcher. + */ +public class MatcherHelper { + + public static CodeMatching mkMatching(String template, List references) { + CodeMatching matching = new CodeMatching(); + + matching.setIgnore(false); + matching.setTemplate(template); + references.forEach(matching::addReference); + return matching; + } + + public static CodeMatching mkMatchingFromAnnotation( + ASTMCModifier annotation, ASTCDCompilationUnit cd) { + // init visitor and traverser + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + AnnotElementCollector collector = new AnnotElementCollector(); + traverser.add4JavaLight(collector); + annotation.accept(traverser); + + // build matching + CodeMatching matching = new CodeMatching(); + matching.setTemplate(collector.getTemplate()); + matching.setIgnore(collector.isIgnore()); + + // resolve and add reference to the matching + for (String ref : collector.getReferences()) { + Optional symbol = AdapterUtils.resolveCDSymbol(ref, cd); + assert symbol.isPresent(); + matching.addReference(symbol.get()); + } + + return matching; + } + + public static Optional mkMatchingFromInfixRef( + List references, String srcName) { + + // check references and build matching + if (!references.isEmpty()) { + List newReferences = MatcherHelper.cleanReferences(references); + String template = MatcherHelper.mkTemplateFormInfix(srcName, newReferences); + List sortedReferences = MatcherHelper.cleanReferences(srcName, newReferences); + return Optional.of(MatcherHelper.mkMatching(template, sortedReferences)); + } + return Optional.empty(); + } + + public static String mkTemplateFormInfix(String name, List infixList) { + String template = name; + + for (ISymbol infixSymbol : infixList) { + String infix = infixSymbol.getName(); + if (name.contains(infix)) { + template = template.replace(infix, SIMPLE_PLACE_HOLDER); + } + if (name.contains(capFirst(infix))) { + template = template.replace(capFirst(infix), CAP_FIRST_PLACE_HOLDER); + } + if (name.contains(uncapFirst(infix))) { + template = template.replace(uncapFirst(infix), UNCAP_FIRST_PLACE_HOLDER); + } + } + return template; + } + + public static List cleanReferences(String name, List infixList) { + List refs = + infixList.stream().map(ref -> ref.getName().toLowerCase()).collect(Collectors.toList()); + Map refMap = new HashMap<>(); + + for (int i = 0; i < refs.size(); i++) { + refMap.put(name.toLowerCase().indexOf(refs.get(i)), infixList.get(i)); + } + + List result = new ArrayList<>(); + for (int i = 0; i < name.length(); i++) { + if (refMap.containsKey(i)) { + result.add(refMap.get(i)); + } + } + return result; + } + + public static Optional getInfoJavaAnnot(List mods) { + for (ASTMCModifier mod : mods) { + if (mod instanceof ASTJavaAnnotation + && ((ASTJavaAnnotation) mod).getAnnotationName().getQName().equals(ANNOT_NAME)) { + return Optional.of((ASTJavaAnnotation) mod); + } + } + return Optional.empty(); + } + + public static Optional getInfoAnnotation(List mods) { + + for (ASTMCModifier mod : mods) { + if (mod instanceof ASTAnnotation + && ((ASTAnnotation) mod).getAnnotationName().getQName().equals(ANNOT_NAME)) { + return Optional.of((ASTAnnotation) mod); + } + } + return Optional.empty(); + } + + /*** + * fill template with the reference. + * @param template the template. + * @param refSymbol the template arguments + * @return the generated String. + */ + public static String fillTemplate(String template, List refSymbol) { + StringBuilder builder = new StringBuilder(template); + + // Create a pattern to match everything between "${" and "}" + Pattern pattern = Pattern.compile(PLACE_HOLDER_REGEX); + Matcher matcher = pattern.matcher(template); + + for (ISymbol feld : refSymbol) { + if (matcher.find()) { + String pHolder = matcher.group(1); + + String replacement; + if (pHolder.equals(CAP_FIRST)) { + replacement = capFirst(feld.getName()); + } else if (pHolder.equals(UNCAP_FIRST)) { + replacement = uncapFirst(feld.getName()); + } else { + replacement = feld.getName(); + } + builder = + new StringBuilder(builder.toString().replaceFirst(PLACE_HOLDER_REGEX, replacement)); + } + } + + return builder.toString(); + } + + public static String capFirst(String str) { + return Character.toUpperCase(str.charAt(0)) + str.substring(1); + } + + public static String uncapFirst(String str) { + return Character.toLowerCase(str.charAt(0)) + str.substring(1); + } + + public static List resolveReferencesFromType( + String varName, ASTMCType type, ASTCDCompilationUnit cd) { + + String t = JavaLoader.print(type); + + List refList = new ArrayList<>(); + for (ASTCDType astcdType : AdapterUtils.getAllCDTypes(cd)) { + if (t.contains(astcdType.getName()) && matchInfix(varName, astcdType.getName())) { + refList.add(astcdType.getSymbol()); + } + } + + return refList; + } + + public static List cleanReferences(List references) { + if (references.isEmpty() || references.size() == 1) { + return references; + } + + Set temps = new HashSet(references); + for (ISymbol symbol : temps) { + for (ISymbol symbol1 : temps) { + if (!symbol.equals(symbol1) && (matchInfix(symbol.getName(), symbol1.getName()))) { + references.remove(symbol1); + } + } + } + return references; + } + + public static boolean matchInfix(String element, String infix) { + return element.toLowerCase().contains(infix.toLowerCase()); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java new file mode 100644 index 00000000..f5553f57 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTMemberMatcher.java @@ -0,0 +1,89 @@ +package de.monticore.codeAdaption.matcher.NameMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/*** + * match Field and method in the code with attribute and method in the class diagram + * having the same name. + */ +public class NameTMemberMatcher implements TMemberMatcher { + protected TypeMatcher typeMatcher; + protected ASTCDCompilationUnit cd; + + public NameTMemberMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setTypeMatcher(TypeMatcher typeMatcher) { + this.typeMatcher = typeMatcher; + } + + @Override + public TypeMatcher getTypeMatcher() { + return typeMatcher; + } + + @Override + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + List references = resolveMethodReferencesOf(type, method.getName(), String::equals); + + if (references.size() == 1) { + return Optional.of(MatcherHelper.mkMatching("${}", references)); + } + + return Optional.empty(); + } + + /*** + * match a field in referring classes with the same name. + * example :field "id" in "EntityBuilder" refers to "id" in Entity. + */ + @Override + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration field) { + String fieldName = field.getVariableDeclarator(0).getDeclarator().getName(); + + List references = resolveFieldReferencesOf(type, fieldName, String::equals); + if (references.size() == 1) { + return Optional.of(MatcherHelper.mkMatching("${}", references)); + } + + return Optional.empty(); + } + + @Override + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { + List references = new ArrayList<>(); + String srcName = JavaLoader.print(supertype); + // collect type reference in the class diagram + for (ASTCDType astcdType : AdapterUtils.getAllCDTypes(cd)) { + if (srcName.toLowerCase().contains(astcdType.getName().toLowerCase())) { + references.add(astcdType.getSymbol()); + } + } + // check reference and build matching + return MatcherHelper.mkMatchingFromInfixRef(references, srcName); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java new file mode 100644 index 00000000..b683b6fc --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/NameMatcher/NameTypeMatcher.java @@ -0,0 +1,54 @@ +package de.monticore.codeAdaption.matcher.NameMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/*** + * match a type in the code with a type with a type with the same name + * in the reference class diagram. + */ +public class NameTypeMatcher implements TypeMatcher { + protected ASTCDCompilationUnit cd; + + protected Set typeDeclarationSet; + + @Override + public Set getAllTypeDeclarations() { + return typeDeclarationSet; + } + + @Override + public void setAllTypeDeclarations(Set typeDeclarationSet) { + this.typeDeclarationSet = typeDeclarationSet; + } + + public NameTypeMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + /*** + * match a type to a type with the same name in the class diagram. + */ + @Override + public Optional getMatchedType(ASTTypeDeclaration element) { + for (ASTCDType type : AdapterUtils.getAllCDTypes(cd)) { + if (element.getName().equals(type.getName())) { + return Optional.of(MatcherHelper.mkMatching("${}", List.of(type.getSymbol()))); + } + } + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java new file mode 100644 index 00000000..f921a331 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TMemberMatcher.java @@ -0,0 +1,90 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cdbasis._ast.ASTCDAttribute; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.*; +import java.util.function.BiFunction; + +public interface TMemberMatcher { + void setReferenceCD(ASTCDCompilationUnit cd); + + void setTypeMatcher(TypeMatcher matcher); + + TypeMatcher getTypeMatcher(); + + Optional getMatchedMethod(ASTTypeDeclaration type, ASTMethodDeclaration method); + + Optional getMatchedField(ASTTypeDeclaration type, ASTFieldDeclaration field); + + Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype); + + default List resolveFieldReferencesOf( + ASTTypeDeclaration type, String name, BiFunction match) { + + List references = new ArrayList<>(); + + Optional matching = getTypeMatcher().getMatchedType(type); + + if (matching.isEmpty()) { + return references; + } + + // resolve attribute reference in referencing types + for (ISymbol symbol : matching.get().getReferences()) { + for (ASTCDAttribute att : ((ASTCDType) symbol.getAstNode()).getCDAttributeList()) { + if (match.apply(name, att.getName())) { + references.add(att.getSymbol()); + } + } + } + return references; + } + + default List resolveMethodReferencesOf( + ASTTypeDeclaration type, String name, BiFunction match) { + + List references = new ArrayList<>(); + Optional matching = getTypeMatcher().getMatchedType(type); + + if (matching.isEmpty()) { + return references; + } + + // resolve attribute reference in referencing types + for (ISymbol symbol : matching.get().getReferences()) { + for (ASTCDMethod att : ((ASTCDType) symbol.getAstNode()).getCDMethodList()) { + if (match.apply(name, att.getName())) { + references.add(att.getSymbol()); + } + } + } + return references; + } + + default List resolveTypeReferencesOf( + ASTTypeDeclaration type, String name, BiFunction match) { + + List references = new ArrayList<>(); + Optional matching = getTypeMatcher().getMatchedType(type); + + if (matching.isEmpty()) { + return references; + } + + // resolve attribute reference in referencing types + for (ISymbol symbol : matching.get().getReferences()) { + + if (match.apply(name, symbol.getName())) { + references.add(symbol); + } + } + return references; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java new file mode 100644 index 00000000..7299d70d --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/TypeMatcher.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.java.javadsl._ast.*; +import java.util.Optional; +import java.util.Set; + +/*** + * this interface validates and cleans a reference code for a given reference model. + * it also collects the necessary update operation for an adaptation. + */ + +public interface TypeMatcher { + void setReferenceCD(ASTCDCompilationUnit cd); + + Set getAllTypeDeclarations(); + + void setAllTypeDeclarations(Set typeDeclarations); + + Optional getMatchedType(ASTTypeDeclaration type); +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java new file mode 100644 index 00000000..344ee407 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/VariableMatcher.java @@ -0,0 +1,18 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import java.util.Optional; + +public interface VariableMatcher { + void setReferenceCD(ASTCDCompilationUnit cd); + + Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar); + + Optional getMatchedFormalParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param); +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java new file mode 100644 index 00000000..26bb3111 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotElementCollector.java @@ -0,0 +1,66 @@ +package de.monticore.codeAdaption.matcher.annotMatcher; + +import de.monticore.codeAdaption.utils.Constants; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.expressions.expressionsbasis._ast.ASTLiteralExpression; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTElementValueOrExpr; +import de.monticore.javalight._ast.ASTElementValuePair; +import de.monticore.javalight._visitor.JavaLightVisitor2; +import de.monticore.literals.mccommonliterals._ast.ASTBooleanLiteral; +import de.monticore.literals.mccommonliterals._ast.ASTStringLiteral; +import de.monticore.literals.mccommonliterals._visitor.MCCommonLiteralsVisitor2; +import java.util.ArrayList; +import java.util.List; + +/*** + * this class visits an ASTAnnotation or ASTJavaAnnotation and collects information. + * (template, ignore-tag and references) + */ +public class AnnotElementCollector implements JavaLightVisitor2 { + + private String template; + private final List references = new ArrayList<>(); + private boolean ignore; + + @Override + public void visit(ASTElementValuePair node) { + + if (node.getName().equals(Constants.TEMPLATE)) { + ASTExpression val = node.getElementValueOrExpr().getExpression(); + template = ((ASTStringLiteral) ((ASTLiteralExpression) val).getLiteral()).getValue(); + } + + if (node.getName().equals(Constants.IGNORE)) { + ASTExpression val = node.getElementValueOrExpr().getExpression(); + ignore = ((ASTBooleanLiteral) ((ASTLiteralExpression) val).getLiteral()).getValue(); + } + + if (node.getName().equals(Constants.REFERENCE)) { + ASTElementValueOrExpr val = node.getElementValueOrExpr(); + MCCommonLiteralsVisitor2 visitor = + new MCCommonLiteralsVisitor2() { + @Override + public void visit(ASTStringLiteral node) { + references.add(node.getValue()); + } + }; + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4MCCommonLiterals(visitor); + val.accept(traverser); + } + } + + public List getReferences() { + return references; + } + + public String getTemplate() { + return template; + } + + public boolean isIgnore() { + return ignore; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java new file mode 100644 index 00000000..0710c2bf --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTMemberMatcher.java @@ -0,0 +1,61 @@ +package de.monticore.codeAdaption.matcher.annotMatcher; + +import static de.monticore.codeAdaption.matcher.MatcherHelper.*; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.Optional; + +/*** + * match an Attributes and method in the reference code to elements + * in the reference class Diagram form annotations. + */ +public class AnnotTMemberMatcher implements TMemberMatcher { + + protected ASTCDCompilationUnit cd; + protected TypeMatcher typeMatcher; + + public AnnotTMemberMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setTypeMatcher(TypeMatcher matcher) { + this.typeMatcher = matcher; + } + + @Override + public TypeMatcher getTypeMatcher() { + return typeMatcher; + } + + @Override + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + return getInfoAnnotation(method.getMCModifierList()) + .map(annot -> mkMatchingFromAnnotation(annot, cd)); + } + + @Override + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration field) { + return getInfoJavaAnnot(field.getJavaModifierList()) + .map(annot -> mkMatchingFromAnnotation(annot, cd)); + } + + @Override + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java new file mode 100644 index 00000000..dfdb364c --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotTypeMatcher.java @@ -0,0 +1,52 @@ +package de.monticore.codeAdaption.matcher.annotMatcher; + +import static de.monticore.codeAdaption.matcher.MatcherHelper.*; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.java.javadsl._ast.*; +import java.util.Optional; +import java.util.Set; + +/*** + * match a TypeDeclaration(class, enum, interface) in the reference code to elements in + * the reference class Diagram form annotations. + */ +public class AnnotTypeMatcher implements TypeMatcher { + protected ASTCDCompilationUnit cd; + Set typeDeclarationSet; + + public AnnotTypeMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public Set getAllTypeDeclarations() { + return typeDeclarationSet; + } + + @Override + public void setAllTypeDeclarations(Set typeDeclarationSet) { + this.typeDeclarationSet = typeDeclarationSet; + } + + @Override + public Optional getMatchedType(ASTTypeDeclaration type) { + + Optional annotation = Optional.empty(); + if (type instanceof ASTClassDeclaration) { + annotation = getInfoJavaAnnot(((ASTClassDeclaration) type).getJavaModifierList()); + } else if (type instanceof ASTInterfaceDeclaration) { + annotation = getInfoJavaAnnot(((ASTInterfaceDeclaration) type).getJavaModifierList()); + } else if (type instanceof ASTEnumDeclaration) { + annotation = getInfoJavaAnnot(((ASTEnumDeclaration) type).getJavaModifierList()); + } + return annotation.map(annot -> mkMatchingFromAnnotation(annot, cd)); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java new file mode 100644 index 00000000..02d8b019 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/annotMatcher/AnnotVariableMatcher.java @@ -0,0 +1,41 @@ +package de.monticore.codeAdaption.matcher.annotMatcher; + +import static de.monticore.codeAdaption.matcher.MatcherHelper.*; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.VariableMatcher; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import java.util.Optional; + +/*** + * match a methods parameters and local variables in the reference code to elements + * in the reference class Diagram form annotations. + */ +public class AnnotVariableMatcher implements VariableMatcher { + protected ASTCDCompilationUnit cd; + + public AnnotVariableMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) {} + + @Override + public Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar) { + return getInfoAnnotation(locVar.getMCModifierList()) + .map(annot -> mkMatchingFromAnnotation(annot, cd)); + } + + @Override + public Optional getMatchedFormalParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param) { + return getInfoJavaAnnot(param.getJavaModifierList()) + .map(annot -> mkMatchingFromAnnotation(annot, cd)); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java new file mode 100644 index 00000000..e96714d0 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTMemberMatcher.java @@ -0,0 +1,78 @@ +package de.monticore.codeAdaption.matcher.compMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.List; +import java.util.Optional; + +/*** + * compose matching Strategy for Method and attributes. + * allow trying several matching strategies until a matching is found. + */ +public class CompTMemberMatcher implements TMemberMatcher { + protected TypeMatcher typeMatcher; + protected List matchers; + + public CompTMemberMatcher(List matchers) { + this.matchers = matchers; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + matchers.forEach(matcher -> matcher.setReferenceCD(cd)); + } + + @Override + public void setTypeMatcher(TypeMatcher matcher) { + this.typeMatcher = matcher; + matchers.forEach(m -> m.setTypeMatcher(matcher)); + } + + @Override + public TypeMatcher getTypeMatcher() { + return typeMatcher; + } + + @Override + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + + for (TMemberMatcher matcher : matchers) { + Optional matching = matcher.getMatchedMethod(type, method); + if (matching.isPresent()) { + return matching; + } + } + return Optional.empty(); + } + + @Override + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration field) { + + for (TMemberMatcher matcher : matchers) { + Optional matching = matcher.getMatchedField(type, field); + if (matching.isPresent()) { + return matching; + } + } + return Optional.empty(); + } + + @Override + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { + for (TMemberMatcher matcher : matchers) { + Optional matching = matcher.getMatchedSupertype(type, supertype); + if (matching.isPresent()) { + return matching; + } + } + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java new file mode 100644 index 00000000..92b06378 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompTypeMatcher.java @@ -0,0 +1,50 @@ +package de.monticore.codeAdaption.matcher.compMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/*** + * compose matching Strategy for Types. + * allow trying several matching strategies until a matching is found. + */ +public class CompTypeMatcher implements TypeMatcher { + protected List matchers; + protected Set typeDeclarationSet; + + public CompTypeMatcher(List matchers) { + this.matchers = matchers; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + matchers.forEach(matcher -> matcher.setReferenceCD(cd)); + } + + @Override + public Set getAllTypeDeclarations() { + return typeDeclarationSet; + } + + @Override + public void setAllTypeDeclarations(Set typeDeclarationSet) { + this.typeDeclarationSet = typeDeclarationSet; + matchers.forEach(typeMatcher -> typeMatcher.setAllTypeDeclarations(typeDeclarationSet)); + } + + @Override + public Optional getMatchedType(ASTTypeDeclaration type) { + + for (TypeMatcher matcher : matchers) { + Optional matching = matcher.getMatchedType(type); + if (matching.isPresent()) { + return matching; + } + } + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java new file mode 100644 index 00000000..141846ed --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/compMatcher/CompVariableMatcher.java @@ -0,0 +1,55 @@ +package de.monticore.codeAdaption.matcher.compMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.VariableMatcher; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import java.util.List; +import java.util.Optional; + +/*** + * compose matching Strategy for functions parameters and local variables. + * allow trying several matching strategies until a matching is found. + */ +public class CompVariableMatcher implements VariableMatcher { + + protected List matchers; + + public CompVariableMatcher(List matchers) { + this.matchers = matchers; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + matchers.forEach(matcher -> matcher.setReferenceCD(cd)); + } + + @Override + public Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar) { + + for (VariableMatcher matcher : matchers) { + Optional matching = matcher.getMatchedLocalVariable(type, method, locVar); + if (matching.isPresent()) { + return matching; + } + } + return Optional.empty(); + } + + @Override + public Optional getMatchedFormalParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param) { + + for (VariableMatcher matcher : matchers) { + Optional matching = matcher.getMatchedFormalParameter(type, method, param); + if (matching.isPresent()) { + return matching; + } + } + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java new file mode 100644 index 00000000..fa4e1b7d --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTMemberMatcher.java @@ -0,0 +1,74 @@ +package de.monticore.codeAdaption.matcher.errorMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; +import java.util.Optional; + +/*** + *throws an error when the previous strategies didn't find machining for attributes or a methods. + */ +public class ErrorTMemberMatcher implements TMemberMatcher { + protected ASTCDCompilationUnit cd; + protected TypeMatcher typeMatcher; + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setTypeMatcher(TypeMatcher matcher) { + this.typeMatcher = matcher; + } + + @Override + public TypeMatcher getTypeMatcher() { + return typeMatcher; + } + + @Override + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + + String pos = AdapterUtils.getPosition(method.get_SourcePositionStart()); + Log.error(pos + " No Match found for the Method " + method.getName()); + assert false; + return Optional.empty(); + } + + @Override + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration field) { + + String name = field.getVariableDeclarator(0).getDeclarator().getName(); + String pos = AdapterUtils.getPosition(field.get_SourcePositionStart()); + Log.error(pos + " No Match found for the Field " + name); + assert false; + return Optional.empty(); + } + + @Override + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { + String name = JavaLoader.print(supertype); + + for (ASTTypeDeclaration typeDeclaration : typeMatcher.getAllTypeDeclarations()) { + if (typeDeclaration.getName().equals(name)) { + return Optional.of(new CodeMatching(true)); + } + } + + String pos = AdapterUtils.getPosition(supertype.get_SourcePositionStart()); + Log.error(pos + " No Match found for the Type " + name); + assert false; + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java new file mode 100644 index 00000000..c9e5ac09 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorTypeMatcher.java @@ -0,0 +1,41 @@ +package de.monticore.codeAdaption.matcher.errorMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.se_rwth.commons.logging.Log; +import java.util.Optional; +import java.util.Set; + +/*** + *throws an error when the previous strategy didn't find machining for types + */ +public class ErrorTypeMatcher implements TypeMatcher { + protected ASTCDCompilationUnit cd; + Set typeDeclarationSet; + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public Set getAllTypeDeclarations() { + return typeDeclarationSet; + } + + @Override + public void setAllTypeDeclarations(Set typeDeclarationSet) { + this.typeDeclarationSet = typeDeclarationSet; + } + + @Override + public Optional getMatchedType(ASTTypeDeclaration type) { + String pos = AdapterUtils.getPosition(type.get_SourcePositionStart()); + Log.error(pos + " No Match found for the type " + type.getName()); + assert false; + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java new file mode 100644 index 00000000..9c4df883 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/errorMatcher/ErrorVariableMatcher.java @@ -0,0 +1,43 @@ +package de.monticore.codeAdaption.matcher.errorMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.VariableMatcher; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.se_rwth.commons.logging.Log; +import java.util.Optional; + +/*** + *throws an error when the previous strategy didn't find machining for local-variables + * and method parameters. + */ +public class ErrorVariableMatcher implements VariableMatcher { + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) {} + + @Override + public Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar) { + + String name = locVar.getVariableDeclarator(0).getDeclarator().getName(); + String pos = AdapterUtils.getPosition(locVar.get_SourcePositionStart()); + Log.error(pos + " No Match found for the Local Variable " + name); + assert false; + return Optional.empty(); + } + + @Override + public Optional getMatchedFormalParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param) { + + String name = param.getDeclarator().getName(); + String pos = AdapterUtils.getPosition(param.get_SourcePositionStart()); + Log.error(pos + " No Match found for the formal parameter " + name); + assert false; + return Optional.empty(); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java new file mode 100644 index 00000000..246049bf --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTMemberMatcher.java @@ -0,0 +1,53 @@ +package de.monticore.codeAdaption.matcher.ignoreMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.Optional; + +/*** + *return an empty-matching with the ignore flag set as true. + *when the previous strategy didn't find machining for attributes or methods. + *the adaption will ignore the corresponding element. + */ +public class IgnoreTMemberMatcher implements TMemberMatcher { + protected ASTCDCompilationUnit cd; + protected TypeMatcher typeMatcher; + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setTypeMatcher(TypeMatcher matcher) { + this.typeMatcher = matcher; + } + + @Override + public TypeMatcher getTypeMatcher() { + return typeMatcher; + } + + @Override + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + return Optional.of(new CodeMatching(true)); + } + + @Override + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration field) { + return Optional.of(new CodeMatching(true)); + } + + @Override + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { + return Optional.of(new CodeMatching(true)); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java new file mode 100644 index 00000000..35edf46a --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreTypeMatcher.java @@ -0,0 +1,38 @@ +package de.monticore.codeAdaption.matcher.ignoreMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import java.util.Optional; +import java.util.Set; + +/*** + *Return an empty-matching with the ignore flag set as true. + *When the previous strategy didn't find machining for a type. + *The adaption will ignore the corresponding element. + */ +public class IgnoreTypeMatcher implements TypeMatcher { + protected ASTCDCompilationUnit cd; + Set typeDeclarationSet; + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public Set getAllTypeDeclarations() { + return typeDeclarationSet; + } + + @Override + public void setAllTypeDeclarations(Set typeDeclarationSet) { + this.typeDeclarationSet = typeDeclarationSet; + } + + @Override + public Optional getMatchedType(ASTTypeDeclaration type) { + return Optional.of(new CodeMatching(true)); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java new file mode 100644 index 00000000..4eb9fec4 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/ignoreMatcher/IgnoreVariableMatcher.java @@ -0,0 +1,32 @@ +package de.monticore.codeAdaption.matcher.ignoreMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.VariableMatcher; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import java.util.Optional; + +/*** + *Return an empty-matching with the ignore flag set as true. + *When the previous strategy didn't find machining for a local-variable or a method-parameter. + *The adaption will ignore the corresponding element. + */ +public class IgnoreVariableMatcher implements VariableMatcher { + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) {} + + @Override + public Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar) { + return Optional.of(new CodeMatching(true)); + } + + @Override + public Optional getMatchedFormalParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param) { + return Optional.of(new CodeMatching(true)); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java new file mode 100644 index 00000000..18746537 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTMemberMatcher.java @@ -0,0 +1,97 @@ +package de.monticore.codeAdaption.matcher.infixMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.symboltable.ISymbol; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.List; +import java.util.Optional; + +/*** + * match an Attributes and method in the reference code to elements + * in the reference class Diagram by analyzing the infix. + */ +public class InfixTMemberMatcher implements TMemberMatcher { + protected ASTCDCompilationUnit cd; + protected TypeMatcher typeMatcher; + + public InfixTMemberMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setTypeMatcher(TypeMatcher matcher) { + this.typeMatcher = matcher; + } + + @Override + public TypeMatcher getTypeMatcher() { + return typeMatcher; + } + + /*** + * match method to a type or an attribute in the reference class diagram. + * eg: getId to id ; + * getEntity to Entity + */ + @Override + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + + // resolve references + List references = resolveFieldReferencesOf(type, method.getName(), this::match); + references.addAll(resolveTypeReferencesOf(type, method.getName(), this::match)); + + return MatcherHelper.mkMatchingFromInfixRef(references, method.getName()); + } + + /*** + * match field to a type or an attribute in the reference class diagram. + * eg: entityList to Entity + * longId to id + */ + @Override + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration field) { + String name = field.getVariableDeclarator(0).getDeclarator().getName(); + + // resolve references + List references = resolveFieldReferencesOf(type, name, this::match); + references.addAll(MatcherHelper.resolveReferencesFromType(name, field.getMCType(), cd)); + + // check references and build matching + return MatcherHelper.mkMatchingFromInfixRef(references, name); + } + + /*** + * match field to a type or an attribute in the reference class diagram. + * eg: entityList to Entity + * longId to id + */ + @Override + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType superType) { + String name = JavaLoader.print(superType); + + // resolve references + List references = resolveTypeReferencesOf(type, name, this::match); + + // check references and build matching + return MatcherHelper.mkMatchingFromInfixRef(references, name); + } + + public boolean match(String element, String infix) { + return element.toLowerCase().contains(infix.toLowerCase()); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java new file mode 100644 index 00000000..582d9976 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixTypeMatcher.java @@ -0,0 +1,64 @@ +package de.monticore.codeAdaption.matcher.infixMatcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.symboltable.ISymbol; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/*** + * match a type in the reference code to elements + * in the reference class Diagram by analyzing the infix. + */ +public class InfixTypeMatcher implements TypeMatcher { + protected ASTCDCompilationUnit cd; + + protected Set typeDeclarationSet; + + @Override + public Set getAllTypeDeclarations() { + return typeDeclarationSet; + } + + @Override + public void setAllTypeDeclarations(Set typeDeclarationSet) { + this.typeDeclarationSet = typeDeclarationSet; + } + + public InfixTypeMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + /*** + * match a type to a type in the class diagram with the same suffix. + */ + @Override + public Optional getMatchedType(ASTTypeDeclaration type) { + List references = new ArrayList<>(); + + // collect type reference in the class diagram + for (ASTCDType astcdType : AdapterUtils.getAllCDTypes(cd)) { + if (type.getName().toLowerCase().contains(astcdType.getName().toLowerCase())) { + references.add(astcdType.getSymbol()); + } + } + // check reference and build matching + return MatcherHelper.mkMatchingFromInfixRef(references, type.getName()); + } + + public boolean match(String element, String infix) { + return element.toLowerCase().contains(infix.toLowerCase()); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java new file mode 100644 index 00000000..57c78a26 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/matcher/infixMatcher/InfixVariableMatcher.java @@ -0,0 +1,57 @@ +package de.monticore.codeAdaption.matcher.infixMatcher; + +import static de.monticore.codeAdaption.matcher.MatcherHelper.mkMatchingFromInfixRef; +import static de.monticore.codeAdaption.matcher.MatcherHelper.resolveReferencesFromType; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.matcher.VariableMatcher; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.symboltable.ISymbol; +import java.util.List; +import java.util.Optional; + +/*** + * match a local-variable or a formal-parameter in the reference code to elements + * in the reference class Diagram by analyzing the infix. + */ +public class InfixVariableMatcher implements VariableMatcher { + protected ASTCDCompilationUnit cd; + + public InfixVariableMatcher(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public void setReferenceCD(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + @Override + public Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration locVar) { + String varName = locVar.getVariableDeclarator(0).getDeclarator().getName(); + + List references = resolveReferencesFromType(varName, locVar.getMCType(), cd); + + return MatcherHelper.mkMatchingFromInfixRef(references, varName); + } + + @Override + public Optional getMatchedFormalParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter param) { + String varName = param.getDeclarator().getName(); + + List references = resolveReferencesFromType(varName, param.getMCType(), cd); + + return mkMatchingFromInfixRef(references, varName); + } + + public boolean match(String element, String infix) { + return element.toLowerCase().contains(infix.toLowerCase()); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java new file mode 100644 index 00000000..51c3854b --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/CodeUpdater.java @@ -0,0 +1,97 @@ +package de.monticore.codeAdaption.updater; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +/*** + * this class execute the update operation in the reference code. + */ +public interface CodeUpdater { + /*** + * set the path to the referenceCode. + * @param path the path. + */ + void setCodePath(Path path); + + /*** + * print the current state of the reference code as set of files. + * @return the code as files + */ + Set printCode(); + + /*** + * change the name of a type in the reference code. By the declaration + * an all its reference an uses. + * @param srcType the source type to replace. + * @param newName the new name of the type. + */ + void updateType(ASTTypeDeclaration srcType, String newName); + + /*** + * change the name of a method in the reference code. By the declaration + * an all its reference an uses. + * @param srcType the source-type that contains the method-declaration. + * @param srcMethod the source method. + * @param newName the new name of the type. + */ + void updateMethod(ASTTypeDeclaration srcType, ASTMethodDeclaration srcMethod, String newName); + + /*** + * change the name of a field in the reference code. By its declaration + * an all its references an uses. + * @param srcType the source-type that contains the field-declaration + * @param srcField the source Field. + * @param newName the new name of the field. + */ + void updateField(ASTTypeDeclaration srcType, ASTFieldDeclaration srcField, String newName); + + /*** + * change the name of a local-variable in the reference code. By its declaration + * an all its references an uses. + * @param srcType the source-type that contains the local variable. + * @param srcMethod the source method tha contains le local variable. + * @param sourceVar the source local variable. + * @param newName the new name of the local variable. + */ + void updateLocalVariable( + ASTTypeDeclaration srcType, + ASTMethodDeclaration srcMethod, + ASTLocalVariableDeclaration sourceVar, + String newName); + + /*** + * change the name of a local-variable in the reference code. By it declaration + * and all its references an uses + * @param srcType the source type that contains the local parameter + * @param srcMethod the source method that contains le the parameter + * @param srcParam the source parameter + * @param newName the new name of the parameter + */ + void updateMethodParameter( + ASTTypeDeclaration srcType, + ASTMethodDeclaration srcMethod, + ASTFormalParameter srcParam, + String newName); + + /*** + * Update all types that are not present in the reference code. + * @param cdType type in the reference class diagram to update in the reference code. + * @param newName new name of the type. + */ + void updateCDType(ASTCDType cdType, String newName); + /*** + * set the output directory of the code by printing. + * @param outputPath the output directory + */ + void setOutputDirectory(Path outputPath); + + void updateSuperType(ASTTypeDeclaration type, ASTMCType supertype, String newName); +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java new file mode 100644 index 00000000..72bf6815 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/regexUpdater/RegexUpdater.java @@ -0,0 +1,91 @@ +package de.monticore.codeAdaption.updater.regexUpdater; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +public class RegexUpdater implements CodeUpdater { + protected Set code; + + protected Path outputDir; + + @Override + public void setCodePath(Path path) { + code = JavaLoader.readJavaFile(path); + } + + @Override + public Set printCode() { + return code; + } + + @Override + public void updateType(ASTTypeDeclaration srcType, String newName) { + updateElement(srcType.getName(), newName); + } + + @Override + public void updateMethod( + ASTTypeDeclaration srcType, ASTMethodDeclaration srcMethod, String newName) { + updateElement(srcMethod.getName(), newName); + } + + @Override + public void updateField( + ASTTypeDeclaration srcType, ASTFieldDeclaration srcField, String newName) { + String srcName = srcField.getVariableDeclarator(0).getDeclarator().getName(); + updateElement(srcName, newName); + } + + @Override + public void updateLocalVariable( + ASTTypeDeclaration srcType, + ASTMethodDeclaration srcMethod, + ASTLocalVariableDeclaration sourceVar, + String newName) { + String srcName = sourceVar.getVariableDeclarator(0).getDeclarator().getName(); + updateElement(srcName, newName); + } + + @Override + public void updateMethodParameter( + ASTTypeDeclaration srcType, + ASTMethodDeclaration srcMethod, + ASTFormalParameter srcParam, + String newName) { + String srcName = srcParam.getDeclarator().getName(); + updateElement(srcName, newName); + } + + @Override + public void updateCDType(ASTCDType cdType, String newName) { + updateElement(cdType.getName(), newName); + } + + @Override + public void setOutputDirectory(Path outputPath) { + this.outputDir = outputPath; + } + + @Override + public void updateSuperType(ASTTypeDeclaration type, ASTMCType supertype, String newName) { + updateElement(supertype.printType(), newName); + } + + public void updateElement(String src, String target) { + for (File file : code) { + String fileText = JavaLoader.readFileContent(file); + String updateText = fileText.replaceAll(src, target); + JavaLoader.writeFile(Path.of(file.getAbsolutePath()), updateText); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java new file mode 100644 index 00000000..884956c5 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/updater/spoonUpdater/SpoonUpdater.java @@ -0,0 +1,246 @@ +package de.monticore.codeAdaption.updater.spoonUpdater; + +import static de.monticore.codeAdaption.utils.JavaLoader.print; + +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.updater.CodeUpdater; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.io.File; +import java.nio.file.Path; +import java.util.*; +import spoon.Launcher; +import spoon.refactoring.CtRenameGenericVariableRefactoring; +import spoon.refactoring.Refactoring; +import spoon.reflect.CtModel; +import spoon.reflect.code.CtLocalVariable; +import spoon.reflect.declaration.*; +import spoon.reflect.reference.CtTypeReference; + +public class SpoonUpdater implements CodeUpdater { + private File outputDir; + private Launcher launcher; + private CtModel spoonModel; + private final Map> typeMap = new HashMap<>(); + private final Map> methodMap = new HashMap<>(); + + @Override + public void setCodePath(Path path) { + // init spoon environment + launcher = new Launcher(); + launcher.getEnvironment().setAutoImports(true); + launcher.getEnvironment().setShouldCompile(true); + + // add code to the environment + launcher.addInputResource(path.toAbsolutePath().toString()); + + // build model + launcher.buildModel(); + spoonModel = launcher.getModel(); + } + + @Override + public Set printCode() { + launcher.setSourceOutputDirectory(outputDir); + launcher.prettyprint(); + return JavaLoader.readJavaFile(outputDir.toPath()); + } + + @Override + public void updateType(ASTTypeDeclaration source, String newName) { + CtType type = getSpoonType(source); + Refactoring.changeTypeName(type, newName); + } + + @Override + public void updateMethod( + ASTTypeDeclaration srcType, ASTMethodDeclaration srcMethod, String newName) { + CtMethod method = getSpoonMethod(srcType, srcMethod); + Refactoring.changeMethodName(method, newName); + } + + @Override + public void updateField( + ASTTypeDeclaration srcType, ASTFieldDeclaration srcField, String newName) { + + // get Spoon Variable + String srcName = srcField.getVariableDeclarator(0).getDeclarator().getName(); + CtVariable attribute = getSpoonType(srcType).getField(srcName); + + // perform update + CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); + refactor.setTarget(attribute).setNewName(newName).refactor(); + } + + @Override + public void updateSuperType(ASTTypeDeclaration type, ASTMCType supertype, String newName) { + String srcName = JavaLoader.print(supertype); + CtType spoonType = getSpoonType(type); + + // case super class + CtTypeReference superType = spoonType.getSuperclass(); + if (superType != null && superType.getSimpleName().equals(srcName)) { + spoonType.getSuperclass().setSimpleName(newName); + return; + } + + // case super interface + for (CtTypeReference superType2 : spoonType.getSuperInterfaces()) { + if (superType2.getSimpleName().equals(srcName)) { + superType2.setSimpleName(newName); + } + } + } + + @Override + public void updateLocalVariable( + ASTTypeDeclaration srcType, + ASTMethodDeclaration srcMethod, + ASTLocalVariableDeclaration sourceVar, + String newName) { + + // get spoon local-variable + CtMethod spoonMethod = getSpoonMethod(srcType, srcMethod); + List> localVars = spoonMethod.getElements(Objects::nonNull); + String varName = sourceVar.getVariableDeclarator(0).getDeclarator().getName(); + Optional> var = + localVars.stream().filter(v -> v.getSimpleName().equals(varName)).findAny(); + assert var.isPresent(); + + // perform update + CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); + refactor.setTarget(var.get()).setNewName(newName).refactor(); + } + + @Override + public void updateMethodParameter( + ASTTypeDeclaration srcType, + ASTMethodDeclaration srcMethod, + ASTFormalParameter srcParam, + String newName) { + + // get spoon formal parameter of method + CtMethod spoonMethod = getSpoonMethod(srcType, srcMethod); + List> params = spoonMethod.getElements(Objects::nonNull); + String srcVarName = srcParam.getDeclarator().getName(); + Optional> param = + params.stream().filter(v -> v.getSimpleName().equals(srcVarName)).findAny(); + + if (param.isPresent()) { + // perform update + CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); + refactor.setTarget(param.get()).setNewName(newName).refactor(); + + } else { + + // case formal param in for loop + List> localVars = spoonMethod.getElements(Objects::nonNull); + Optional> localvar = + localVars.stream().filter(v -> v.getSimpleName().equals(srcVarName)).findAny(); + assert localvar.isPresent(); + + // case formal param in for loop + CtRenameGenericVariableRefactoring refactor = new CtRenameGenericVariableRefactoring(); + refactor.setTarget(localvar.get()).setNewName(newName).refactor(); + } + } + + @Override + public void updateCDType(ASTCDType cdType, String newName) { + List> refTypes = spoonModel.getElements(Objects::nonNull); + + for (CtTypeReference typeRef : refTypes) { + if (typeRef.getSimpleName().equals(cdType.getName())) { + typeRef.setSimpleName(newName); + } + } + + // for () + } + + @Override + public void setOutputDirectory(Path outputPath) { + this.outputDir = outputPath.toFile(); + } + + /*** + *get spoonType form the Spoon Model and the mcType. + * save the found spoonType in the type map. + */ + private CtType getSpoonType(ASTTypeDeclaration mcType) { + // cas already found + if (typeMap.containsKey(mcType)) { + return typeMap.get(mcType); + } + // search in the spoon model + Optional> type = + spoonModel.getAllTypes().stream().filter(t -> compare(mcType, t)).findFirst(); + assert type.isPresent(); + typeMap.put(mcType, type.get()); + return type.get(); + } + + /*** + *get spoonMethod form the Spoon Model and the mcType an the mcMethod. + * save the found spoonMethod in the type map. + */ + public CtMethod getSpoonMethod(ASTTypeDeclaration mcType, ASTMethodDeclaration mcMethod) { + // cas method was already found + if (methodMap.containsKey(mcMethod)) { + return methodMap.get(mcMethod); + } + + // search method in the spoonType + CtType spoonType = getSpoonType(mcType); + Optional> method = + spoonType.getAllMethods().stream() + .filter(spMethod -> compare(mcMethod, spMethod)) + .findFirst(); + + assert method.isPresent(); + methodMap.put(mcMethod, method.get()); + return method.get(); + } + + /*** + * compare a mcType an spoonType and return true if both are identical. + */ + protected boolean compare(ASTTypeDeclaration type, CtType spoonType) { + String fileName = type.get_SourcePositionStart().getFileName().orElse(type.getName()); + return fileName.replaceAll("\\\\", ".").endsWith(spoonType.getSimpleName() + ".java"); + } + + /*** + *compare spoonMethod and mcMethod and return true if both are identical. + */ + protected boolean compare(ASTMethodDeclaration mcMethod, CtMethod spoonMethod) { + // compare names + if (!mcMethod.getName().endsWith(spoonMethod.getSimpleName())) { + return false; + } + // is present parameters ? + if (!mcMethod.getFormalParameters().isPresentFormalParameterListing()) { + return spoonMethod.getParameters().isEmpty(); + } + // same number of parameters ? + List mcParams = + mcMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); + if (spoonMethod.getParameters().size() != mcParams.size()) { + return false; + } + // parameters have the same type ? + for (int i = 0; i < spoonMethod.getParameters().size(); i++) { + if (!(spoonMethod.getParameters().get(i).getType().getSimpleName()) + .equals(print(mcParams.get(i).getMCType()))) { + return false; + } + } + + return true; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java new file mode 100644 index 00000000..c3709db4 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Adapt.java @@ -0,0 +1,19 @@ +package de.monticore.codeAdaption.utils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target({ + ElementType.LOCAL_VARIABLE, + ElementType.TYPE, + ElementType.FIELD, + ElementType.METHOD, + ElementType.PARAMETER, +}) +public @interface Adapt { + boolean ignore() default false; + + String[] ref() default {}; + + String template() default ""; +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java new file mode 100644 index 00000000..5373ce1d --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterParam.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.utils; + +public enum AdapterParam { + NAME_MATCHING, + INFIX_MATCHING, + ANNOTATION_MATCHING, + + IGNORE_NON_MATCHED_TYPE, + + IGNORE_NON_MATCHED_VAR, + + IGNORE_NON_MATCHED_TYPE_MEMBER +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java new file mode 100644 index 00000000..153bdd3c --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/AdapterUtils.java @@ -0,0 +1,180 @@ +package de.monticore.codeAdaption.utils; + +import static de.monticore.codeAdaption.utils.JavaLoader.print; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdbasis._ast.ASTCDType; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.*; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; +import de.monticore.symboltable.ISymbol; +import de.se_rwth.commons.SourcePosition; +import java.io.File; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AdapterUtils { + + public static Set getAllCDTypes(ASTCDCompilationUnit cd) { + Set res = new HashSet<>(); + res.addAll(cd.getCDDefinition().getCDClassesList()); + res.addAll(cd.getCDDefinition().getCDInterfacesList()); + res.addAll(cd.getCDDefinition().getCDEnumsList()); + return res; + } + + public static Optional resolveCDSymbol(String name, ASTCDCompilationUnit refCD) { + List symbol = refCD.getEnclosingScope().resolveFieldMany(name); + if (!symbol.isEmpty()) { + return Optional.of(symbol.iterator().next()); + } + return refCD.getEnclosingScope().resolveCDType(name).map(s -> (ISymbol) s).stream().findAny(); + } + + public static String getFileName(ASTOrdinaryCompilationUnit ast) { + return ast.get_SourcePositionStart().getFileName().orElse(""); + } + + public static String getPosition(SourcePosition pos) { + if (pos.getFileName().isPresent()) { + String fileName = new File(pos.getFileName().get()).getName(); + return fileName + " <" + pos.getLine() + "," + pos.getColumn() + ">"; + } + return ""; + } + + /*** + * read a java file an remove multilines an single lines comments. + */ + public static void removeComments(File file) { + + // remove single line comments + String code = JavaLoader.readFileContent(file).replaceAll("//.*", ""); + + // remove multilines comments + Pattern pattern = Pattern.compile("/\\*(?s).*?\\*/"); + Matcher matcher = pattern.matcher(code); + code = matcher.replaceAll(""); + + // print code + JavaLoader.writeFile(file.toPath(), code); + } + + public static ASTOrdinaryCompilationUnit mergeAsts( + ASTOrdinaryCompilationUnit leftAST, ASTOrdinaryCompilationUnit rightAST) { + + JavaAstElemCollector lCollector = new JavaAstElemCollector(); + JavaDSLTraverser leftTraverser = JavaDSLMill.traverser(); + leftTraverser.add4JavaDSL(lCollector); + leftAST.accept(leftTraverser); + + JavaAstElemCollector rCollector = new JavaAstElemCollector(); + JavaDSLTraverser rightTraverser = JavaDSLMill.traverser(); + rightTraverser.add4JavaDSL(rCollector); + rightAST.accept(rightTraverser); + + for (ASTTypeDeclaration right : rCollector.getAllTypeDeclarations()) { + Optional lType = + lCollector.getAllTypeDeclarations().stream() + .filter(t -> t.getName().equals(right.getName())) + .findAny(); + if (lType.isEmpty()) { + leftAST.addTypeDeclaration(right); + } else { + leftAST.removeTypeDeclaration(lType.get()); + leftAST.addTypeDeclaration( + mergeTypeDeclaration(lCollector, lType.get(), rCollector, right)); + } + } + + return leftAST; + } + + private static ASTTypeDeclaration mergeTypeDeclaration( + JavaAstElemCollector lCollector, + ASTTypeDeclaration lefType, + JavaAstElemCollector rCollector, + ASTTypeDeclaration rightType) { + + // merge methods + for (ASTMethodDeclaration rMeth : rCollector.getAllMethodDeclarations(rightType)) { + Optional lMeth = + lCollector.getAllMethodDeclarations(lefType).stream() + .filter(m -> compare(m, rMeth)) + .findAny(); + + if (lMeth.isEmpty()) { + if (lefType instanceof ASTClassDeclaration) { + ((ASTClassDeclaration) lefType).getClassBody().addClassBodyDeclaration(rMeth); + } else if (rightType instanceof ASTInterfaceDeclaration) { + ((ASTInterfaceDeclaration) lefType).getInterfaceBody().addInterfaceBodyDeclaration(rMeth); + } + } + } + + // merge fields + for (ASTFieldDeclaration rField : rCollector.getAllFieldDeclarations(rightType)) { + + Optional lField = + lCollector.getAllFieldDeclarations(lefType).stream() + .filter( + f -> + f.getVariableDeclarator(0) + .getDeclarator() + .getName() + .equals(rField.getVariableDeclarator(0).getDeclarator().getName())) + .findAny(); + + if (lField.isEmpty()) { + if (lefType instanceof ASTClassDeclaration) { + ((ASTClassDeclaration) lefType).getClassBody().addClassBodyDeclaration(rField); + } + } + } + + return lefType; + } + + /*** + * Compare two method (names and types) and return true when the method are the same. + * @param leftMethod the left method. + * @param rightMethod the right method. + * @return true if both method are the same. + */ + protected static boolean compare( + ASTMethodDeclaration leftMethod, ASTMethodDeclaration rightMethod) { + // compare names + if (!leftMethod.getName().equals(rightMethod.getName())) { + return false; + } + + // is present parameters ? + if (!leftMethod.getFormalParameters().isPresentFormalParameterListing()) { + return !rightMethod.getFormalParameters().isPresentFormalParameterListing(); + } + + List leftParams = + leftMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); + List rightParams = + rightMethod.getFormalParameters().getFormalParameterListing().getFormalParameterList(); + + // same number of parameters ? + if (leftParams.size() != rightParams.size()) { + return false; + } + + // parameters have the same type ? + for (int i = 0; i < leftParams.size(); i++) { + if (!print(leftParams.get(i).getMCType()).equals(print(rightParams.get(i).getMCType()))) { + return false; + } + } + + return true; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java new file mode 100644 index 00000000..73576355 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Constants.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption.utils; + +public class Constants { + public static final String TEMPLATE = "template"; + public static final String REFERENCE = "ref"; + public static final String ANNOT_NAME = "Adapt"; + public static final String ANNOT_PACKAGE = "de.monticore.codeAdaption.utils.Adapt"; + public static final String IGNORE = "ignore"; + public static final String CAP_FIRST = "cap_first"; + public static final String UNCAP_FIRST = "uncap_first"; + + public static final String PLACE_HOLDER_REGEX = "\\$\\{(.*?)}"; + public static final String SIMPLE_PLACE_HOLDER = "${}"; + public static final String CAP_FIRST_PLACE_HOLDER = "${" + CAP_FIRST + "}"; + public static final String UNCAP_FIRST_PLACE_HOLDER = "${" + UNCAP_FIRST + "}"; +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Generator.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Generator.java new file mode 100644 index 00000000..c9a2715c --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/Generator.java @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.CD4CodeTool; +import java.io.File; +import java.nio.file.Path; + +public class Generator { + + public static void generate(File cdFile, Path hwcPath, Path output) { + String[] input = { + "-i", + cdFile.getAbsolutePath(), + "-ct", + "cd2java.CD2Java", + "--gen", + "-hwc", + hwcPath.toString(), + "-o", + output.toString(), + "--fieldfromrole", + "navigable" + }; + CD4CodeTool.main(input); + + // delete hook-points + JavaLoader.readJavaFile(Path.of("target")).forEach(AdapterUtils::removeComments); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java new file mode 100644 index 00000000..d12a3265 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/JavaLoader.java @@ -0,0 +1,216 @@ +package de.monticore.codeAdaption.utils; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import de.monticore.ast.ASTNode; +import de.monticore.cd._symboltable.BuiltInTypes; +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cd4code._cocos.CD4CodeCoCoChecker; +import de.monticore.cd4code._parser.CD4CodeParser; +import de.monticore.cd4code._symboltable.CD4CodeSymbolTableCompleter; +import de.monticore.cd4code._symboltable.ICD4CodeArtifactScope; +import de.monticore.cd4code.cocos.CD4CodeCoCosDelegator; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl.JavaDSLTool; +import de.monticore.java.javadsl._ast.ASTCompilationUnit; +import de.monticore.java.javadsl._ast.ASTMCBasicGenericType; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._prettyprint.JavaDSLFullPrettyPrinter; +import de.monticore.java.javadsl._symboltable.IJavaDSLArtifactScope; +import de.monticore.java.javadsl._symboltable.IJavaDSLGlobalScope; +import de.monticore.java.javadsl._symboltable.JavaDSLScopesGenitor; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.prettyprint.IndentPrinter; +import de.monticore.symboltable.ImportStatement; +import de.monticore.types.mcbasictypes.MCBasicTypesMill; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Assertions; + +public class JavaLoader { + + /*** + *parse a class diagram, build the symbol table and check the cocos. + */ + public static ASTCDCompilationUnit loadCD(File file) { + // parse the class diagram + assert file.getName().endsWith(".cd"); + CD4CodeParser cdParser = new CD4CodeParser(); + Optional optCdAST = Optional.empty(); + try { + optCdAST = cdParser.parse(file.getAbsolutePath()); + } catch (IOException e) { + System.out.println(e); + // Log.error("It was not possible to parse the class diagram " + file.getAbsolutePath()); + } + Assertions.assertTrue(optCdAST.isPresent()); + + // create symbol table + createCDSymTab(optCdAST.get()); + + // checkCoCos + CD4CodeCoCoChecker cdChecker = new CD4CodeCoCosDelegator().getCheckerForAllCoCos(); + // cdChecker.checkAll(optCdAST.get()); + return optCdAST.get(); + } + + public static ASTCDCompilationUnit parseCD(String cdFile) { + try { + Optional cd = CD4CodeMill.parser().parseCDCompilationUnit(cdFile); + + if (cd.isPresent()) { + ICD4CodeArtifactScope as = CD4CodeMill.scopesGenitorDelegator().createFromAST(cd.get()); + as.addImports(new ImportStatement("java.lang.String", true)); + as.addImports(new ImportStatement("java.util", true)); + cd.get().accept(new CD4CodeSymbolTableCompleter(cd.get()).getTraverser()); + + return cd.get(); + + } else { + fail("Could not parse CDs."); + } + + } catch (IOException e) { + fail(e.getMessage()); + } + return null; + } + + private static void createCDSymTab(ASTCDCompilationUnit ast) { + BuiltInTypes.addBuiltInTypes(CD4CodeMill.globalScope()); + ICD4CodeArtifactScope as = CD4CodeMill.scopesGenitorDelegator().createFromAST(ast); + as.addImports(new ImportStatement("java.lang", true)); + as.addImports(new ImportStatement("java.util", true)); + CD4CodeSymbolTableCompleter c = + new CD4CodeSymbolTableCompleter( + ast.getMCImportStatementList(), MCBasicTypesMill.mCQualifiedNameBuilder().build()); + ast.accept(c.getTraverser()); + ast.setEnclosingScope(as); + } + + /*** + * loa a java files,transform it to an AST and creation symbol-tables. + */ + public static ASTOrdinaryCompilationUnit loadJava(File javaFile) { + assertTrue(javaFile.getName().endsWith(".java")); + + // parse + JavaDSLTool tool = new JavaDSLTool(); + Optional ast; + ast = Optional.ofNullable(tool.parse(javaFile.getAbsolutePath())); + + assertTrue(ast.isPresent()); + assertTrue(ast.get() instanceof ASTOrdinaryCompilationUnit); + + // create symbol table + IJavaDSLGlobalScope globalScope = JavaDSLMill.globalScope(); + JavaDSLScopesGenitor genitor = JavaDSLMill.scopesGenitor(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.setJavaDSLHandler(genitor); + traverser.add4JavaDSL(genitor); + genitor.putOnStack(globalScope); + + IJavaDSLArtifactScope artifactScope = genitor.createFromAST(ast.get()); + globalScope.addSubScope(artifactScope); + + return (ASTOrdinaryCompilationUnit) ast.get(); + } + + /** print a javaASTNode */ + public static String print(ASTNode node) { + JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); + return prettyPrinter.prettyprint(node); + } + + public static String print(ASTMCType type) { + if (type instanceof ASTMCBasicGenericType) { + return ((ASTMCBasicGenericType) type).getAnnotatedName(0).getName(); + } + return print((ASTNode) type); + } + + public static void writeFile(Path path, String content) { + try { + FileUtils.writeStringToFile(path.toFile(), content, Charset.defaultCharset(), false); + } catch (IOException e) { + Log.error("Exception occur when writing the file " + path); + } + } + + /*** + * read recursive all java files in a directory and its subdirectories. + * @param directoryPath the root directory to read. + * @return the set of Java files as AST + */ + public static Set readJavaCode(Path directoryPath) { + Set res = new HashSet<>(); + readJavaCode(directoryPath, res); + return res.stream().map(JavaLoader::loadJava).collect(Collectors.toSet()); + } + + /*** + * read recursive all java files in a directory and its subdirectories. + * @param directoryPath the root directory to read. + * @return the set of Java files as files + */ + public static Set readJavaFile(Path directoryPath) { + Set res = new HashSet<>(); + readJavaCode(directoryPath, res); + return res; + } + + private static void readJavaCode(Path directoryPath, Set res) { + File directory = directoryPath.toFile(); + File[] files = directory.listFiles(); + + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + readJavaCode(file.toPath(), res); + } else if (file.isFile() && file.getName().endsWith(".java")) { + res.add(file); + } + } + } + } + + public static String readFileContent(File file) { + byte[] bytes = new byte[0]; + try { + bytes = Files.readAllBytes(Path.of(file.getAbsolutePath())); + } catch (IOException e) { + Log.error("It was not possible to read the file " + file.getAbsolutePath()); + } + return new String(bytes); + } + + public static void printAST(Set asts, Path codePath) { + for (ASTOrdinaryCompilationUnit ast : asts) { + File sourceFile = + new File(ast.get_SourcePositionStart().getFileName().orElse(codePath.toString())); + JavaDSLFullPrettyPrinter prettyPrinter = new JavaDSLFullPrettyPrinter(new IndentPrinter()); + String output = prettyPrinter.prettyprint(ast); + JavaLoader.writeFile(sourceFile.toPath(), output); + } + } + + public static void removeDirectory(Path path) { + try { + // Delete the directory and its contents + FileUtils.deleteDirectory(new File(path.toString())); + ; + } catch (IOException e) { + Log.error("Failed to delete directory: " + e.getMessage()); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java new file mode 100644 index 00000000..889b7e2c --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/AnnotationRemover.java @@ -0,0 +1,79 @@ +package de.monticore.codeAdaption.utils.visitors; + +import static de.monticore.codeAdaption.utils.Constants.ANNOT_PACKAGE; + +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.java.javadsl._ast.*; +import de.monticore.java.javadsl._visitor.JavaDSLVisitor2; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.javalight._visitor.JavaLightVisitor2; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mccommonstatements._ast.ASTJavaModifier; +import de.monticore.statements.mccommonstatements._visitor.MCCommonStatementsVisitor2; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.statements.mcvardeclarationstatements._visitor.MCVarDeclarationStatementsVisitor2; +import java.util.List; +import java.util.Optional; + +/*** + * this Visitor remove info-Annotation form the reference code. + */ +public class AnnotationRemover + implements JavaDSLVisitor2, + JavaLightVisitor2, + MCCommonStatementsVisitor2, + MCVarDeclarationStatementsVisitor2 { + + @Override + public void visit(ASTOrdinaryCompilationUnit node) { + Optional importDec = + node.getImportDeclarationList().stream() + .filter(i -> i.getMCQualifiedName().getQName().equals(ANNOT_PACKAGE)) + .findFirst(); + importDec.map(node.getImportDeclarationList()::remove); + } + + @Override + public void visit(ASTClassDeclaration node) { + this.removeJavaInfoAnnot(node.getJavaModifierList()); + } + + @Override + public void visit(ASTInterfaceDeclaration node) { + this.removeJavaInfoAnnot(node.getJavaModifierList()); + } + + @Override + public void visit(ASTEnumDeclaration node) { + this.removeJavaInfoAnnot(node.getJavaModifierList()); + } + + @Override + public void visit(ASTMethodDeclaration node) { + removeInfoAnnot(node.getMCModifierList()); + } + + @Override + public void visit(ASTFieldDeclaration node) { + this.removeJavaInfoAnnot(node.getJavaModifierList()); + } + + @Override + public void visit(ASTFormalParameter param) { + removeJavaInfoAnnot(param.getJavaModifierList()); + } + + @Override + public void visit(ASTLocalVariableDeclaration node) { + removeInfoAnnot(node.getMCModifierList()); + } + + private void removeJavaInfoAnnot(List modifiers) { + MatcherHelper.getInfoJavaAnnot(modifiers).map(modifiers::remove); + } + + private void removeInfoAnnot(List modifiers) { + MatcherHelper.getInfoAnnotation(modifiers).map(modifiers::remove); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java new file mode 100644 index 00000000..ed4462dd --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/utils/visitors/JavaAstElemCollector.java @@ -0,0 +1,153 @@ +package de.monticore.codeAdaption.utils.visitors; + +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.*; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.java.javadsl._visitor.JavaDSLVisitor2; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.javalight._visitor.JavaLightVisitor2; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mccommonstatements._visitor.MCCommonStatementsVisitor2; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.statements.mcvardeclarationstatements._visitor.MCVarDeclarationStatementsVisitor2; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.util.*; + +/*** + * this visitor collect Type, field,methods, local-variable and formal parameters + * from a ASTOrdinaryCompilationUnit + */ + +public class JavaAstElemCollector implements JavaDSLVisitor2 { + private final List typeDeclarations = new ArrayList<>(); + private final Map typeElements = new HashMap<>(); + + @Override + public void visit(ASTClassDeclaration node) { + TypeElementCollector collector = visitType(node); + + collector.supertypesDeclarations.addAll(node.getImplementedInterfaceList()); + if (node.isPresentSuperClass()) { + collector.supertypesDeclarations.add(node.getSuperClass()); + } + + typeElements.put(node, collector); + } + + @Override + public void visit(ASTInterfaceDeclaration node) { + TypeElementCollector collector = visitType(node); + collector.supertypesDeclarations.addAll(node.getExtendedInterfaceList()); + typeElements.put(node, collector); + } + + @Override + public void visit(ASTEnumDeclaration node) { + TypeElementCollector collector = visitType(node); + typeElements.put(node, collector); + } + + private TypeElementCollector visitType(ASTTypeDeclaration node) { + typeDeclarations.add(node); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + TypeElementCollector collector = new TypeElementCollector(); + traverser.add4JavaDSL(collector); + traverser.add4JavaLight(collector); + + node.accept(traverser); + + return collector; + } + + public List getAllTypeDeclarations() { + return new ArrayList<>(typeDeclarations); + } + + public List getAllMethodDeclarations(ASTTypeDeclaration type) { + if (typeElements.containsKey(type)) { + return typeElements.get(type).methodDeclarations; + } + return new ArrayList<>(); + } + + public List getAllFieldDeclarations(ASTTypeDeclaration type) { + if (typeElements.containsKey(type)) { + return typeElements.get(type).fieldDeclarations; + } + return new ArrayList<>(); + } + + public List getAllFSuperTypeDeclarations(ASTTypeDeclaration type) { + if (typeElements.containsKey(type)) { + return typeElements.get(type).supertypesDeclarations; + } + return new ArrayList<>(); + } + + public List getAllParameters( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + if (typeElements.containsKey(type) + && typeElements.get(type).formalParamsMap.containsKey(method)) { + return typeElements.get(type).formalParamsMap.get(method); + } + return new ArrayList<>(); + } + + public List getAllLocVariables( + ASTTypeDeclaration type, ASTMethodDeclaration method) { + if (typeElements.containsKey(type) && typeElements.get(type).localVarsMap.containsKey(method)) { + return typeElements.get(type).localVarsMap.get(method); + } + return new ArrayList<>(); + } +} + +/*** + * this class collect element of a type. + */ +class TypeElementCollector implements JavaDSLVisitor2, JavaLightVisitor2 { + + List methodDeclarations = new ArrayList<>(); + List fieldDeclarations = new ArrayList<>(); + List supertypesDeclarations = new ArrayList<>(); + + Map> localVarsMap = new HashMap<>(); + Map> formalParamsMap = new HashMap<>(); + + @Override + public void visit(ASTMethodDeclaration node) { + methodDeclarations.add(node); + + List localVars = new ArrayList<>(); + List formalParams = new ArrayList<>(); + + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + + MCVarDeclarationStatementsVisitor2 localVarCollector = + new MCVarDeclarationStatementsVisitor2() { + @Override + public void visit(ASTLocalVariableDeclaration node) { + localVars.add(node); + } + }; + + MCCommonStatementsVisitor2 formalParamVisitor = + new MCCommonStatementsVisitor2() { + @Override + public void visit(ASTFormalParameter node) { + formalParams.add(node); + } + }; + + traverser.add4MCVarDeclarationStatements(localVarCollector); + traverser.add4MCCommonStatements(formalParamVisitor); + node.accept(traverser); + localVarsMap.put(node, localVars); + formalParamsMap.put(node, formalParams); + } + + @Override + public void visit(ASTFieldDeclaration node) { + fieldDeclarations.add(node); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java new file mode 100644 index 00000000..4c45c855 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/CodeValidator.java @@ -0,0 +1,201 @@ +package de.monticore.codeAdaption.validator; + +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static de.monticore.codeAdaption.utils.JavaLoader.readJavaCode; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.NameMatcher.NameTMemberMatcher; +import de.monticore.codeAdaption.matcher.NameMatcher.NameTypeMatcher; +import de.monticore.codeAdaption.matcher.TMemberMatcher; +import de.monticore.codeAdaption.matcher.TypeMatcher; +import de.monticore.codeAdaption.matcher.VariableMatcher; +import de.monticore.codeAdaption.matcher.annotMatcher.AnnotTMemberMatcher; +import de.monticore.codeAdaption.matcher.annotMatcher.AnnotTypeMatcher; +import de.monticore.codeAdaption.matcher.annotMatcher.AnnotVariableMatcher; +import de.monticore.codeAdaption.matcher.compMatcher.CompTMemberMatcher; +import de.monticore.codeAdaption.matcher.compMatcher.CompTypeMatcher; +import de.monticore.codeAdaption.matcher.compMatcher.CompVariableMatcher; +import de.monticore.codeAdaption.matcher.errorMatcher.ErrorTMemberMatcher; +import de.monticore.codeAdaption.matcher.errorMatcher.ErrorTypeMatcher; +import de.monticore.codeAdaption.matcher.errorMatcher.ErrorVariableMatcher; +import de.monticore.codeAdaption.matcher.ignoreMatcher.IgnoreTMemberMatcher; +import de.monticore.codeAdaption.matcher.ignoreMatcher.IgnoreTypeMatcher; +import de.monticore.codeAdaption.matcher.ignoreMatcher.IgnoreVariableMatcher; +import de.monticore.codeAdaption.matcher.infixMatcher.InfixTMemberMatcher; +import de.monticore.codeAdaption.matcher.infixMatcher.InfixTypeMatcher; +import de.monticore.codeAdaption.matcher.infixMatcher.InfixVariableMatcher; +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.codeAdaption.validator.cocos.OneVarInDeclaration; +import de.monticore.codeAdaption.validator.cocos.ValidAnnotation; +import de.monticore.codeAdaption.validator.cocos.ValidTemplate; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.java.javadsl._cocos.JavaDSLASTFieldDeclarationCoCo; +import de.monticore.java.javadsl._cocos.JavaDSLASTJavaAnnotationCoCo; +import de.monticore.java.javadsl._cocos.JavaDSLASTTypeDeclarationCoCo; +import de.monticore.java.javadsl._cocos.JavaDSLCoCoChecker; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.javalight._cocos.JavaLightASTAnnotationCoCo; +import de.monticore.javalight._cocos.JavaLightASTMethodDeclarationCoCo; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mccommonstatements._cocos.MCCommonStatementsASTFormalParameterCoCo; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.statements.mcvardeclarationstatements._cocos.MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import java.nio.file.Path; +import java.util.*; + +/*** + * this class check if a reference Code is valid for the given reference code. + */ + +public class CodeValidator { + private final CompTypeMatcher typeMatcher; + private final CompTMemberMatcher tMemberMatcher; + private final CompVariableMatcher variableMatcher; + + public CodeValidator(ASTCDCompilationUnit cd, Set params) { + List typeMatchers = new ArrayList<>(); + List tMemberMatchers = new ArrayList<>(); + List variableMatchers = new ArrayList<>(); + + if (params.contains(AdapterParam.ANNOTATION_MATCHING)) { + typeMatchers.add(new AnnotTypeMatcher(cd)); + tMemberMatchers.add(new AnnotTMemberMatcher(cd)); + variableMatchers.add(new AnnotVariableMatcher(cd)); + } + + if (params.contains(AdapterParam.NAME_MATCHING)) { + typeMatchers.add(new NameTypeMatcher(cd)); + tMemberMatchers.add(new NameTMemberMatcher(cd)); + } + + if (params.contains(AdapterParam.INFIX_MATCHING)) { + typeMatchers.add(new InfixTypeMatcher(cd)); + tMemberMatchers.add(new InfixTMemberMatcher(cd)); + variableMatchers.add(new InfixVariableMatcher(cd)); + } + + if (params.contains(IGNORE_NON_MATCHED_TYPE)) { + typeMatchers.add(new IgnoreTypeMatcher()); + } else { + typeMatchers.add(new ErrorTypeMatcher()); + } + + if (params.contains(IGNORE_NON_MATCHED_TYPE_MEMBER)) { + tMemberMatchers.add(new IgnoreTMemberMatcher()); + } else { + tMemberMatchers.add(new ErrorTMemberMatcher()); + } + + if (params.contains(IGNORE_NON_MATCHED_VAR)) { + variableMatchers.add(new IgnoreVariableMatcher()); + } else { + variableMatchers.add(new ErrorVariableMatcher()); + } + + typeMatcher = new CompTypeMatcher(typeMatchers); + variableMatcher = new CompVariableMatcher(variableMatchers); + tMemberMatcher = new CompTMemberMatcher(tMemberMatchers); + + tMemberMatcher.setTypeMatcher(typeMatcher); + } + + public boolean isValid(ASTCDCompilationUnit refCD, Path refCode) { + Set asts = readJavaCode(refCode); + + // check cocos phase 1 + asts.forEach(ast -> runCoCosPhase1(ast, refCD)); + + // cocos phase 2 + asts.forEach(ast -> runCoCosPhase2(ast, refCD)); + + // check that all elements matched + Set allType = new HashSet<>(); + for (ASTOrdinaryCompilationUnit ast : asts) { + JavaAstElemCollector collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + ast.accept(traverser); + + allType.addAll(collector.getAllTypeDeclarations()); + checkAllMatching(collector); + } + + typeMatcher.setAllTypeDeclarations(allType); + return true; + } + + protected void checkAllMatching(JavaAstElemCollector collector) { + + for (ASTTypeDeclaration type : collector.getAllTypeDeclarations()) { + if (getMatchedType(type).isPresent()) { + collector.getAllFieldDeclarations(type).forEach(f -> getMatchedField(type, f)); + + for (ASTMethodDeclaration method : collector.getAllMethodDeclarations(type)) { + if (getMatchedMethod(type, method).isPresent()) { + collector + .getAllLocVariables(type, method) + .forEach(lv -> getMatchedLocalVariable(type, method, lv)); + collector + .getAllParameters(type, method) + .forEach(params -> getMatchedParameter(type, method, params)); + } + } + } + } + } + + public Optional getMatchedMethod( + ASTTypeDeclaration type, ASTMethodDeclaration element) { + return tMemberMatcher.getMatchedMethod(type, element); + } + + public Optional getMatchedField( + ASTTypeDeclaration type, ASTFieldDeclaration element) { + return tMemberMatcher.getMatchedField(type, element); + } + + public Optional getMatchedSupertype(ASTTypeDeclaration type, ASTMCType supertype) { + return tMemberMatcher.getMatchedSupertype(type, supertype); + } + + public Optional getMatchedType(ASTTypeDeclaration element) { + return typeMatcher.getMatchedType(element); + } + + public Optional getMatchedLocalVariable( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTLocalVariableDeclaration element) { + return variableMatcher.getMatchedLocalVariable(type, method, element); + } + + public Optional getMatchedParameter( + ASTTypeDeclaration type, ASTMethodDeclaration method, ASTFormalParameter element) { + return variableMatcher.getMatchedFormalParameter(type, method, element); + } + + protected void runCoCosPhase1(ASTOrdinaryCompilationUnit ast, ASTCDCompilationUnit refCD) { + JavaDSLCoCoChecker checker = new JavaDSLCoCoChecker(); + checker.addCoCo((JavaDSLASTJavaAnnotationCoCo) new ValidAnnotation(refCD)); + checker.addCoCo((JavaLightASTAnnotationCoCo) new ValidAnnotation(refCD)); + checker.addCoCo((JavaDSLASTFieldDeclarationCoCo) new OneVarInDeclaration()); + checker.addCoCo( + (MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo) new OneVarInDeclaration()); + checker.checkAll(ast); + } + + protected void runCoCosPhase2(ASTOrdinaryCompilationUnit ast, ASTCDCompilationUnit refCD) { + JavaDSLCoCoChecker checker = new JavaDSLCoCoChecker(); + checker.addCoCo((JavaDSLASTTypeDeclarationCoCo) new ValidTemplate(refCD)); + checker.addCoCo((JavaLightASTMethodDeclarationCoCo) new ValidTemplate(refCD)); + checker.addCoCo((MCCommonStatementsASTFormalParameterCoCo) new ValidTemplate(refCD)); + checker.addCoCo( + (MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo) new ValidTemplate(refCD)); + checker.checkAll(ast); + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/OneVarInDeclaration.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/OneVarInDeclaration.java new file mode 100644 index 00000000..f453ad5a --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/OneVarInDeclaration.java @@ -0,0 +1,34 @@ +package de.monticore.codeAdaption.validator.cocos; + +import static de.monticore.codeAdaption.utils.AdapterUtils.getPosition; + +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._cocos.JavaDSLASTFieldDeclarationCoCo; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.statements.mcvardeclarationstatements._cocos.MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo; +import de.se_rwth.commons.logging.Log; + +/** + * check if there are only one variable for each variable declaration. eg: "String a, b"; is not + * allowed. allow is "String a; String b"; + */ +public class OneVarInDeclaration + implements JavaDSLASTFieldDeclarationCoCo, + MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo { + protected String message = + "0xRC002 %s invalid variable declaration: expected just one variable per declaration but got more."; + + @Override + public void check(ASTFieldDeclaration node) { + if (node.getVariableDeclaratorList().size() > 1) { + Log.error(String.format(message, getPosition(node.get_SourcePositionStart()))); + } + } + + @Override + public void check(ASTLocalVariableDeclaration node) { + if (node.getVariableDeclaratorList().size() > 1) { + Log.error(String.format(message, getPosition(node.get_SourcePositionStart()))); + } + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java new file mode 100644 index 00000000..e78822a9 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidAnnotation.java @@ -0,0 +1,102 @@ +package de.monticore.codeAdaption.validator.cocos; + +import static de.monticore.codeAdaption.utils.AdapterUtils.getPosition; +import static de.monticore.codeAdaption.utils.Constants.*; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.annotMatcher.AnnotElementCollector; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.codeAdaption.utils.Constants; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTJavaAnnotation; +import de.monticore.java.javadsl._cocos.JavaDSLASTJavaAnnotationCoCo; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTAnnotation; +import de.monticore.javalight._cocos.JavaLightASTAnnotationCoCo; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; +import de.monticore.symboltable.ISymbol; +import de.se_rwth.commons.logging.Log; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ValidAnnotation implements JavaDSLASTJavaAnnotationCoCo, JavaLightASTAnnotationCoCo { + private final ASTCDCompilationUnit cd; + + public ValidAnnotation(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + protected String missingTemplate = + "0xRC001 %s Invalid annotation: expected a template or ignore set to 'true'"; + + protected String templateArguments = + "0xRC001 %s Invalid annotation:the number of references is [%d], but the template expect [%d] arguments"; + + protected String refNotFound = + "0xRC001 %s Invalid annotation:the reference [%s] was not found in the class diagram [%s]"; + + @Override + public void check(ASTJavaAnnotation node) { + if (JavaLoader.print(node.getAnnotationName()).endsWith(ANNOT_NAME)) { + checkAnnotation(node); + } + } + + @Override + public void check(ASTAnnotation node) { + if (JavaLoader.print(node.getAnnotationName()).endsWith(ANNOT_NAME)) { + checkAnnotation(node); + } + } + + public void checkAnnotation(ASTMCModifier node) { + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + AnnotElementCollector collector = new AnnotElementCollector(); + traverser.add4JavaLight(collector); + node.accept(traverser); + + String pos = getPosition(node.get_SourcePositionStart()); + + if (!collector.isIgnore()) { + + // template missing + if (collector.getTemplate() == null) { + Log.error(String.format(missingTemplate, pos)); + } + + // template argument == references + long arguments = + collector.getTemplate() == null + ? 0 + : collector.getTemplate().chars().filter(s -> (char) s == '$').count(); + long references = collector.getReferences().size(); + if (arguments != collector.getReferences().size()) { + Log.error(String.format(templateArguments, pos, references, arguments)); + } + + // reference must exist in the class diagram + for (String ref : collector.getReferences()) { + Optional symbol = AdapterUtils.resolveCDSymbol(ref, cd); + if (symbol.isEmpty()) { + Log.error(String.format(refNotFound, pos, ref, cd.getCDDefinition().getName())); + } + } + } + } + + public static List extractPlaceHolders(String template) { + List matches = new ArrayList<>(); + Pattern pattern = Pattern.compile(Constants.PLACE_HOLDER_REGEX); + Matcher matcher = pattern.matcher(template); + + while (matcher.find()) { + matches.add(matcher.group()); + } + + return matches; + } +} diff --git a/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidTemplate.java b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidTemplate.java new file mode 100644 index 00000000..d75399a4 --- /dev/null +++ b/ref-code-adaptation/src/main/java/de/monticore/codeAdaption/validator/cocos/ValidTemplate.java @@ -0,0 +1,92 @@ +package de.monticore.codeAdaption.validator.cocos; + +import static de.monticore.codeAdaption.matcher.MatcherHelper.*; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.matcher.CodeMatching; +import de.monticore.codeAdaption.matcher.MatcherHelper; +import de.monticore.codeAdaption.utils.AdapterUtils; +import de.monticore.java.javadsl._ast.*; +import de.monticore.java.javadsl._cocos.JavaDSLASTFieldDeclarationCoCo; +import de.monticore.java.javadsl._cocos.JavaDSLASTTypeDeclarationCoCo; +import de.monticore.javalight._ast.ASTAnnotation; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.javalight._cocos.JavaLightASTMethodDeclarationCoCo; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mccommonstatements._cocos.MCCommonStatementsASTFormalParameterCoCo; +import de.monticore.statements.mcstatementsbasis._ast.ASTMCModifier; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import de.monticore.statements.mcvardeclarationstatements._cocos.MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo; +import de.se_rwth.commons.logging.Log; +import java.util.Optional; + +public class ValidTemplate + implements JavaDSLASTFieldDeclarationCoCo, + JavaDSLASTTypeDeclarationCoCo, + JavaLightASTMethodDeclarationCoCo, + MCCommonStatementsASTFormalParameterCoCo, + MCVarDeclarationStatementsASTLocalVariableDeclarationCoCo { + protected ASTCDCompilationUnit cd; + + public ValidTemplate(ASTCDCompilationUnit cd) { + this.cd = cd; + } + + protected String message = + "0xRC003 %s invalid annotation template: filling template [%s] with the references " + + " produce [%s]. But expected [%s].\n" + + "allowed templates placeholder are {${},${cap_first} and ${uncap_first} }"; + + @Override + public void check(ASTMethodDeclaration node) { + Optional annotation = getInfoAnnotation(node.getMCModifierList()); + annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, node.getName())); + } + + @Override + public void check(ASTFieldDeclaration node) { + String srcName = node.getVariableDeclarator(0).getDeclarator().getName(); + Optional annotation = getInfoJavaAnnot(node.getJavaModifierList()); + annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, srcName)); + } + + @Override + public void check(ASTTypeDeclaration node) { + Optional annotation = Optional.empty(); + if (node instanceof ASTClassDeclaration) { + annotation = getInfoJavaAnnot(((ASTClassDeclaration) node).getJavaModifierList()); + } else if (node instanceof ASTInterfaceDeclaration) { + annotation = getInfoJavaAnnot(((ASTInterfaceDeclaration) node).getJavaModifierList()); + } else if (node instanceof ASTEnumDeclaration) { + annotation = getInfoJavaAnnot(((ASTEnumDeclaration) node).getJavaModifierList()); + } + + annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, node.getName())); + } + + @Override + public void check(ASTFormalParameter node) { + Optional annotation = getInfoJavaAnnot(node.getJavaModifierList()); + annotation.ifPresent( + astJavaAnnotation -> checkTemplate(astJavaAnnotation, node.getDeclarator().getName())); + } + + @Override + public void check(ASTLocalVariableDeclaration node) { + String srcName = node.getVariableDeclarator(0).getDeclarator().getName(); + Optional annotation = getInfoAnnotation(node.getMCModifierList()); + annotation.ifPresent(astJavaAnnotation -> checkTemplate(astJavaAnnotation, srcName)); + } + + public void checkTemplate(ASTMCModifier annotation, String sourceNAme) { + String pos = AdapterUtils.getPosition(annotation.get_SourcePositionStart()); + CodeMatching matching = mkMatchingFromAnnotation(annotation, cd); + if (matching.getTemplate() != null) { + String computedName = + MatcherHelper.fillTemplate(matching.getTemplate(), matching.getReferences()); + if (!computedName.equals(sourceNAme)) { + Log.error(String.format(message, pos, matching.getTemplate(), computedName, sourceNAme)); + } + } + } +} diff --git a/ref-code-adaptation/src/main/resources/de/monticore/template/cd2java/EmptyBody.ftl b/ref-code-adaptation/src/main/resources/de/monticore/template/cd2java/EmptyBody.ftl new file mode 100644 index 00000000..18e868ab --- /dev/null +++ b/ref-code-adaptation/src/main/resources/de/monticore/template/cd2java/EmptyBody.ftl @@ -0,0 +1,11 @@ + +<#assign retunType = cdPrinter.printType(ast.getMCReturnType())> + +<#if retunType = "boolean"> + return false ; +<#elseif retunType = "int" || retunType = "double" || retunType = "long" || retunType = "short"> + return 0 ; +<#else > + return null ; + + diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java new file mode 100644 index 00000000..ce994ab8 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/AdapterAbstractTest.java @@ -0,0 +1,16 @@ +package de.monticore.codeAdaption; + +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.java.javadsl.JavaDSLMill; +import de.se_rwth.commons.logging.Log; + +public abstract class AdapterAbstractTest { + + public static void initMills() { + JavaDSLMill.init(); + JavaDSLMill.globalScope().clear(); + CD4CodeMill.init(); + CD4CodeMill.globalScope().clear(); + Log.init(); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java new file mode 100644 index 00000000..78099f19 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterTest.java @@ -0,0 +1,97 @@ +package de.monticore.codeAdaption; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.JavaLoader; +import java.io.File; +import java.nio.file.Path; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.*; + +public class CodeAdapterTest extends AdapterAbstractTest { + private final String baseDir = "src/test/resources/de/monticore/codeAdaption/"; + protected Path conHwc = Path.of(baseDir + "hwc"); + private final File REF_CD = new File(baseDir + "App.cd"); + private final File CON_CD = new File(baseDir + "UniApp.cd"); + + private Set confParameters; + private Set adapterParams; + + private Set mappings = Set.of("ref"); + + @BeforeEach + public void setup() { + initMills(); + confParameters = Set.of(NAME_MAPPING, INHERITANCE, STEREOTYPE_MAPPING); + } + + @Test + public void testAdaptionWithName() { + Path outputPath = Path.of("target/adapter/name"); + adapterParams = Set.of(NAME_MATCHING); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + adapter.adapt(REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/name"), conHwc, outputPath); + + String student = readFileWithoutSpace(outputPath, "Student.java"); + Assertions.assertEquals("publicclassStudent{StringstudentId;}", student); + } + + @Test + public void testAdaptionWithInfix() { + Path outputPath = Path.of("target/adapter/infix"); + adapterParams = Set.of(INFIX_MATCHING, IGNORE_NON_MATCHED_VAR); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + adapter.adapt(REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/infix"), conHwc, outputPath); + + String studentBuilder = readFileWithoutSpace(outputPath, "StudentBuilder.java"); + Assertions.assertEquals( + "publicclassStudentBuilder{protectedStringstudentId;publicStudentBuildersetStudentId(Stringid){Studentstudent=newStudent();}}", + studentBuilder); + } + + @Test + public void testAdaptionWithAnnotation() { + Path outputPath = Path.of("target/adapter/annot"); + adapterParams = Set.of(ANNOTATION_MATCHING, IGNORE_NON_MATCHED_VAR); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + adapter.adapt(REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/annot"), conHwc, outputPath); + + String studentRepository = readFileWithoutSpace(outputPath, "StudentRepository.java"); + Assertions.assertEquals( + "importjava.util.*;publicclassStudentRepositoryextendsRepository{privateSetstudentSet=newHashSet<>();publicOptionalfindStudentByStudentId(Stringid){returnOptional.empty();}publicListgetAllStudentSortedByStudentId(){ListstudentList=newArrayList<>();}publicvoidstore(Studentstudent){studentSet.add(student);}}", + studentRepository); + } + + @Test + public void testAdaptionWithAllMatchingStrategy() { + Path outputPath = Path.of("target/adapter/compose"); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, INFIX_MATCHING, IGNORE_NON_MATCHED_VAR); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + + adapter.adapt( + REF_CD, CON_CD, mappings, Path.of(baseDir + "adapter/compose"), conHwc, outputPath); + + String studentRepository = readFileWithoutSpace(outputPath, "StudentRepository.java"); + + Assertions.assertEquals( + "importjava.util.*;publicclassStudentRepositoryextendsRepository{privateSetstudentSet=newHashSet<>();publicOptionalfindStudentByStudentId(Stringid){returnOptional.empty();}publicListgetAllStudentSortedByStudentId(){ListstudentList=newArrayList<>();}publicvoidstore(Studentstudent){studentSet.add(student);}}", + studentRepository); + } + + protected String readFileWithoutSpace(Path dir, String filename) { + Optional file = + JavaLoader.readJavaFile(dir).stream() + .filter(f -> f.getName().endsWith(filename)) + .findFirst(); + Assertions.assertTrue(file.isPresent()); + return JavaLoader.readFileContent(file.get()).replaceAll("\\s+", ""); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java new file mode 100644 index 00000000..7bcd6a75 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/CodeAdapterToolTest.java @@ -0,0 +1,12 @@ +package de.monticore.codeAdaption; + +import org.junit.jupiter.api.Test; + +public class CodeAdapterToolTest { + + @Test + public void test() { + String cmd = "-i University.cd --reference UserRole.cd --rc code" ; + // String cmd = "java -jar AdapterTool.jar -i University.cd --reference UserRole.cd --rc code" ; + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java new file mode 100644 index 00000000..caf2445f --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase1.java @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.evaluation; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; + +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.codeAdaption.CodeAdapter; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class CodeAdapterTestCase1 extends EvaluationAbstractTest { + + @BeforeEach + public void setup() { + referenceCD = new File(resourcesPath + "testcase_1/Reference.cd"); + concreteCD = new File(resourcesPath + "testcase_1/Concrete.cd"); + refCodePath = Path.of(resourcesPath + "testcase_1/reference"); + conCodePath = Path.of(resourcesPath + "testcase_1/concrete"); + output = Path.of("target/codeAdapter/evaluation/testcase_1/"); + CD4CodeMill.init(); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, INFIX_MATCHING, IGNORE_NON_MATCHED_VAR); + confParameters = Set.of(INHERITANCE, STEREOTYPE_MAPPING, SRC_TARGET_ASSOC_MAPPING); + } + + @Test + @DisplayName("Evaluation Code Adapter Case Study 1") + public void evaluationCodeAdapterCaseStudy1Test() { + Set mappings = Set.of("stud", "prof"); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java new file mode 100644 index 00000000..a752ad75 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/CodeAdapterTestCase2a.java @@ -0,0 +1,42 @@ +package de.monticore.codeAdaption.evaluation; + +import static de.monticore.cdconformance.CDConfParameter.*; +import static de.monticore.codeAdaption.utils.AdapterParam.*; +import static de.monticore.codeAdaption.utils.AdapterParam.IGNORE_NON_MATCHED_VAR; + +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.codeAdaption.CodeAdapter; +import de.monticore.codeAdaption.utils.Generator; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class CodeAdapterTestCase2a extends EvaluationAbstractTest { + + @BeforeEach + public void setup() { + referenceCD = new File(resourcesPath + "testcase_2_cd4code/Reference.cd"); + concreteCD = new File(resourcesPath + "testcase_2_cd4code/Concrete.cd"); + refCodePath = Path.of(resourcesPath + "testcase_2_cd4code/hwc/entity"); + conCodePath = Path.of(resourcesPath + "testcase_2_cd4code/concrete"); + output = Path.of("target/codeAdapter/evaluation/testcase_2_cd4code/"); + CD4CodeMill.init(); + adapterParams = + Set.of(NAME_MATCHING, ANNOTATION_MATCHING, INFIX_MATCHING, IGNORE_NON_MATCHED_VAR); + confParameters = Set.of(INHERITANCE, STEREOTYPE_MAPPING, SRC_TARGET_ASSOC_MAPPING); + } + + @Test + @DisplayName("Evaluation Code Adapter Case Study 2 CD4Code") + public void evaluationCodeAdapterCaseStudy1Test() { + Set mappings = Set.of("stud"); + CodeAdapter adapter = new CodeAdapter(adapterParams, confParameters); + adapter.adapt(referenceCD, concreteCD, mappings, refCodePath, conCodePath, output); + + Path genCode = Path.of("target/codeAdapter/evaluation/testcase_2_cd4code/generated"); + Generator.generate(concreteCD, output, genCode); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/ConfCheckerEvalTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/ConfCheckerEvalTest.java new file mode 100644 index 00000000..a04ed62f --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/ConfCheckerEvalTest.java @@ -0,0 +1,44 @@ +package de.monticore.codeAdaption.evaluation; + +import static de.monticore.cdconformance.CDConfParameter.*; + +import de.monticore.cd4code.CD4CodeMill; +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.cdconformance.CDConformanceChecker; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ConfCheckerEvalTest extends EvaluationAbstractTest { + @BeforeEach + public void setup() { + referenceCD = new File(resourcesPath + "confCheckingCD/Reference.cd"); + concreteCD = new File(resourcesPath + "confCheckingCD/Concrete.cd"); + refCodePath = Path.of(resourcesPath + "confCheckingCD/reference"); + conCodePath = Path.of(resourcesPath + "confCheckingCD/concrete"); + output = Path.of("target/codeAdapter/evaluation/confCheckingCD/"); + CD4CodeMill.init(); + Log.init(); + confParameters = Set.of(INHERITANCE, STEREOTYPE_MAPPING, SRC_TARGET_ASSOC_MAPPING); + } + + @Test + @DisplayName("Evaluation conformance checker for class diagrams") + public void evaluationConformanceCheckerCDtest() { + long start = System.currentTimeMillis(); + Set mappings = Set.of("prof", "stud"); + ASTCDCompilationUnit conCD = JavaLoader.loadCD(concreteCD); + ASTCDCompilationUnit refCD = JavaLoader.loadCD(referenceCD); + + CDConformanceChecker conformanceChecker = new CDConformanceChecker(confParameters); + Assertions.assertTrue(conformanceChecker.checkConformance(conCD, refCD, mappings)); + double duration = (System.currentTimeMillis() - start) / 1000.0; + System.out.println("duration: " + duration); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/EvaluationAbstractTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/EvaluationAbstractTest.java new file mode 100644 index 00000000..0c46345a --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/evaluation/EvaluationAbstractTest.java @@ -0,0 +1,21 @@ +package de.monticore.codeAdaption.evaluation; + +import de.monticore.cdconformance.CDConfParameter; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.AdapterParam; +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +public abstract class EvaluationAbstractTest extends AdapterAbstractTest { + protected final String resourcesPath = "src/test/resources/de/monticore/codeAdaption/evaluation/"; + protected File referenceCD; + protected File concreteCD; + + protected Set adapterParams; + protected Set confParameters; + + protected Path refCodePath; + protected Path conCodePath; + protected Path output; +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java new file mode 100644 index 00000000..c3b3c625 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/AnnotMatcherTest.java @@ -0,0 +1,95 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class AnnotMatcherTest extends MatcherAbstractTest { + private CodeValidator validator; + + @Override + public void init(String javaFile) { + super.init(javaFile); + validator = new CodeValidator(cd, Set.of(AdapterParam.ANNOTATION_MATCHING)); + } + + @Test + public void TestTypeAnnotationMatching() { + init("/annotMatcher/EntityRepository.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + Optional matching = validator.getMatchedType(entityRepos); + + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${}Repository", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestMethodAnnotationMatching() { + init("/annotMatcher/EntityRepository.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + ASTMethodDeclaration method = collector.getAllMethodDeclarations(entityRepos).get(0); + + Optional matching = validator.getMatchedMethod(entityRepos, method); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(2, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("id", matching.get().getReferences().get(1).getName()); + Assertions.assertEquals("find${}By${cap_first}", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestAttributeAnnotationMatching() { + init("/annotMatcher/EntityRepository.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + ASTFieldDeclaration attribute = collector.getAllFieldDeclarations(entityRepos).get(0); + + Optional matching = validator.getMatchedField(entityRepos, attribute); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${uncap_first}Set", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestLocalVariableAnnotationMatching() { + init("/annotMatcher/EntityRepository.java"); + ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(2); + ASTLocalVariableDeclaration localVar = collector.getAllLocVariables(type, method).get(0); + + Optional matching = validator.getMatchedLocalVariable(type, method, localVar); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${uncap_first}List", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestFormalParameterAnnotationMatching() { + init("/annotMatcher/EntityRepository.java"); + ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(3); + ASTFormalParameter param = collector.getAllParameters(type, method).get(0); + + Optional matching = validator.getMatchedParameter(type, method, param); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${uncap_first}", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java new file mode 100644 index 00000000..86662685 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/InfixMatcherTest.java @@ -0,0 +1,95 @@ +package de.monticore.codeAdaption.matcher; + +import static de.monticore.codeAdaption.utils.AdapterParam.INFIX_MATCHING; + +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import de.monticore.statements.mccommonstatements._ast.ASTFormalParameter; +import de.monticore.statements.mcvardeclarationstatements._ast.ASTLocalVariableDeclaration; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.*; + +class InfixMatcherTest extends MatcherAbstractTest { + private CodeValidator validator; + + @Override + public void init(String javaFile) { + super.init(javaFile); + validator = new CodeValidator(cd, Set.of(INFIX_MATCHING)); + } + + @Test + public void TestTypeInfixMatching() { + init("/infixMatcher/EntityRepository.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + Optional matching = validator.getMatchedType(entityRepos); + + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${}Repository", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestMethodInfixMatching() { + init("/infixMatcher/EntityRepository.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + ASTMethodDeclaration method = collector.getAllMethodDeclarations(entityRepos).get(0); + + Optional matching = validator.getMatchedMethod(entityRepos, method); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(2, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("id", matching.get().getReferences().get(1).getName()); + Assertions.assertEquals("find${}By${cap_first}", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestAttributeInfixMatching() { + init("/infixMatcher/EntityRepository.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + ASTFieldDeclaration attribute = collector.getAllFieldDeclarations(entityRepos).get(0); + + Optional matching = validator.getMatchedField(entityRepos, attribute); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${uncap_first}Set", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestLocalVariableInfixMatching() { + init("/infixMatcher/EntityRepository.java"); + ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(2); + ASTLocalVariableDeclaration localVar = collector.getAllLocVariables(type, method).get(0); + + Optional matching = validator.getMatchedLocalVariable(type, method, localVar); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${uncap_first}List", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestFormalParameterAnnotationMatching() { + init("/infixMatcher/EntityRepository.java"); + ASTTypeDeclaration type = collector.getAllTypeDeclarations().get(0); + ASTMethodDeclaration method = collector.getAllMethodDeclarations(type).get(3); + ASTFormalParameter param = collector.getAllParameters(type, method).get(0); + + Optional matching = validator.getMatchedParameter(type, method, param); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${uncap_first}", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/MatcherAbstractTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/MatcherAbstractTest.java new file mode 100644 index 00000000..39da285b --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/MatcherAbstractTest.java @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import java.io.File; +import java.nio.file.Path; +import org.junit.jupiter.api.BeforeEach; + +public abstract class MatcherAbstractTest extends AdapterAbstractTest { + protected final Path REF_HWC_Dir = + Path.of("src/test/resources/de/monticore/codeAdaption/matcher"); + protected final Path REF_CD = Path.of("src/test/resources/de/monticore/codeAdaption/App.cd"); + + protected ASTCDCompilationUnit cd; + + protected JavaAstElemCollector collector; + + @BeforeEach + public void setup() { + initMills(); + } + + public void init(String javaFile) { + collector = new JavaAstElemCollector(); + JavaDSLTraverser traverser = JavaDSLMill.traverser(); + traverser.add4JavaDSL(collector); + ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(new File(REF_HWC_Dir + javaFile)); + cd = JavaLoader.loadCD(new File(REF_CD.toString())); + + ast.accept(traverser); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/NameTypeMatcherTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/NameTypeMatcherTest.java new file mode 100644 index 00000000..1c746087 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/matcher/NameTypeMatcherTest.java @@ -0,0 +1,47 @@ +package de.monticore.codeAdaption.matcher; + +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.validator.CodeValidator; +import de.monticore.java.javadsl._ast.ASTFieldDeclaration; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class NameTypeMatcherTest extends MatcherAbstractTest { + private CodeValidator validator; + + @Override + public void init(String javaFile) { + super.init(javaFile); + validator = new CodeValidator(cd, Set.of(AdapterParam.NAME_MATCHING)); + } + + @Test + public void TestTypeNameMatching() { + init("/nameMatcher/Entity.java"); + ASTTypeDeclaration entity = collector.getAllTypeDeclarations().get(0); + Optional matching = validator.getMatchedType(entity); + + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("Entity", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${}", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } + + @Test + public void TestAttributeNameMatching() { + init("/nameMatcher/Entity.java"); + ASTTypeDeclaration entityRepos = collector.getAllTypeDeclarations().get(0); + ASTFieldDeclaration attribute = collector.getAllFieldDeclarations(entityRepos).get(0); + + Optional matching = validator.getMatchedField(entityRepos, attribute); + Assertions.assertTrue(matching.isPresent()); + Assertions.assertEquals(1, matching.get().getReferences().size()); + Assertions.assertEquals("id", matching.get().getReferences().get(0).getName()); + Assertions.assertEquals("${}", matching.get().getTemplate()); + Assertions.assertTrue(matching.get().mustBePerform()); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java new file mode 100644 index 00000000..64590171 --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/utils/JavaAstElemCollectorTest.java @@ -0,0 +1,49 @@ +package de.monticore.codeAdaption.utils; + +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector; +import de.monticore.java.javadsl.JavaDSLMill; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.monticore.java.javadsl._ast.ASTTypeDeclaration; +import de.monticore.java.javadsl._visitor.JavaDSLTraverser; +import de.monticore.javalight._ast.ASTMethodDeclaration; +import java.io.File; +import java.nio.file.Path; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class JavaAstElemCollectorTest extends AdapterAbstractTest { + private final Path REF_HWC_CODE = + Path.of("src/test/resources/de/monticore/codeAdaption/utils/ElementCollection.java"); + + private JavaAstElemCollector collector; + private JavaDSLTraverser traverser; + + @BeforeEach + public void init() { + initMills(); + traverser = JavaDSLMill.traverser(); + collector = new JavaAstElemCollector(); + traverser.add4JavaDSL(collector); + } + + @Test + public void testTypeOperationCollection() { + ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(new File(REF_HWC_CODE.toString())); + ast.accept(traverser); + + // check a type collection + Assertions.assertEquals(collector.getAllTypeDeclarations().size(), 1); + + // check type element collection + ASTTypeDeclaration t = collector.getAllTypeDeclarations().get(0); + Assertions.assertEquals(2, collector.getAllFieldDeclarations(t).size()); + Assertions.assertEquals(1, collector.getAllMethodDeclarations(t).size()); + + // check method element collection + ASTMethodDeclaration m = collector.getAllMethodDeclarations(t).get(0); + Assertions.assertEquals(2, collector.getAllParameters(t, m).size()); + Assertions.assertEquals(2, collector.getAllLocVariables(t, m).size()); + } +} diff --git a/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java new file mode 100644 index 00000000..2e9e042b --- /dev/null +++ b/ref-code-adaptation/src/test/java/de/monticore/codeAdaption/validator/CodeValidatorTest.java @@ -0,0 +1,71 @@ +package de.monticore.codeAdaption.validator; + +import static de.monticore.codeAdaption.utils.AdapterParam.*; + +import de.monticore.cdbasis._ast.ASTCDCompilationUnit; +import de.monticore.codeAdaption.AdapterAbstractTest; +import de.monticore.codeAdaption.utils.AdapterParam; +import de.monticore.codeAdaption.utils.JavaLoader; +import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit; +import de.se_rwth.commons.logging.Log; +import java.io.File; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class CodeValidatorTest extends AdapterAbstractTest { + protected String baseDir = "src/test/resources/de/monticore/codeAdaption/validator/"; + protected CodeValidator validator; + protected ASTCDCompilationUnit cd; + protected Set confParameters = + Set.of(IGNORE_NON_MATCHED_TYPE, IGNORE_NON_MATCHED_TYPE_MEMBER, IGNORE_NON_MATCHED_VAR); + + @BeforeEach + public void setup() { + initMills(); + Log.enableFailQuick(false); + cd = JavaLoader.loadCD(new File(baseDir + "Validator.cd")); + validator = new CodeValidator(cd, confParameters); + } + + public static Stream invalidFiles1() { + return Stream.of( + Arguments.of("InvalidReference.java", "0xRC001"), + Arguments.of("ManyVarInOneFieldDecl.java", "0xRC002"), + Arguments.of("ManyVarInOneLocalVarDecl.java", "0xRC002"), + Arguments.of("MissingTemplate.java", "0xRC001"), + Arguments.of("MissingTemplateArgument.java", "0xRC001")); + } + + public static Stream invalidFiles2() { + return Stream.of(Arguments.of("InvalidTemplate.java", "0xRC003")); + } + + @ParameterizedTest + @MethodSource("invalidFiles1") + public void checkAnnotationPhase1(String filename, String errorCode) { + + String fileName = baseDir + "invalid/" + filename; + ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(new File(fileName)); + validator.runCoCosPhase1(ast, cd); + + Assertions.assertEquals(1, Log.getErrorCount()); + Assertions.assertTrue(Log.getFindings().get(0).getMsg().startsWith(errorCode)); + } + + @ParameterizedTest + @MethodSource("invalidFiles2") + public void checkAnnotationPhase2(String filename, String errorCode) { + + String fileName = baseDir + "invalid/" + filename; + ASTOrdinaryCompilationUnit ast = JavaLoader.loadJava(new File(fileName)); + validator.runCoCosPhase2(ast, cd); + + Assertions.assertEquals(Log.getErrorCount(), 5); + Log.getFindings().forEach(f -> Assertions.assertTrue(f.getMsg().startsWith(errorCode))); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd new file mode 100644 index 00000000..8ed23820 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/App.cd @@ -0,0 +1,20 @@ +import java.lang.String ; + +classdiagram App { + class Application; + + + + class Entity{ + - String id ; + } + + + + + class Service; + + +// association Application -> service.Service; +// association Service ->entity.Entity; + +} + diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd new file mode 100644 index 00000000..85f72c87 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/UniApp.cd @@ -0,0 +1,17 @@ +import java.lang.String ; + +classdiagram UniApp { + + <> class SchoolApplication; + + + <> + class Student { + <>- String studentId ; + } + + + +<> + class StudentService; + + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/Entity.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/Entity.java new file mode 100644 index 00000000..9bd43e1f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/Entity.java @@ -0,0 +1,6 @@ +import de.monticore.codeAdaption.utils.Adapt; +@Adapt(ref = "Entity",template = "${}") +public class Entity { + @Adapt(ref = "Entity.id",template = "${}") + String id; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/EntityRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/EntityRepository.java new file mode 100644 index 00000000..d23c5965 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/EntityRepository.java @@ -0,0 +1,30 @@ + +import Repository; +import de.monticore.codeAdaption.utils.Adapt; + +import java.util.*; + +import Entity; + +@Adapt(ref = {"Entity"}, template = "${}Repository") +public class EntityRepository extends Repository { + + @Adapt(ref = {"Entity"}, template = "${uncap_first}Set") + private Set entitySet = new HashSet<>(); + + @Adapt(ref = {"Entity", "Entity.id"}, template = "find${}By${cap_first}") + public Optional findEntityById(String id) { + return Optional.empty(); + } + + @Adapt(ref = {"Entity", "Entity.id"}, template = "getAll${}SortedBy${cap_first}") + public List getAllEntitySortedById() { + @Adapt(ref = {"Entity"}, template = "${uncap_first}List") + List entityList = new ArrayList<>(); + } + @Adapt(ignore = true) + public void store( + @Adapt(ref = {"Entity"}, template = "${uncap_first}") Entity entity) { + entitySet.add(entity); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/Repository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/Repository.java new file mode 100644 index 00000000..1b79d493 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/annot/Repository.java @@ -0,0 +1,5 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ignore = true) +public class Repository { +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/Entity.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/Entity.java new file mode 100644 index 00000000..4c712628 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/Entity.java @@ -0,0 +1,7 @@ + + + + +public class Entity { + String id; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/EntityRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/EntityRepository.java new file mode 100644 index 00000000..4d702193 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/EntityRepository.java @@ -0,0 +1,30 @@ + +import Repository; +import de.monticore.codeAdaption.utils.Adapt; +import java.util.*; + +import Entity; + + +public class EntityRepository extends Repository { + + + private Set entitySet = new HashSet<>(); + + @Adapt(ref = {"Entity", "Entity.id"}, template = "find${}By${cap_first}") + public Optional findEntityById(String id) { + return Optional.empty(); + } + + @Adapt(ref = {"Entity", "Entity.id"}, template = "getAll${}SortedBy${cap_first}") + public List getAllEntitySortedById() { + + List entityList = new ArrayList<>(); + } + @Adapt(ignore = true) + public void store( + @Adapt(ref = {"Entity"}, template = "${uncap_first}") + Entity entity) { + entitySet.add(entity); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/Repository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/Repository.java new file mode 100644 index 00000000..1b79d493 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/compose/Repository.java @@ -0,0 +1,5 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ignore = true) +public class Repository { +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/infix/Entity.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/infix/Entity.java new file mode 100644 index 00000000..4c712628 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/infix/Entity.java @@ -0,0 +1,7 @@ + + + + +public class Entity { + String id; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/infix/EntityBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/infix/EntityBuilder.java new file mode 100644 index 00000000..2d018b6f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/infix/EntityBuilder.java @@ -0,0 +1,10 @@ + + + +public class EntityBuilder { + protected String id; + + public EntityBuilder setId(String id) { + Entity entity = new Entity(); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java new file mode 100644 index 00000000..4c712628 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/adapter/name/Entity.java @@ -0,0 +1,7 @@ + + + + +public class Entity { + String id; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd new file mode 100644 index 00000000..5133fbcf --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Concrete.cd @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.evaluation; +import java.lang.String; + +classdiagram Concrete { + + <>class Person{ + <> String firstname; + <> String lastname; + <> Date birthDay; + } + + <> class Professor { + <> String workingId; + <> String password; + <> int yearOfExperience; + } + + <>class TeachingRole { + <> String name ; + } + + <> class Student { + <> String matriculationId; + <>String password ; + <> int semester; + } + + + <> class HiwiRole { + <> String name ; + } + + + + association [1] Student -> (roles)HiwiRole [*]; + association [1] Professor -> (roles)TeachingRole [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd new file mode 100644 index 00000000..22969782 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/Reference.cd @@ -0,0 +1,23 @@ +package de.monticore.codeAdaption.evaluation; +import java.lang.String; + +classdiagram Reference { + + class Person { + String firstname; + String lastname; + Date birthday; + } + + class User { + String loginName; + String password; + int intData; + } + + class Role { + String name; + } + + association [1] User -> (roles)Role [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd new file mode 100644 index 00000000..261cda75 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Concrete.cd @@ -0,0 +1,37 @@ +package de.monticore.codeAdaption.evaluation.confCheckingCD; +import java.lang.String; + +classdiagram Concrete { + + <>class Person{ + <> String firstname; + <> String lastname; + <> Date birthDay; + } + + <> class Professor { + <> String workingId; + <> String password; + <> int yearOfExperience; + } + + <>class TeachingRole extends Role ; + + <> class Student { + <> String matriculationId; + <>String password ; + <> int semester; + } + + + <> class HiwiRole extends Role ; + + class Role { + <> String name; + } + + + + association [1] Student -> (roles)HiwiRole [*]; + association [1] Professor -> (roles)TeachingRole [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd new file mode 100644 index 00000000..7b31ec6a --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/confCheckingCD/Reference.cd @@ -0,0 +1,23 @@ +package de.monticore.codeAdaption.evaluation.confCheckingCD; +import java.lang.String; + +classdiagram Reference { + + class Person { + String firstname; + String lastname; + Date birthday; + } + + class User { + String loginName; + String password; + int intData; + } + + class Role { + String name; + } + + association [1] User -> (roles)Role [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd new file mode 100644 index 00000000..065c8f96 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Concrete.cd @@ -0,0 +1,44 @@ +package de.monticore.codeAdaption.evaluation.testcase_1; +import java.lang.String; + +classdiagram Concrete { + + <>class Person{ + <> String firstname; + <> String lastname; + <> Date birthDay; + } + + <> class Professor { + <> String workingId; + <> String password; + <> int yearOfExperience; + } + + <>class TeachingRole { + <> String name ; + } + + <> class Student { + <> String matriculationId; + <>String password ; + <> int semester; + } + + + <> class HiwiRole { + <> String name ; + } + + <> class GL; + <> class WiMi; + <> class StudentData; + + + association [1] Student -> (roles)HiwiRole [*]; + association [1] Professor -> (roles)TeachingRole [*]; + + association [1] GL (isObservedBy) <-> (observes) WiMi [1]; + association [1] WiMi (isObservedBy) <-> (observes) StudentData [1]; + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd new file mode 100644 index 00000000..dfd8aef5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/Reference.cd @@ -0,0 +1,28 @@ +package de.monticore.codeAdaption.evaluation.testcase_1; +import java.lang.String; + +classdiagram Reference { + + class Person { + String firstname; + String lastname; + Date birthday; + } + + class User { + String loginName; + String password; + int intData; + } + + class Role { + String name; + } + + class Observer; + class Observable; + + association [1] User -> (roles)Role [*]; + + association [1] Observer (isObservedBy) <-> (observes) Observable [1]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/Authentication.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/Authentication.java new file mode 100644 index 00000000..3ae75380 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/Authentication.java @@ -0,0 +1,20 @@ +package de.monticore.codeAdaption.evaluation.reference; + +import de.monticore.codeAdaption.utils.Adapt; +import de.monticore.codeAdaption.evaluation.reference.entity.User; + +@Adapt(ignore = true) +public class Authentication { + + @Adapt(ignore = true) + public boolean authenticate(String username, String password) { + // Implement authentication logic, e.g., check username and password against database + return true; // Return true if authentication is successful, false otherwise + } + + @Adapt(ref = "User", template = "check${}") + public void checkUser(User user){ + + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/UserRegistration.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/UserRegistration.java new file mode 100644 index 00000000..c71fa969 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/UserRegistration.java @@ -0,0 +1,14 @@ +package de.monticore.codeAdaption.evaluation.reference; + +import de.monticore.codeAdaption.evaluation.reference.entity.User; +import de.monticore.codeAdaption.utils.Adapt; + + +public class UserRegistration { + @Adapt(ignore = true) + + public void register(User user) { + // Implement logic to save the user details (username, password, roles) to the database + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/PersonBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/PersonBuilder.java new file mode 100644 index 00000000..4d1b4e0f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/PersonBuilder.java @@ -0,0 +1,49 @@ +package de.monticore.codeAdaption.evaluation.reference.builders; + +import de.monticore.codeAdaption.evaluation.reference.entity.Person; +import de.monticore.codeAdaption.utils.Adapt; + +import java.util.Date; + +public class PersonBuilder { + private String lastname; + private String firstname; + + private Date birthday; + + public PersonBuilder setFirstname(String firstname) { + this.firstname = firstname; + return this; + } + + public PersonBuilder setLastname(String lastname) { + this.lastname = lastname; + return this; + } + + public PersonBuilder setBirthday(Date birthday) { + this.birthday = birthday; + return this; + } + + public Date getBirthday() { + return birthday; + } + + public String getLastname() { + return lastname; + } + + public String getFirstname() { + return firstname; + } +@Adapt(ignore = true) + public Person build() { + Person person = new Person(); + person.setLastname(lastname); + person.setFirstname(firstname); + person.setBirthday(birthday); + + return person; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/RoleBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/RoleBuilder.java new file mode 100644 index 00000000..165958bc --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/RoleBuilder.java @@ -0,0 +1,24 @@ +package de.monticore.codeAdaption.evaluation.reference.builders; + +import de.monticore.codeAdaption.evaluation.reference.entity.Role; +import de.monticore.codeAdaption.utils.Adapt; + +public class RoleBuilder { + private String name; + + public String getName() { + return name; + } + + public RoleBuilder setName(String name) { + this.name = name; + return this; + } + + @Adapt(ignore = true) + public Role build() { + Role role = new Role(); + role.setName(name); + return role; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/UserBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/UserBuilder.java new file mode 100644 index 00000000..4c3e1930 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/builders/UserBuilder.java @@ -0,0 +1,42 @@ +package de.monticore.codeAdaption.evaluation.reference.builders; + +import de.monticore.codeAdaption.evaluation.reference.entity.User; +import de.monticore.codeAdaption.utils.Adapt; + +public class UserBuilder extends PersonBuilder { + private String loginName; + + private String password; + + private int intData; + + public UserBuilder setIntData(int intData) { + this.intData = intData; + return this; + } + + public UserBuilder setLoginName(String loginName) { + this.loginName = loginName; + return this; + } + + public UserBuilder setPassword(String password) { + this.password = password; + return this; + } + + @Override + @Adapt(ignore = true) + public User build() { + User user = new User(); + user.setIntData(intData); + user.setLoginName(loginName); + user.setPassword(password); + + user.setLastname(getLastname()); + user.setFirstname(getFirstname()); + user.setBirthday(getBirthday()); + + return user; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Observable.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Observable.java new file mode 100644 index 00000000..1fa4d851 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Observable.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.evaluation.reference.entity; + +import de.monticore.codeAdaption.utils.Adapt; + +public class Observable { + @Adapt(ignore=true) + public Observer isObservedBy; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Observer.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Observer.java new file mode 100644 index 00000000..28ecf516 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Observer.java @@ -0,0 +1,8 @@ +package de.monticore.codeAdaption.evaluation.reference.entity; + +import de.monticore.codeAdaption.utils.Adapt; + +public class Observer { + @Adapt(ignore=true) + public Observable observes; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Person.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Person.java new file mode 100644 index 00000000..d70c5db8 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Person.java @@ -0,0 +1,33 @@ +package de.monticore.codeAdaption.evaluation.reference.entity; + +import java.util.Date; + +public class Person { + private String lastname; + private String firstname; + private Date birthday; + + public String getLastname() { + return lastname; + } + + public Date getBirthday() { + return birthday; + } + + public String getFirstname() { + return firstname; + } + + public void setBirthday(Date birthday) { + this.birthday = birthday; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Role.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Role.java new file mode 100644 index 00000000..8eb816e0 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/Role.java @@ -0,0 +1,13 @@ +package de.monticore.codeAdaption.evaluation.reference.entity; + +public class Role { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/User.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/User.java new file mode 100644 index 00000000..eb26d967 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/entity/User.java @@ -0,0 +1,32 @@ +package de.monticore.codeAdaption.evaluation.reference.entity; + +public class User extends Person { + private String loginName; + private String password; + + private int intData; + + public String getPassword() { + return password; + } + + public String getLoginName() { + return loginName; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setLoginName(String loginName) { + this.loginName = loginName; + } + + public int getIntData() { + return intData; + } + + public void setIntData(int intData) { + this.intData = intData; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/CRUDRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/CRUDRepository.java new file mode 100644 index 00000000..40af77c1 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/CRUDRepository.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.evaluation.reference.repository; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ignore = true) +public interface CRUDRepository {} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/RoleRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/RoleRepository.java new file mode 100644 index 00000000..4960661f --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/RoleRepository.java @@ -0,0 +1,18 @@ +package de.monticore.codeAdaption.evaluation.reference.repository; + +import de.monticore.codeAdaption.evaluation.reference.entity.Role; +import de.monticore.codeAdaption.evaluation.reference.entity.User; + +import java.util.List; + +public interface RoleRepository extends CRUDRepository{ + User getRoleByName(String name); + + void storeRole(User user); + + List getAllRole(); + + List getAllRoleSortedByName(); + + void removeRole(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/UserRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/UserRepository.java new file mode 100644 index 00000000..8c92d7a9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_1/reference/repository/UserRepository.java @@ -0,0 +1,17 @@ +package de.monticore.codeAdaption.evaluation.reference.repository; + +import de.monticore.codeAdaption.evaluation.reference.entity.User; + +import java.util.List; + +public interface UserRepository extends CRUDRepository { + User getUserByLoginName(String name); + + void storeUser(User user); + + List getAllUser(); + + List getAllUserSortedByLoginName(); + + void removeUser(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd new file mode 100644 index 00000000..0d27a347 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Concrete.cd @@ -0,0 +1,23 @@ +package de.monticore.codeAdaption.evaluation.testcase_2_cd4code; +import java.lang.String; +import java.util.Date; + +classdiagram Concrete { + + <>class Student{ + <> String firstname; + <> String lastname; + <> Date birthDay; + } + + + <> class HiwiRole { + <> String name ; + } + + + + association [1] Student -> (roles) HiwiRole [*]; + + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd new file mode 100644 index 00000000..84d52cf2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/Reference.cd @@ -0,0 +1,17 @@ +package de.monticore.codeAdaption.evaluation.testcase_2_cd4code; +import java.lang.String; + +classdiagram Reference { + + class User { + String firstname; + String lastname; + Date birthday; + } + + class Role { + String name; + } + + association [1] User -> (roles)Role [*]; +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/builders/UserBuilder.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/builders/UserBuilder.java new file mode 100644 index 00000000..d2b169a5 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/builders/UserBuilder.java @@ -0,0 +1,49 @@ +package de.monticore.codeAdaption.evaluation.testcase_2_cd4code.Concrete; + +import de.monticore.codeAdaption.evaluation.reference.entity.Person; +import de.monticore.codeAdaption.utils.Adapt; + +import java.util.Date; + +public class UserBuilder { + private String lastname; + private String firstname; + + private Date birthday; + + public UserBuilder setFirstname(String firstname) { + this.firstname = firstname; + return this; + } + + public UserBuilder setLastname(String lastname) { + this.lastname = lastname; + return this; + } + + public UserBuilder setBirthday(Date birthday) { + this.birthday = birthday; + return this; + } + + public Date getBirthday() { + return birthday; + } + + public String getLastname() { + return lastname; + } + + public String getFirstname() { + return firstname; + } +@Adapt(ignore = true) + public User build() { + User user = new User(); + user.setLastname(lastname); + user.setFirstname(firstname); + user.setBirthday(birthday); + + return user; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java new file mode 100644 index 00000000..41eff3c6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/entity/User.java @@ -0,0 +1,15 @@ +package de.monticore.codeAdaption.evaluation.testcase_2_cd4code.Concrete; + +import de.monticore.codeAdaption.utils.Adapt; + +public class User extends UserTOP { + + @Adapt(ref = "Role", template = "print${}s") + public String printRoles() { + String roleNames = ""; + for (Role role : this.roles){ + roleNames = role.name + ", "; + } + return roleNames; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/repository/CRUDRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/repository/CRUDRepository.java new file mode 100644 index 00000000..849b34a6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/repository/CRUDRepository.java @@ -0,0 +1,6 @@ +package de.monticore.codeAdaption.evaluation.testcase_2_cd4code.Concrete; + +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(ignore = true) +public interface CRUDRepository {} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/repository/UserRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/repository/UserRepository.java new file mode 100644 index 00000000..a45469d4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/evaluation/testcase_2_cd4code/hwc/repository/UserRepository.java @@ -0,0 +1,17 @@ +package de.monticore.codeAdaption.evaluation.testcase_2_cd4code.Concrete; + +import de.monticore.codeAdaption.evaluation.reference.entity.User; + +import java.util.List; + +public interface UserRepository extends CRUDRepository { + User getUserByName(String name); + + void storeUser(User user); + + List getAllUser(); + + List getAllUserSortedByName(); + + void removeUser(); +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/EntityRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/EntityRepository.java new file mode 100644 index 00000000..853cd8b6 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/EntityRepository.java @@ -0,0 +1,61 @@ +package repository; + +import de.monticore.codeAdaption.utils.Adapt; + +import java.util.*; +import model.reference.hwc.Application.user.Entity; + +@Adapt( + ref = {"Entity"}, + template = "${}Repository") +public class EntityRepository extends Repository { + @Adapt( + ref = {"Entity"}, + template = "${uncap_first}Set") + private Set entitySet = new HashSet<>(); + + @Adapt( + ref = {"Entity", "Entity.id"}, + template = "find${}By${cap_first}") + public Optional findEntityById(String id) { + int i = 0; + for (Entity element : getAllEntity()) { + if (element.getId().compareTo(id) == 0) { + return Optional.of(element); + } + } + return Optional.empty(); + } + + @Adapt( + ref = {"Entity"}, + template = "getAll${}") + public Set getAllEntity() { + return entitySet; + } + + @Adapt( + ref = {"Entity", "Entity.id"}, + template = "getAll${}SortedBy${cap_first}") + public List getAllEntitySortedById() { + + @Adapt( + ref = {"Entity"}, + template = "${uncap_first}List") + List entityList = new ArrayList<>(getAllEntity()); + + Comparator comparator = Comparator.comparing(Entity::getId); + + entityList.sort(comparator); + + return entityList; + } + + public void store( + @Adapt( + ref = {"Entity"}, + template = "${uncap_first}") + Entity entity) { + entitySet.add(entity); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/annotMatcher/EntityRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/annotMatcher/EntityRepository.java new file mode 100644 index 00000000..4250ba5d --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/annotMatcher/EntityRepository.java @@ -0,0 +1,57 @@ +package de.monticore.codeAdaption.matcher.annotMatcher; + +import de.monticore.codeAdaption.utils.Adapt; + +import java.util.*; +import model.reference.hwc.Application.user.Entity; + +@Adapt( + ref = {"Entity"}, + template = "${}Repository") +public class EntityRepository extends Repository { + @Adapt( + ref = {"Entity"}, + template = "${uncap_first}Set") + private Set entitySet = new HashSet<>(); + + @Adapt( + ref = {"Entity", "Entity.id"}, + template = "find${}By${cap_first}") + public Optional findEntityById(String id) { + int i = 0; + for (Entity element : getAllEntity()) { + if (element.getId().compareTo(id) == 0) { + return Optional.of(element); + } + } + return Optional.empty(); + } + + @Adapt( + ref = {"Entity"}, + template = "getAll${}") + public Set getAllEntity() { + return entitySet; + } + + @Adapt( + ref = {"Entity", "Entity.id"}, + template = "getAll${}SortedBy${cap_first}") + public List getAllEntitySortedById() { + + @Adapt( + ref = {"Entity"}, + template = "${uncap_first}List") + List entityList = new ArrayList<>(getAllEntity()); + + Comparator comparator = Comparator.comparing(Entity::getId); + + entityList.sort(comparator); + + return entityList; + } + + public void store(@Adapt(ref = {"Entity"}, template = "${uncap_first}") Entity entity) { + entitySet.add(entity); + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/infixMatcher/EntityRepository.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/infixMatcher/EntityRepository.java new file mode 100644 index 00000000..9a1340d2 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/infixMatcher/EntityRepository.java @@ -0,0 +1,30 @@ +package de.monticore.codeAdaption.matcher.annotMatcher; + +import java.util.*; +import model.reference.hwc.Application.user.Entity; + +import javax.swing.text.html.parser.Entity; + + +public class EntityRepository extends Repository { + + private Set entitySet = new HashSet<>(); + + + public Optional findEntityById(String id) { + return Optional.empty(); + } + + public Set getAllEntity() { + return entitySet; + } + + public List getAllEntitySortedById() { + List entityList = new ArrayList<>(getAllEntity()); + } + + public void storeEntity(Entity entity){ + + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/nameMatcher/Entity.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/nameMatcher/Entity.java new file mode 100644 index 00000000..f3c5467b --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/matcher/nameMatcher/Entity.java @@ -0,0 +1,16 @@ +package nameMatcher; + +public class Entity { + + String id; + + public String getId() { + return id; + } + + + public void setId(String id) { + this.id = id; + } + +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/utils/ElementCollection.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/utils/ElementCollection.java new file mode 100644 index 00000000..7e1a092c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/utils/ElementCollection.java @@ -0,0 +1,14 @@ +package model.reference.hwc.Application.repository; + +import java.util.Optional; + +public class ElementCollection { + + int someAttribut; + int anotherAttribut; + + public Optional doSomthing(int param1, int param2) { + int localVar1; + int localVar2; + } +} diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd new file mode 100644 index 00000000..5ebb7a38 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/Validator.cd @@ -0,0 +1,5 @@ +classdiagram Validator{ +public class Entity { + String id ; +} +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidReference.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidReference.java new file mode 100644 index 00000000..d8ecaa5c --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidReference.java @@ -0,0 +1,5 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(template = "${}",ref = "Invalid") +public class InvalidReference { +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidTemplate.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidTemplate.java new file mode 100644 index 00000000..b3ab1061 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/InvalidTemplate.java @@ -0,0 +1,13 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(template = "${}",ref = "Entity") +public class InvalidTemplate { + @Adapt(template = "${}",ref = "Entity") + public String someAttribut ; + + @Adapt(template = "${}",ref = "Entity") + public void someMethod(@Adapt(template = "${}",ref = "Entity")String args) { + @Adapt(template = "${}",ref = "Entity") + String someLocalvar ; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/ManyVarInOneFieldDecl.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/ManyVarInOneFieldDecl.java new file mode 100644 index 00000000..1a75ae92 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/ManyVarInOneFieldDecl.java @@ -0,0 +1,3 @@ +public class ManyVarInOneFiieldDecl { + private String a ,b ; +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/ManyVarInOneLocalVarDecl.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/ManyVarInOneLocalVarDecl.java new file mode 100644 index 00000000..dfbeefd4 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/ManyVarInOneLocalVarDecl.java @@ -0,0 +1,10 @@ + + +import java.lang.String; + +public class ManyVarInOneLocalVarDecl { + public static void main(String [] args) { + int a ,b; + String [] s; + } +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/MissingTemplate.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/MissingTemplate.java new file mode 100644 index 00000000..213a12e7 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/MissingTemplate.java @@ -0,0 +1,5 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt() +public class NoTemplate { +} \ No newline at end of file diff --git a/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/MissingTemplateArgument.java b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/MissingTemplateArgument.java new file mode 100644 index 00000000..06a18ce9 --- /dev/null +++ b/ref-code-adaptation/src/test/resources/de/monticore/codeAdaption/validator/invalid/MissingTemplateArgument.java @@ -0,0 +1,5 @@ +import de.monticore.codeAdaption.utils.Adapt; + +@Adapt(template = "${}" ) +public class TemplateArgument { +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 85158ca3..dcb42efe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,7 +15,16 @@ pluginManagement { } } +dependencyResolutionManagement { + versionCatalogs { + create("corpus") { + from(files("./gradle/corpus.versions.toml")) + } + } +} + rootProject.name = 'javaDSL' include(':javaDSL') -include(':javaDSL-emf') \ No newline at end of file +include(':javaDSL-emf') +include(':ref-code-adaptation') \ No newline at end of file