diff --git a/src/main/resources/automatalib-learnlib-checkstyle.xml b/config/build-tools-checkstyle.xml similarity index 98% rename from src/main/resources/automatalib-learnlib-checkstyle.xml rename to config/build-tools-checkstyle.xml index 6cc25e6..7a411eb 100644 --- a/src/main/resources/automatalib-learnlib-checkstyle.xml +++ b/config/build-tools-checkstyle.xml @@ -36,7 +36,7 @@ limitations under the License. - + diff --git a/src/main/resources/checkstyle-suppressions.xml b/config/checkstyle-suppressions.xml similarity index 100% rename from src/main/resources/checkstyle-suppressions.xml rename to config/checkstyle-suppressions.xml diff --git a/src/main/resources/license-header-java.txt b/config/license-header-java.txt similarity index 100% rename from src/main/resources/license-header-java.txt rename to config/license-header-java.txt diff --git a/src/main/resources/pmd-ruleset.xml b/config/pmd-ruleset.xml similarity index 100% rename from src/main/resources/pmd-ruleset.xml rename to config/pmd-ruleset.xml diff --git a/pom.xml b/pom.xml index f8f4fdc..14c2b9b 100644 --- a/pom.xml +++ b/pom.xml @@ -98,23 +98,16 @@ limitations under the License. 1.2.0 - 0.0.2 1.12-4 9.3 0.21.0 1.7.0 1.13.0 - 1.8 7.5.1 + 1.1.3 - - com.github.misberner.ap-commons - ap-commons - ${ap-commons.version} - - com.squareup javapoet @@ -127,13 +120,6 @@ limitations under the License. ${brics.version} - - org.kohsuke.metainf-services - metainf-services - ${metainf-services.version} - provided - - com.google.testing.compile compile-testing @@ -141,6 +127,13 @@ limitations under the License. test + + com.google.truth + truth + ${truth.version} + test + + org.testng testng @@ -175,6 +168,12 @@ limitations under the License. maven-compiler-plugin ${compiler-plugin.version} + + default-compile + + none + + default-testCompile @@ -279,9 +278,9 @@ limitations under the License. maven-checkstyle-plugin ${checkstyle-plugin.version} - ${project.resources[0].directory}/automatalib-learnlib-checkstyle.xml - ${project.resources[0].directory}/license-header-java.txt - ${project.resources[0].directory}/checkstyle-suppressions.xml + ${project.basedir}/config/build-tools-checkstyle.xml + ${project.basedir}/config/license-header-java.txt + ${project.basedir}/config/checkstyle-suppressions.xml true false @@ -295,7 +294,7 @@ limitations under the License. true false - ${project.resources[0].directory}/pmd-ruleset.xml + ${project.basedir}/config/pmd-ruleset.xml target/generated-sources @@ -511,29 +510,5 @@ limitations under the License. - - compile-testing-compatibility - - [9,) - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - @{argLine} - --add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED - --add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED - --add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED - - - - - - - diff --git a/src/main/java/de/learnlib/tooling/annotation/Generated.java b/src/main/java/de/learnlib/tooling/annotation/Generated.java index bef2001..065bcdd 100644 --- a/src/main/java/de/learnlib/tooling/annotation/Generated.java +++ b/src/main/java/de/learnlib/tooling/annotation/Generated.java @@ -29,18 +29,16 @@ public @interface Generated { /** - * The generator element MUST have the name of the code generator. The name is the fully qualified name of the code - * generator. + * The the fully qualified name of the code generator. * - * @return The name of the code generator + * @return The the fully qualified name of the code generator */ String[] generator(); /** - * The source element MUST have the name of the source. The name is the fully qualified name of the annotated - * class. + * The fully qualified name of the annotated class. * - * @return The name of the annotated class + * @return The fully qualified name of the annotated class */ String source(); } diff --git a/src/main/java/de/learnlib/tooling/annotation/refinement/GenerateRefinement.java b/src/main/java/de/learnlib/tooling/annotation/refinement/GenerateRefinement.java index a9d57ca..07b2cd3 100644 --- a/src/main/java/de/learnlib/tooling/annotation/refinement/GenerateRefinement.java +++ b/src/main/java/de/learnlib/tooling/annotation/refinement/GenerateRefinement.java @@ -55,7 +55,7 @@ * * @return a mapping of specializations of parameter types for the refinement's constructor parameters */ - Map[] parameterMapping() default {}; + Mapping[] typeMapping() default {}; /** * An array of additional interfaces the refinement should implement. diff --git a/src/main/java/de/learnlib/tooling/annotation/refinement/Generic.java b/src/main/java/de/learnlib/tooling/annotation/refinement/Generic.java index 5939a03..5ca2982 100644 --- a/src/main/java/de/learnlib/tooling/annotation/refinement/Generic.java +++ b/src/main/java/de/learnlib/tooling/annotation/refinement/Generic.java @@ -26,7 +26,8 @@ public @interface Generic { /** - * A literal representation of a type parameter (e.g. defined in {@link GenerateRefinement#generics()}). + * A literal representation of a type parameter (e.g. defined in {@link GenerateRefinement#generics()}). A non-empty + * value has a higher precedence over any {@link #clazz()} parameter. * * @return a literal representation of a type parameter */ @@ -40,7 +41,7 @@ Class clazz() default Void.class; /** - * Potential nested type parameters of the referenced (cf. {@link #clazz()}) referential type parameter. + * Potential nested type parameters of the referenced {@link #clazz() referential} type parameter. * * @return potential nested type parameters of the referenced referential type parameter */ diff --git a/src/main/java/de/learnlib/tooling/annotation/refinement/Interface.java b/src/main/java/de/learnlib/tooling/annotation/refinement/Interface.java index dde6f58..f22fa7a 100644 --- a/src/main/java/de/learnlib/tooling/annotation/refinement/Interface.java +++ b/src/main/java/de/learnlib/tooling/annotation/refinement/Interface.java @@ -37,6 +37,6 @@ * * @return potential nested type parameters of the referenced interface */ - String[] generics() default {}; + Generic[] generics() default {}; } diff --git a/src/main/java/de/learnlib/tooling/annotation/refinement/Map.java b/src/main/java/de/learnlib/tooling/annotation/refinement/Mapping.java similarity index 72% rename from src/main/java/de/learnlib/tooling/annotation/refinement/Map.java rename to src/main/java/de/learnlib/tooling/annotation/refinement/Mapping.java index cc429e6..c138ce9 100644 --- a/src/main/java/de/learnlib/tooling/annotation/refinement/Map.java +++ b/src/main/java/de/learnlib/tooling/annotation/refinement/Mapping.java @@ -23,7 +23,7 @@ */ @Retention(RetentionPolicy.SOURCE) @Target({}) -public @interface Map { +public @interface Mapping { /** * The type of input parameter that if matched (equality) should be replaced. @@ -40,19 +40,10 @@ Class to(); /** - * Potential nested type parameters of the replacement (cf. {@link #to()}) type. If the replacement type has inner - * type variables use {@link #withComplexGenerics()}. + * Potential nested type parameters of the {@link #to() replacement} type. * * @return potential nested type parameters of the replacement type */ - String[] withGenerics() default {}; - - /** - * Potential nested type parameters of the replacement (cf. {@link #to()}) type that may contain inner type - * variables themselves. - * - * @return potential nested type parameters of the replacement type - */ - Generic[] withComplexGenerics() default {}; + Generic[] generics() default {}; } diff --git a/src/main/java/de/learnlib/tooling/processor/AbstractLearnLibProcessor.java b/src/main/java/de/learnlib/tooling/processor/AbstractLearnLibProcessor.java index 4bdcbf6..54cbe62 100644 --- a/src/main/java/de/learnlib/tooling/processor/AbstractLearnLibProcessor.java +++ b/src/main/java/de/learnlib/tooling/processor/AbstractLearnLibProcessor.java @@ -14,12 +14,22 @@ */ package de.learnlib.tooling.processor; +import java.lang.annotation.Annotation; +import java.util.List; + import javax.annotation.processing.AbstractProcessor; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; -import javax.tools.Diagnostic.Kind; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ArrayTypeName; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; import de.learnlib.tooling.annotation.Generated; public abstract class AbstractLearnLibProcessor extends AbstractProcessor { @@ -29,15 +39,51 @@ public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } - public AnnotationSpec createAnnotation(Element annotatedClass) { + protected AnnotationSpec createAnnotation(Element annotatedClass) { return AnnotationSpec.builder(Generated.class) .addMember("generator", "$S", getClass().getCanonicalName()) .addMember("source", "$S", annotatedClass.toString()) .build(); } - public void error(String msg) { - super.processingEnv.getMessager().printMessage(Kind.ERROR, msg); + protected TypeElement validateClassKind(Element element, Class annotation) { + if (element.getKind() != ElementKind.CLASS) { + throw new IllegalArgumentException("Annotation " + annotation + " is only supported on classes"); + } + + return (TypeElement) element; } + protected String getPackageName(Element element, String defaultValue) { + if (defaultValue != null && !defaultValue.isEmpty()) { + return defaultValue; + } else { + return super.processingEnv.getElementUtils().getPackageOf(element).getQualifiedName().toString(); + } + } + + protected boolean requiresSafeVarargs(MethodSpec.Builder mBuilder) { + final List parameters = mBuilder.parameters; + + if (parameters.isEmpty()) { + return false; + } else { + final ParameterSpec last = parameters.get(parameters.size() - 1); + final TypeName type = last.type; + + return requiresSafeVarargs(type); + } + } + + private boolean requiresSafeVarargs(TypeName type) { + if (type instanceof ParameterizedTypeName) { + return true; + } else if (type instanceof TypeVariableName) { + return true; + } else if (type instanceof ArrayTypeName) { + return requiresSafeVarargs(((ArrayTypeName) type).componentType); + } else { + return false; + } + } } diff --git a/src/main/java/de/learnlib/tooling/processor/builder/BuilderProcessor.java b/src/main/java/de/learnlib/tooling/processor/builder/BuilderProcessor.java index a8cb275..8aadf3e 100644 --- a/src/main/java/de/learnlib/tooling/processor/builder/BuilderProcessor.java +++ b/src/main/java/de/learnlib/tooling/processor/builder/BuilderProcessor.java @@ -15,14 +15,12 @@ package de.learnlib.tooling.processor.builder; import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; -import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -30,14 +28,11 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.MirroredTypeException; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; -import com.github.misberner.apcommons.util.ElementUtils; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; @@ -50,9 +45,7 @@ import de.learnlib.tooling.annotation.builder.GenerateBuilder; import de.learnlib.tooling.annotation.builder.Option; import de.learnlib.tooling.processor.AbstractLearnLibProcessor; -import org.kohsuke.MetaInfServices; -@MetaInfServices(Processor.class) public class BuilderProcessor extends AbstractLearnLibProcessor { @Override @@ -69,7 +62,7 @@ public boolean process(Set annotations, RoundEnvironment final GenerateBuilder annotation = elem.getAnnotation(GenerateBuilder.class); final String name = getBuilderName(elem, annotation); - final String pkg = getPackageName(elem, annotation); + final String pkg = super.getPackageName(elem, annotation.packageName()); final String create = annotation.createName(); final Iterable modifiers = annotation.builderPublic() ? Collections.singleton(Modifier.PUBLIC) : Collections.emptyList(); @@ -101,13 +94,11 @@ public boolean process(Set annotations, RoundEnvironment .collect(Collectors.toList())); final List params = elem.getParameters(); - final List fieldNames = new ArrayList<>(params.size()); + final StringJoiner returnJoiner = new StringJoiner(", ", "return new $T(", ")"); for (int i = 0; i < params.size(); i++) { final VariableElement ve = params.get(i); final boolean isVarArgs = elem.isVarArgs() && i == params.size() - 1; - final boolean isSafeVarargs = - isVarArgs && ((ArrayType) ve.asType()).getComponentType().getKind() == TypeKind.TYPEVAR; final Option paramAnnotation = ve.getAnnotation(Option.class); final boolean isFieldSuppressed; final String fieldName; @@ -129,8 +120,8 @@ public boolean process(Set annotations, RoundEnvironment fieldName = ve.getSimpleName().toString(); } + returnJoiner.add(fieldName); final TypeName fieldTypeName = ClassName.get(ve.asType()); - fieldNames.add(fieldName); // attribute classBuilder.addField(FieldSpec.builder(fieldTypeName, fieldName, Modifier.PRIVATE).build()); @@ -171,7 +162,7 @@ public boolean process(Set annotations, RoundEnvironment .varargs(isVarArgs) .addParameter(fieldTypeName, fieldName) .addStatement("this.$N = $N", fieldName, fieldName); - if (isSafeVarargs) { + if (isVarArgs && super.requiresSafeVarargs(setterBuilder)) { setterBuilder.addModifiers(Modifier.FINAL).addAnnotation(SafeVarargs.class); } classBuilder.addMethod(setterBuilder.build()); @@ -191,7 +182,7 @@ public boolean process(Set annotations, RoundEnvironment .addParameter(fieldTypeName, fieldName) .addStatement("this.$N = $N", fieldName, fieldName) .addStatement("return this"); - if (isSafeVarargs) { + if (isVarArgs && super.requiresSafeVarargs(withBuilder)) { withBuilder.addModifiers(Modifier.FINAL).addAnnotation(SafeVarargs.class); } classBuilder.addMethod(withBuilder.build()); @@ -201,15 +192,13 @@ public boolean process(Set annotations, RoundEnvironment // create if (paramAnnotation != null && paramAnnotation.requiredOnCreation()) { createBuilder.varargs(isVarArgs).addParameter(fieldTypeName, fieldName); - if (isSafeVarargs) { + if (isVarArgs && super.requiresSafeVarargs(createBuilder)) { createBuilder.addModifiers(Modifier.FINAL).addAnnotation(SafeVarargs.class); } } } - final StringJoiner sj = new StringJoiner(", ", "return new $T(", ")"); - fieldNames.forEach(sj::add); - createBuilder.addStatement(CodeBlock.of(sj.toString(), ClassName.get(clazz.asType()))); + createBuilder.addStatement(returnJoiner.toString(), ClassName.get(clazz.asType())); classBuilder.addMethod(constructorBuilder.build()); classBuilder.addMethod(createBuilder.build()); @@ -220,7 +209,7 @@ public boolean process(Set annotations, RoundEnvironment .build() .writeTo(super.processingEnv.getFiler()); } catch (IOException ioe) { - super.error("Could not writer source: " + ioe.getMessage()); + throw new IllegalStateException(ioe); } } return true; @@ -253,16 +242,6 @@ private String getBuilderName(Element element, GenerateBuilder annotation) { } } - private String getPackageName(Element element, GenerateBuilder annotation) { - final String pkg = annotation.packageName(); - - if (pkg == null || pkg.isEmpty()) { - return ElementUtils.getPackageName(element); - } else { - return pkg; - } - } - private TypeElement getDefaultsValue(GenerateBuilder annotation) { try { annotation.defaults(); diff --git a/src/main/java/de/learnlib/tooling/processor/edsl/EDSLProcessor.java b/src/main/java/de/learnlib/tooling/processor/edsl/EDSLProcessor.java index 908dd2b..00b5a54 100644 --- a/src/main/java/de/learnlib/tooling/processor/edsl/EDSLProcessor.java +++ b/src/main/java/de/learnlib/tooling/processor/edsl/EDSLProcessor.java @@ -31,20 +31,16 @@ import java.util.stream.Collectors; import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; -import com.github.misberner.apcommons.util.ElementUtils; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; @@ -56,6 +52,7 @@ import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec.Builder; import com.squareup.javapoet.TypeVariableName; +import de.learnlib.tooling.annotation.builder.GenerateBuilder; import de.learnlib.tooling.annotation.edsl.Action; import de.learnlib.tooling.annotation.edsl.Expr; import de.learnlib.tooling.annotation.edsl.GenerateEDSL; @@ -63,9 +60,7 @@ import dk.brics.automaton.Automaton; import dk.brics.automaton.RegExp; import dk.brics.automaton.State; -import org.kohsuke.MetaInfServices; -@MetaInfServices(Processor.class) public class EDSLProcessor extends AbstractLearnLibProcessor { @Override @@ -85,13 +80,13 @@ public boolean process(Set annotations, RoundEnvironment for (Element e : roundEnv.getElementsAnnotatedWith(GenerateEDSL.class)) { - final TypeElement elem = (TypeElement) e; + final TypeElement elem = super.validateClassKind(e, GenerateBuilder.class); final GenerateEDSL annotation = elem.getAnnotation(GenerateEDSL.class); final String name = annotation.name(); - final String pkg = getPackageName(elem, annotation); + final String pkg = super.getPackageName(elem, annotation.packageName()); final Modifier[] modifiers = annotation.isPublic() ? new Modifier[] {Modifier.PUBLIC} : new Modifier[0]; - final String syntax = getExpandedSyntax(annotation); + final String syntax = getExpandedSyntax(elem, annotation); final List tokens = getTokens(syntax); final Map token2Label = new HashMap<>(); @@ -190,20 +185,14 @@ public boolean process(Set annotations, RoundEnvironment .collect(Collectors.toList())); final StringJoiner sj = new StringJoiner(", ", "$N.$N(", ")"); - VariableElement lastParameter = null; for (VariableElement p : m.getParameters()) { String pName = p.getSimpleName().toString(); methodBuilder.addParameter(ParameterSpec.builder(ParameterizedTypeName.get(p.asType()), pName).build()); sj.add(pName); - lastParameter = p; } - final boolean isSafeVarargs = lastParameter != null && m.isVarArgs() && - ((ArrayType) lastParameter.asType()).getComponentType() - .getKind() == - TypeKind.TYPEVAR; - if (isSafeVarargs) { + if (m.isVarArgs() && super.requiresSafeVarargs(methodBuilder)) { methodBuilder.addModifiers(Modifier.FINAL).addAnnotation(SafeVarargs.class); } @@ -241,13 +230,13 @@ public boolean process(Set annotations, RoundEnvironment .build() .writeTo(super.processingEnv.getFiler()); } catch (IOException ioe) { - super.error("Could not writer source: " + ioe.getMessage()); + throw new IllegalStateException(ioe); } } return true; } - private String getExpandedSyntax(GenerateEDSL annotation) { + private String getExpandedSyntax(TypeElement clazz, GenerateEDSL annotation) { String result = annotation.syntax(); @@ -259,8 +248,8 @@ private String getExpandedSyntax(GenerateEDSL annotation) { } if (result.contains("<") || result.contains(">")) { - throw new IllegalArgumentException( - '\'' + annotation.syntax() + "' contains expressions that could not be substituted"); + throw new IllegalArgumentException("Syntax '" + annotation.syntax() + "' in " + clazz + + " contains expressions that could not be substituted"); } return result; @@ -305,7 +294,7 @@ private Map> getDomainActionMap(TypeElement claz if (!result.keySet().containsAll(tokensAsSet)) { tokensAsSet.removeAll(result.keySet()); - throw new IllegalArgumentException("Could not find action for tokens: " + tokensAsSet); + throw new IllegalArgumentException("Could not find action for tokens: " + tokensAsSet + " in " + clazz); } return result; @@ -323,7 +312,7 @@ private List getAnnotatedConstructors(TypeElement clazz) { final List constructors = ElementFilter.constructorsIn(getAnnotatedElements(clazz)); if (constructors.isEmpty()) { - throw new IllegalArgumentException("Could not find annotated constructor"); + throw new IllegalArgumentException("Could not find annotated constructor while processing " + clazz); } return constructors; @@ -349,14 +338,4 @@ private TypeSpec.Builder createBuilder(Element element, GenerateEDSL generateEDS return builder; } - - private String getPackageName(Element element, GenerateEDSL annotation) { - final String pkg = annotation.packageName(); - - if (pkg == null || pkg.isEmpty()) { - return ElementUtils.getPackageName(element); - } else { - return pkg; - } - } } diff --git a/src/main/java/de/learnlib/tooling/processor/refinement/RefinementProcessor.java b/src/main/java/de/learnlib/tooling/processor/refinement/RefinementProcessor.java index f61111a..8b84d91 100644 --- a/src/main/java/de/learnlib/tooling/processor/refinement/RefinementProcessor.java +++ b/src/main/java/de/learnlib/tooling/processor/refinement/RefinementProcessor.java @@ -18,36 +18,32 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.StringJoiner; import java.util.function.Function; -import javax.annotation.processing.Processor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.MirroredTypeException; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.WildcardType; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Types; -import com.github.misberner.apcommons.util.ElementUtils; -import com.github.misberner.apcommons.util.annotations.AnnotationUtils; -import com.github.misberner.apcommons.util.methods.MethodUtils; -import com.github.misberner.apcommons.util.methods.ParameterInfo; -import com.github.misberner.apcommons.util.types.TypeUtils; import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; @@ -59,18 +55,24 @@ import de.learnlib.tooling.annotation.refinement.GenerateRefinements; import de.learnlib.tooling.annotation.refinement.Generic; import de.learnlib.tooling.annotation.refinement.Interface; -import de.learnlib.tooling.annotation.refinement.Map; +import de.learnlib.tooling.annotation.refinement.Mapping; import de.learnlib.tooling.processor.AbstractLearnLibProcessor; -import org.kohsuke.MetaInfServices; -@MetaInfServices(Processor.class) public class RefinementProcessor extends AbstractLearnLibProcessor { + private Types typeUtils; + @Override public Set getSupportedAnnotationTypes() { return new HashSet<>(Arrays.asList(GenerateRefinement.class.getName(), GenerateRefinements.class.getName())); } + @Override + public void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.typeUtils = super.processingEnv.getTypeUtils(); + } + @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { @@ -80,321 +82,236 @@ public boolean process(Set annotations, RoundEnvironment for (Element elem : elements) { - validateAnnotation(elem); + super.validateClassKind(elem, GenerateRefinement.class); - final GenerateRefinement[] refinements; - final GenerateRefinements generateRefinements = elem.getAnnotation(GenerateRefinements.class); - - if (generateRefinements != null) { - refinements = generateRefinements.value(); - } else { - refinements = new GenerateRefinement[] {elem.getAnnotation(GenerateRefinement.class)}; - } - - int idx = 0; - - for (GenerateRefinement annotation : refinements) { + for (GenerateRefinement annotation : elem.getAnnotationsByType(GenerateRefinement.class)) { final TypeElement annotatedClass = (TypeElement) elem; final TypeSpec.Builder builder = createClass(annotatedClass, annotation); - addGenerics(builder, annotation); - addSuperClass(builder, annotatedClass, annotation); + final Map typeVarMap = addSuperClass(builder, annotatedClass, annotation); + addInterfaces(builder, annotation); - addConstructors(builder, annotatedClass, annotation, idx); + addConstructors(builder, annotatedClass, annotation, typeVarMap); try { - JavaFile.builder(ElementUtils.getPackageName(elem), builder.build()) + JavaFile.builder(super.getPackageName(elem, ""), builder.build()) .indent(" ") .build() .writeTo(super.processingEnv.getFiler()); } catch (IOException e) { - super.error("Could not writer source: " + e.getMessage()); + throw new IllegalStateException(e); } - - idx++; } } return true; } - private void validateAnnotation(Element element) { - if (element.getKind() != ElementKind.CLASS) { - super.error("Annotation " + GenerateRefinement.class + " is only supported on class level"); - throw new IllegalArgumentException(); - } - } - private TypeSpec.Builder createClass(TypeElement annotatedClass, GenerateRefinement annotation) { - return TypeSpec.classBuilder(annotation.name()) - .addModifiers(Modifier.PUBLIC) - .addJavadoc("This is an auto-generated refinement. See the {@link $T original class}.\n", - super.processingEnv.getTypeUtils().erasure(annotatedClass.asType())) - .addAnnotation(super.createAnnotation(annotatedClass)); - } + final TypeSpec.Builder builder = TypeSpec.classBuilder(annotation.name()) + .addModifiers(Modifier.PUBLIC) + .addJavadoc("This is an auto-generated refinement of {@link $T}.", + this.typeUtils.erasure(annotatedClass.asType())) + .addAnnotation(super.createAnnotation(annotatedClass)); - private void addGenerics(TypeSpec.Builder builder, GenerateRefinement annotation) { for (String typeParameter : annotation.generics()) { builder.addTypeVariable(TypeVariableName.get(typeParameter)); } + + return builder; } - private void addSuperClass(TypeSpec.Builder builder, TypeElement annotatedClass, GenerateRefinement annotation) { + private Map addSuperClass(TypeSpec.Builder builder, + TypeElement annotatedClass, + GenerateRefinement annotation) { + final List typeParameters = annotatedClass.getTypeParameters(); + final Generic[] generics = annotation.parentGenerics(); + final Map typeMap; - final Generic[] pgens = annotation.parentGenerics(); + assert typeParameters.size() == generics.length; - if (pgens.length > 0) { - final List generics = new ArrayList<>(pgens.length); - for (Generic generic : pgens) { - generics.add(extractGeneric(generic)); - } - builder.superclass(ParameterizedTypeName.get(ClassName.get(annotatedClass), - generics.toArray(new TypeName[0]))); + if (typeParameters.isEmpty()) { + typeMap = Collections.emptyMap(); } else { - builder.superclass(ClassName.get(annotatedClass)); + typeMap = new HashMap<>(); + for (int i = 0; i < typeParameters.size(); i++) { + typeMap.put(typeParameters.get(i).toString(), generics[i]); + } } + builder.superclass(toTypeName(annotatedClass.asType(), generics)); + return typeMap; } private void addInterfaces(TypeSpec.Builder builder, GenerateRefinement annotation) { for (Interface inter : annotation.interfaces()) { + final TypeMirror clazz = getClassValue(inter, Interface::clazz); + final Generic[] generics = inter.generics(); - final TypeName typeName = extractClass(inter, Interface::clazz); - - if (!(typeName instanceof ClassName)) { - throw new IllegalArgumentException("type '" + typeName + "' is not allowed as interface"); - } - - final ClassName className = (ClassName) typeName; - - final List generics = new ArrayList<>(annotation.interfaces().length); - for (String generic : inter.generics()) { - generics.add(TypeVariableName.get(generic)); - } - - builder.addSuperinterface(ParameterizedTypeName.get(className, generics.toArray(new TypeName[0]))); + builder.addSuperinterface(toTypeName(clazz, generics)); } } private void addConstructors(TypeSpec.Builder builder, TypeElement annotatedClass, GenerateRefinement annotation, - int idx) { + Map typeVarMap) { - final AnnotationMirror mirror; - final AnnotationMirror generateRefinementsMirror = - AnnotationUtils.findAnnotationMirror(annotatedClass, GenerateRefinements.class); - - if (generateRefinementsMirror != null) { - final List values = - find(generateRefinementsMirror, "value", Collections.emptyList()); - mirror = (AnnotationMirror) values.get(idx).getValue(); - } else { - mirror = AnnotationUtils.findAnnotationMirror(annotatedClass, GenerateRefinement.class); - } + final Mapping[] typeMapping = annotation.typeMapping(); - final List parameterMapping = - find(mirror, "parameterMapping", Collections.emptyList()); - - for (ExecutableElement constructor : TypeUtils.getConstructors(annotatedClass)) { + for (ExecutableElement constructor : ElementFilter.constructorsIn(annotatedClass.getEnclosedElements())) { + final TypeName classType = ClassName.get(this.typeUtils.erasure(annotatedClass.asType())); final MethodSpec.Builder mBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC); - - final StringJoiner javadocJoiner = new StringJoiner(", ", - "This is an auto-generated constructor. See the {@link $T#$T(", - ") original constructor}.\n"); - - final int numOfConstructorParams = constructor.getParameters().size(); - final List parameterNames = new ArrayList<>(numOfConstructorParams); - final List javadocTypes = new ArrayList<>(numOfConstructorParams + 2); - - // references to # - javadocTypes.add(super.processingEnv.getTypeUtils().erasure(annotatedClass.asType())); - javadocTypes.add(super.processingEnv.getTypeUtils().erasure(annotatedClass.asType())); - - for (ParameterInfo info : MethodUtils.getParameterInfos(constructor)) { - javadocJoiner.add("$T"); - javadocTypes.add(super.processingEnv.getTypeUtils().erasure(info.getType())); - parameterNames.add(info.getName()); - - if (info.isVarArgs()) { - mBuilder.varargs(true); - mBuilder.addAnnotation(SafeVarargs.class); - } - - final TypeName typeName = buildTypeName(annotation, info.getType(), parameterMapping, info.isVarArgs()); - - mBuilder.addParameter(typeName, info.getName()); + final StringJoiner superJoiner = new StringJoiner(", ", "super(", ")"); + final StringJoiner docJoiner = + new StringJoiner(", ", "This is an auto-generated constructor calling {@link $T#$T(", ")}."); + + final List arguments = new ArrayList<>(constructor.getParameters().size() + 2); + arguments.add(classType); + arguments.add(classType); + + for (VariableElement p : constructor.getParameters()) { + final String name = p.getSimpleName().toString(); + final TypeName typeName = mapTypeName(p.asType(), typeMapping, typeVarMap); + + mBuilder.addParameter(typeName, name); + superJoiner.add(name); + docJoiner.add("$T"); + arguments.add(ClassName.get(this.typeUtils.erasure(p.asType()))); } - final StringJoiner sj = new StringJoiner(", ", "super(", ")"); - parameterNames.forEach(sj::add); + mBuilder.varargs(constructor.isVarArgs()); + if (constructor.isVarArgs() && super.requiresSafeVarargs(mBuilder)) { + mBuilder.addAnnotation(SafeVarargs.class); + } - mBuilder.addStatement(CodeBlock.of(sj.toString(), parameterNames.toArray())); - mBuilder.addJavadoc(javadocJoiner.toString(), javadocTypes.toArray()); + mBuilder.addJavadoc(docJoiner.toString(), arguments.toArray()); + mBuilder.addStatement(superJoiner.toString()); builder.addMethod(mBuilder.build()); } } - private TypeName buildTypeName(GenerateRefinement annotation, - TypeMirror typeMirror, - List parameterMapping, - boolean isVarArgs) { - - final TypeMirror typeToCompare; + private TypeName mapTypeName(TypeMirror typeMirror, Mapping[] typeMapping, Map typeVarMap) { + + switch (typeMirror.getKind()) { + case ARRAY: + final ArrayType arrayMirror = (ArrayType) typeMirror; + final TypeName innerTypeName = mapTypeName(arrayMirror.getComponentType(), typeMapping, typeVarMap); + return ArrayTypeName.of(innerTypeName); + case WILDCARD: + final WildcardType wildcardMirror = (WildcardType) typeMirror; + final TypeMirror extendsBound = wildcardMirror.getExtendsBound(); + if (extendsBound != null) { + return WildcardTypeName.subtypeOf(mapTypeName(extendsBound, typeMapping, typeVarMap)); + } + final TypeMirror superBound = wildcardMirror.getSuperBound(); + if (superBound != null) { + return WildcardTypeName.supertypeOf(mapTypeName(superBound, typeMapping, typeVarMap)); + } + return WildcardTypeName.get(wildcardMirror); + case TYPEVAR: + final Generic generic = typeVarMap.get(typeMirror.toString()); - if (isVarArgs && typeMirror.getKind() == TypeKind.ARRAY) { - typeToCompare = ((ArrayType) typeMirror).getComponentType(); - } else { - typeToCompare = typeMirror; - } + // a dynamic method type variable, not present in the class definition + if (generic == null) { + throw new IllegalArgumentException("Cannot handle dynamic type variable " + typeMirror); + } - ClassName replacementClass = null; - int i = 0; - boolean isArray = false; - for (AnnotationValue parameter : parameterMapping) { - AnnotationMirror parameterMirror = (AnnotationMirror) parameter.getValue(); - TypeMirror fromAttribute = find(parameterMirror, "from", null); - if (super.processingEnv.getTypeUtils() - .isSameType(super.processingEnv.getTypeUtils().erasure(typeToCompare), - fromAttribute)) { - final TypeMirror toAttribute = find(parameterMirror, "to", null); - - if (toAttribute instanceof DeclaredType) { - replacementClass = - ClassName.get(super.processingEnv.getElementUtils().getTypeElement(toAttribute.toString())); - } else if (toAttribute instanceof ArrayType) { - isArray = true; - replacementClass = ClassName.get(super.processingEnv.getElementUtils() - .getTypeElement(((ArrayType) toAttribute).getComponentType() - .toString())); + final String value = generic.value(); + if (value != null && !value.isEmpty()) { + return TypeVariableName.get(value); } else { - throw new IllegalArgumentException("Cannot handle '" + toAttribute + '\''); + return toTypeName(getClassValue(generic, Generic::clazz), toTypeVariableNames(generic.generics())); + } + case DECLARED: + for (Mapping mapping : typeMapping) { + final TypeMirror from = getClassValue(mapping, Mapping::from); + if (this.typeUtils.isSameType(this.typeUtils.erasure(typeMirror), from)) { + final TypeMirror to = getClassValue(mapping, Mapping::to); + final Generic[] generics = mapping.generics(); + return toTypeName(to, generics); + } } - break; - } - i++; - } - - if (replacementClass != null) { - final Map[] parametersAnn = annotation.parameterMapping(); - final boolean isWildcard = typeMirror.getKind() == TypeKind.WILDCARD; - final Map map = parametersAnn[i]; - final String[] gens = map.withGenerics(); - final Generic[] cgens = map.withComplexGenerics(); - - final List generics = new ArrayList<>(gens.length + cgens.length); - - for (String generic : gens) { - generics.add(TypeVariableName.get(generic)); - } - for (Generic generic : cgens) { - generics.add(extractGeneric(generic)); - } - - final TypeName parameterizedTypeName; - - if (!generics.isEmpty()) { - parameterizedTypeName = ParameterizedTypeName.get(replacementClass, generics.toArray(new TypeName[0])); - } else { - parameterizedTypeName = replacementClass; - } - - final TypeName typeName; + final DeclaredType declaredMirror = (DeclaredType) typeMirror; + final ClassName typeName = ClassName.get((TypeElement) declaredMirror.asElement()); + final List typeArguments = declaredMirror.getTypeArguments(); - if (isWildcard) { - if (((WildcardType) typeMirror).getExtendsBound() != null) { - typeName = WildcardTypeName.subtypeOf(parameterizedTypeName); + if (typeArguments.isEmpty()) { + return typeName; } else { - typeName = WildcardTypeName.supertypeOf(parameterizedTypeName); + final TypeName[] generics = new TypeName[typeArguments.size()]; + for (int i = 0; i < typeArguments.size(); i++) { + generics[i] = mapTypeName(typeArguments.get(i), typeMapping, typeVarMap); + } + return ParameterizedTypeName.get(typeName, generics); } - } else { - typeName = parameterizedTypeName; - } - - if (isArray || isVarArgs) { - return ArrayTypeName.of(typeName); - } - - return typeName; - } else { // no replacement + default: + return ClassName.get(typeMirror); + } + } - if (typeMirror.getKind() == TypeKind.DECLARED) { - final DeclaredType declaredType = (DeclaredType) typeMirror; + private TypeName toTypeName(TypeMirror typeMirror, TypeName[] generics) { - if (declaredType.getTypeArguments().isEmpty()) { - return TypeName.get(typeMirror); - } + final ClassName className = ClassName.get((TypeElement) this.typeUtils.asElement(typeMirror)); - final List genericTypeNames = new ArrayList<>(declaredType.getTypeArguments().size()); + if (generics.length > 0) { + return ParameterizedTypeName.get(className, generics); + } else { + return className; + } + } - for (TypeMirror t : declaredType.getTypeArguments()) { - genericTypeNames.add(buildTypeName(annotation, t, parameterMapping, false)); - } + private TypeName toTypeName(TypeMirror typeMirror, Generic[] generics) { - return ParameterizedTypeName.get(ClassName.get(this.processingEnv.getElementUtils() - .getTypeElement(declaredType.asElement() - .toString())), - genericTypeNames.toArray(new TypeName[0])); + if (generics.length > 0) { + final TypeName[] typeNames = new TypeName[generics.length]; + for (int i = 0; i < generics.length; i++) { + typeNames[i] = extractGeneric(generics[i]); } - return TypeName.get(typeMirror); + return toTypeName(typeMirror, typeNames); + } else { + return ClassName.get(typeMirror); } } private TypeName extractGeneric(Generic annotation) { - final TypeName typeName = extractClass(annotation, Generic::clazz); + final String value = annotation.value(); - if (!ClassName.get(Void.class).equals(typeName)) { // no default value - - if (annotation.generics().length > 0) { - if (!(typeName instanceof ClassName)) { - throw new IllegalArgumentException("Arrays are not allowed to have generics"); - } - - final ClassName className = (ClassName) typeName; - final List genericModels = new ArrayList<>(annotation.generics().length); - - for (String generic : annotation.generics()) { - genericModels.add(TypeVariableName.get(generic)); - } + if (!value.isEmpty()) { + return TypeVariableName.get(value); + } else { + final TypeMirror typeMirror = getClassValue(annotation, Generic::clazz); + final String[] generics = annotation.generics(); - return ParameterizedTypeName.get(className, genericModels.toArray(new TypeName[0])); + if (generics.length > 0) { + final TypeName[] typeNames = toTypeVariableNames(generics); + return toTypeName(typeMirror, typeNames); + } else { + return ClassName.get(typeMirror); } + } + } - return typeName; - } else if (!annotation.value().isEmpty()) { - return TypeVariableName.get(annotation.value()); - } else { - throw new IllegalArgumentException(); + private TypeName[] toTypeVariableNames(String[] generics) { + final TypeName[] typeNames = new TypeName[generics.length]; + for (int i = 0; i < generics.length; i++) { + typeNames[i] = TypeVariableName.get(generics[i]); } + + return typeNames; } - private TypeName extractClass(T obj, Function> extractor) { + private TypeMirror getClassValue(T obj, Function> extractor) { try { - final Class clazz = extractor.apply(obj); - return ClassName.get(clazz); + extractor.apply(obj); + throw new IllegalStateException("Expected MirroredTypeException"); } catch (MirroredTypeException mte) { - final TypeMirror typeMirror = mte.getTypeMirror(); - if (typeMirror instanceof DeclaredType) { - DeclaredType classTypeMirror = (DeclaredType) typeMirror; - TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement(); - return ClassName.get(classTypeElement); - } else if (typeMirror instanceof ArrayType) { - ArrayType arrayTypeMirror = (ArrayType) typeMirror; - return ArrayTypeName.get(arrayTypeMirror); - } else { - throw mte; - } + return mte.getTypeMirror(); } } - @SuppressWarnings("unchecked") - private T find(AnnotationMirror mirror, String name, T defaultValue) { - final AnnotationValue av = AnnotationUtils.findAnnotationValue(mirror, name); - return av == null ? defaultValue : (T) av.getValue(); - } - } diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000..d8424f6 --- /dev/null +++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,3 @@ +de.learnlib.tooling.processor.builder.BuilderProcessor +de.learnlib.tooling.processor.edsl.EDSLProcessor +de.learnlib.tooling.processor.refinement.RefinementProcessor diff --git a/src/test/java/de/learnlib/tooling/it/builder/GenericBuilderITResult.java b/src/test/java/de/learnlib/tooling/it/builder/GenericBuilderITResult.java index 72792be..9f098b0 100644 --- a/src/test/java/de/learnlib/tooling/it/builder/GenericBuilderITResult.java +++ b/src/test/java/de/learnlib/tooling/it/builder/GenericBuilderITResult.java @@ -83,4 +83,4 @@ public final GenericBuilderITResult withD(O... d) { public final GenericBuilderIT create(O... d) throws Exception { return new GenericBuilderIT(a, b, c, d); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/builder/RenamedBuilderITResult.java b/src/test/java/de/learnlib/tooling/it/builder/RenamedBuilderITResult.java index 2358fbf..dd4ca44 100644 --- a/src/test/java/de/learnlib/tooling/it/builder/RenamedBuilderITResult.java +++ b/src/test/java/de/learnlib/tooling/it/builder/RenamedBuilderITResult.java @@ -79,4 +79,4 @@ public RenamedBuilderITResult withoutDD(Object[] d) { public RenamingBuilderIT create() { return new RenamingBuilderIT(param1, b, c, d); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/builder/SimpleBuilderITBuilder.java b/src/test/java/de/learnlib/tooling/it/builder/SimpleBuilderITBuilder.java index b1ec979..a8ae8f1 100644 --- a/src/test/java/de/learnlib/tooling/it/builder/SimpleBuilderITBuilder.java +++ b/src/test/java/de/learnlib/tooling/it/builder/SimpleBuilderITBuilder.java @@ -78,4 +78,4 @@ public SimpleBuilderITBuilder withD(boolean... d) { public SimpleBuilderIT create() { return new SimpleBuilderIT(a, b, c, d); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/edsl/DefaultEDSLITResult.java b/src/test/java/de/learnlib/tooling/it/edsl/DefaultEDSLITResult.java index 3e80eac..98c18b3 100644 --- a/src/test/java/de/learnlib/tooling/it/edsl/DefaultEDSLITResult.java +++ b/src/test/java/de/learnlib/tooling/it/edsl/DefaultEDSLITResult.java @@ -1,4 +1,3 @@ - package de.learnlib.tooling.it.edsl; import de.learnlib.tooling.annotation.Generated; @@ -96,7 +95,7 @@ private DefaultEDSLITResult2() { } public DefaultEDSLITResult withStateProperty(SP stateProperty, - Object stateId) { + Object stateId) { delegate.withStateProperty(stateProperty, stateId); return getDefaultEDSLITResult(); } @@ -141,4 +140,4 @@ public final DefaultEDSLITResult2 on(I firstInput, I... otherInputs) { return getDefaultEDSLITResult2(); } } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/edsl/ExtendingEDSLITResult.java b/src/test/java/de/learnlib/tooling/it/edsl/ExtendingEDSLITResult.java index c7f3df7..aec1ea8 100644 --- a/src/test/java/de/learnlib/tooling/it/edsl/ExtendingEDSLITResult.java +++ b/src/test/java/de/learnlib/tooling/it/edsl/ExtendingEDSLITResult.java @@ -1,4 +1,3 @@ - package de.learnlib.tooling.it.edsl; import de.learnlib.tooling.annotation.Generated; @@ -278,4 +277,4 @@ public final ExtendingEDSLITResult5 on(I firstInput, I... otherInputs) { return getExtendingEDSLITResult5(); } } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/edsl/OverlappingEDSLITResult.java b/src/test/java/de/learnlib/tooling/it/edsl/OverlappingEDSLITResult.java index 27123f9..59653b1 100644 --- a/src/test/java/de/learnlib/tooling/it/edsl/OverlappingEDSLITResult.java +++ b/src/test/java/de/learnlib/tooling/it/edsl/OverlappingEDSLITResult.java @@ -1,4 +1,3 @@ - package de.learnlib.tooling.it.edsl; import de.learnlib.tooling.annotation.Generated; @@ -101,4 +100,4 @@ public OverlappingEDSLITResult0 aaa() { return getOverlappingEDSLITResult0(); } } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/refinement/GenericRefinementIT.java b/src/test/java/de/learnlib/tooling/it/refinement/GenericRefinementIT.java new file mode 100644 index 0000000..4dd9a76 --- /dev/null +++ b/src/test/java/de/learnlib/tooling/it/refinement/GenericRefinementIT.java @@ -0,0 +1,35 @@ +/* Copyright (C) 2023 TU Dortmund University + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.tooling.it.refinement; + +import java.util.Collection; + +import de.learnlib.tooling.annotation.refinement.GenerateRefinement; +import de.learnlib.tooling.annotation.refinement.Generic; +import de.learnlib.tooling.annotation.refinement.Mapping; + +@GenerateRefinement(name = "GenericRefinementITResult", + parentGenerics = {@Generic(clazz = String.class), @Generic(clazz = Boolean.class)}, + typeMapping = @Mapping(from = SuperInterface.class, + to = SubInterface.class, + generics = @Generic(clazz = String.class))) +public class GenericRefinementIT { + + public GenericRefinementIT(O a, SuperInterface... b) {} + + @SafeVarargs + public GenericRefinementIT(Collection> a, I... b) {} + +} diff --git a/src/test/java/de/learnlib/tooling/it/refinement/GenericRefinementITResult.java b/src/test/java/de/learnlib/tooling/it/refinement/GenericRefinementITResult.java new file mode 100644 index 0000000..1a23fe0 --- /dev/null +++ b/src/test/java/de/learnlib/tooling/it/refinement/GenericRefinementITResult.java @@ -0,0 +1,31 @@ +package de.learnlib.tooling.it.refinement; + +import de.learnlib.tooling.annotation.Generated; +import java.lang.Boolean; +import java.lang.SafeVarargs; +import java.lang.String; +import java.util.Collection; + +/** + * This is an auto-generated refinement of {@link GenericRefinementIT}. + */ +@Generated( + generator = "de.learnlib.tooling.processor.refinement.RefinementProcessor", + source = "de.learnlib.tooling.it.refinement.GenericRefinementIT" +) +public class GenericRefinementITResult extends GenericRefinementIT { + /** + * This is an auto-generated constructor calling {@link GenericRefinementIT#GenericRefinementIT(java.lang.Object, SuperInterface[])}. + */ + @SafeVarargs + public GenericRefinementITResult(Boolean a, SubInterface... b) { + super(a, b); + } + + /** + * This is an auto-generated constructor calling {@link GenericRefinementIT#GenericRefinementIT(Collection, java.lang.Object[])}. + */ + public GenericRefinementITResult(Collection> a, String... b) { + super(a, b); + } +} diff --git a/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementIT.java b/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementIT.java index b24d787..d07eb4d 100644 --- a/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementIT.java +++ b/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementIT.java @@ -16,19 +16,20 @@ import de.learnlib.tooling.annotation.refinement.GenerateRefinement; import de.learnlib.tooling.annotation.refinement.Generic; -import de.learnlib.tooling.annotation.refinement.Map; +import de.learnlib.tooling.annotation.refinement.Mapping; @GenerateRefinement(name = "MultiRefinementITResult1", generics = "M", parentGenerics = @Generic("M"), - parameterMapping = {@Map(from = Object[].class, to = String[].class), - @Map(from = SuperInterface.class, - to = SubInterface.class, - withComplexGenerics = @Generic(clazz = SuperInterface2.class, - generics = "M"))}) + typeMapping = {@Mapping(from = Object.class, to = String.class), + @Mapping(from = SuperInterface.class, + to = SubInterface.class, + generics = @Generic(clazz = SuperInterface2.class, generics = "M"))}) @GenerateRefinement(name = "MultiRefinementITResult2", parentGenerics = @Generic(clazz = String[].class)) public class MultiRefinementIT implements SuperInterface { + public MultiRefinementIT(int[] param1, Object[] param2) {} + @SafeVarargs public MultiRefinementIT(int[] param1, Object[] param2, SuperInterface>... param3) {} diff --git a/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult1.java b/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult1.java index 78df6cf..5edfec5 100644 --- a/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult1.java +++ b/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult1.java @@ -5,7 +5,7 @@ import java.lang.String; /** - * This is an auto-generated refinement. See the {@link MultiRefinementIT original class}. + * This is an auto-generated refinement of {@link MultiRefinementIT}. */ @Generated( generator = "de.learnlib.tooling.processor.refinement.RefinementProcessor", @@ -13,11 +13,18 @@ ) public class MultiRefinementITResult1 extends MultiRefinementIT { /** - * This is an auto-generated constructor. See the {@link MultiRefinementIT#MultiRefinementIT(int[], Object[], SuperInterface[]) original constructor}. + * This is an auto-generated constructor calling {@link MultiRefinementIT#MultiRefinementIT(int[], java.lang.Object[])}. + */ + public MultiRefinementITResult1(int[] param1, String[] param2) { + super(param1, param2); + } + + /** + * This is an auto-generated constructor calling {@link MultiRefinementIT#MultiRefinementIT(int[], java.lang.Object[], SuperInterface[])}. */ @SafeVarargs public MultiRefinementITResult1(int[] param1, String[] param2, SubInterface>... param3) { super(param1, param2, param3); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult2.java b/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult2.java index 57b43d5..aa8fd0f 100644 --- a/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult2.java +++ b/src/test/java/de/learnlib/tooling/it/refinement/MultiRefinementITResult2.java @@ -6,7 +6,7 @@ import java.lang.String; /** - * This is an auto-generated refinement. See the {@link MultiRefinementIT original class}. + * This is an auto-generated refinement of {@link MultiRefinementIT}. */ @Generated( generator = "de.learnlib.tooling.processor.refinement.RefinementProcessor", @@ -14,7 +14,14 @@ ) public class MultiRefinementITResult2 extends MultiRefinementIT { /** - * This is an auto-generated constructor. See the {@link MultiRefinementIT#MultiRefinementIT(int[], Object[], SuperInterface[]) original constructor}. + * This is an auto-generated constructor calling {@link MultiRefinementIT#MultiRefinementIT(int[], Object[])}. + */ + public MultiRefinementITResult2(int[] param1, Object[] param2) { + super(param1, param2); + } + + /** + * This is an auto-generated constructor calling {@link MultiRefinementIT#MultiRefinementIT(int[], Object[], SuperInterface[])}. */ @SafeVarargs public MultiRefinementITResult2(int[] param1, Object[] param2, diff --git a/src/test/java/de/learnlib/tooling/it/refinement/SimpleRefinementITResult.java b/src/test/java/de/learnlib/tooling/it/refinement/SimpleRefinementITResult.java index c2b2cca..76da67a 100644 --- a/src/test/java/de/learnlib/tooling/it/refinement/SimpleRefinementITResult.java +++ b/src/test/java/de/learnlib/tooling/it/refinement/SimpleRefinementITResult.java @@ -3,7 +3,7 @@ import de.learnlib.tooling.annotation.Generated; /** - * This is an auto-generated refinement. See the {@link SimpleRefinementIT original class}. + * This is an auto-generated refinement of {@link SimpleRefinementIT}. */ @Generated( generator = "de.learnlib.tooling.processor.refinement.RefinementProcessor", @@ -11,9 +11,9 @@ ) public class SimpleRefinementITResult extends SimpleRefinementIT { /** - * This is an auto-generated constructor. See the {@link SimpleRefinementIT#SimpleRefinementIT() original constructor}. + * This is an auto-generated constructor calling {@link SimpleRefinementIT#SimpleRefinementIT()}. */ public SimpleRefinementITResult() { super(); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementIT.java b/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementIT.java index 3991acb..fdbc68e 100644 --- a/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementIT.java +++ b/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementIT.java @@ -17,16 +17,16 @@ import de.learnlib.tooling.annotation.refinement.GenerateRefinement; import de.learnlib.tooling.annotation.refinement.Generic; import de.learnlib.tooling.annotation.refinement.Interface; -import de.learnlib.tooling.annotation.refinement.Map; +import de.learnlib.tooling.annotation.refinement.Mapping; @GenerateRefinement(name = "SingleRefinementITResult", generics = "M", parentGenerics = {@Generic("M"), @Generic(clazz = Boolean.class)}, - parameterMapping = {@Map(from = SuperInterface.class, to = SubInterface.class, withGenerics = "M"), - @Map(from = SuperInterface2.class, - to = SubInterface2.class, - withComplexGenerics = @Generic(clazz = Boolean.class))}, - interfaces = @Interface(clazz = SubInterface.class, generics = "Boolean")) + typeMapping = {@Mapping(from = SuperInterface.class, to = SubInterface.class, generics = @Generic("M")), + @Mapping(from = SuperInterface2.class, + to = SubInterface2.class, + generics = @Generic(clazz = Boolean.class))}, + interfaces = @Interface(clazz = SubInterface.class, generics = @Generic(clazz = Boolean.class))) public class SingleRefinementIT implements SuperInterface { public SingleRefinementIT(int param1, diff --git a/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementITResult.java b/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementITResult.java index bbaea1b..25b8e8b 100644 --- a/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementITResult.java +++ b/src/test/java/de/learnlib/tooling/it/refinement/SingleRefinementITResult.java @@ -5,7 +5,7 @@ import java.lang.String; /** - * This is an auto-generated refinement. See the {@link SingleRefinementIT original class}. + * This is an auto-generated refinement of {@link SingleRefinementIT}. */ @Generated( generator = "de.learnlib.tooling.processor.refinement.RefinementProcessor", @@ -13,10 +13,10 @@ ) public class SingleRefinementITResult extends SingleRefinementIT implements SubInterface { /** - * This is an auto-generated constructor. See the {@link SingleRefinementIT#SingleRefinementIT(int, SuperInterface, String, SuperInterface2) original constructor}. + * This is an auto-generated constructor calling {@link SingleRefinementIT#SingleRefinementIT(int, SuperInterface, String, SuperInterface2)}. */ public SingleRefinementITResult(int param1, SubInterface param2, String param3, SubInterface2 param4) { super(param1, param2, param3, param4); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/processor/builder/BuilderProcessorTest.java b/src/test/java/de/learnlib/tooling/processor/builder/BuilderProcessorTest.java index 27d377b..cfe6541 100644 --- a/src/test/java/de/learnlib/tooling/processor/builder/BuilderProcessorTest.java +++ b/src/test/java/de/learnlib/tooling/processor/builder/BuilderProcessorTest.java @@ -14,6 +14,8 @@ */ package de.learnlib.tooling.processor.builder; +import java.io.IOException; + import com.google.testing.compile.Compilation; import com.google.testing.compile.CompilationSubject; import com.google.testing.compile.Compiler; @@ -30,46 +32,50 @@ public class BuilderProcessorTest { @Test - public void testSimpleBuilder() { + public void testSimpleBuilder() throws IOException { final Compilation compilation = Compiler.javac().withProcessors(new BuilderProcessor()).compile(Util.toJFO(SimpleBuilderIT.class)); final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(SimpleBuilderITBuilder.class)) - .hasSourceEquivalentTo(Util.toJFO(SimpleBuilderITBuilder.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(SimpleBuilderITBuilder.class).getCharContent(false)); } @Test - public void testRenamingBuilder() { + public void testRenamingBuilder() throws IOException { final Compilation compilation = Compiler.javac().withProcessors(new BuilderProcessor()).compile(Util.toJFO(RenamingBuilderIT.class)); final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(RenamedBuilderITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(RenamedBuilderITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(RenamedBuilderITResult.class).getCharContent(false)); } @Test - public void testDisablingBuilder() { + public void testDisablingBuilder() throws IOException { final Compilation compilation = Compiler.javac().withProcessors(new BuilderProcessor()).compile(Util.toJFO(DisablingBuilderIT.class)); final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(DisablingBuilderITBuilder.class)) - .hasSourceEquivalentTo(Util.toJFO(DisablingBuilderITBuilder.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(DisablingBuilderITBuilder.class).getCharContent(false)); } @Test - public void testGenericBuilder() { + public void testGenericBuilder() throws IOException { final Compilation compilation = Compiler.javac().withProcessors(new BuilderProcessor()).compile(Util.toJFO(GenericBuilderIT.class)); final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(GenericBuilderITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(GenericBuilderITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(GenericBuilderITResult.class).getCharContent(false)); } } diff --git a/src/test/java/de/learnlib/tooling/processor/builder/DisablingBuilderITBuilder.java b/src/test/java/de/learnlib/tooling/processor/builder/DisablingBuilderITBuilder.java index 211339f..cfbbc8c 100644 --- a/src/test/java/de/learnlib/tooling/processor/builder/DisablingBuilderITBuilder.java +++ b/src/test/java/de/learnlib/tooling/processor/builder/DisablingBuilderITBuilder.java @@ -47,4 +47,4 @@ DisablingBuilderITBuilder withC(SuperInterface c) { DisablingBuilderIT create(Object... d) { return new DisablingBuilderIT(a, b, c, d); } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/processor/edsl/EDSLProcessorTest.java b/src/test/java/de/learnlib/tooling/processor/edsl/EDSLProcessorTest.java index 411f4af..73ac1dd 100644 --- a/src/test/java/de/learnlib/tooling/processor/edsl/EDSLProcessorTest.java +++ b/src/test/java/de/learnlib/tooling/processor/edsl/EDSLProcessorTest.java @@ -14,6 +14,7 @@ */ package de.learnlib.tooling.processor.edsl; +import java.io.IOException; import java.util.Arrays; import com.google.testing.compile.Compilation; @@ -40,7 +41,8 @@ public void testDefaultEDSL() throws Exception { final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(DefaultEDSLITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(DefaultEDSLITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(DefaultEDSLITResult.class).getCharContent(false)); // check that we can use the result as intended final String arg = "string"; @@ -59,7 +61,8 @@ public void testExtendingEDSL() throws Exception { final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(ExtendingEDSLITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(ExtendingEDSLITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(ExtendingEDSLITResult.class).getCharContent(false)); // check that we can use the result as intended ExtendingEDSLITResult fluent = new ExtendingEDSLITResult<>(null); @@ -77,7 +80,7 @@ public void testExtendingEDSL() throws Exception { } @Test - public void testEmptyEDSL() { + public void testEmptyEDSL() throws IOException { // we need to compile both files, otherwise the annotations are missing on the super classes final Compilation compilation = Compiler.javac().withProcessors(new EDSLProcessor()).compile(Util.toJFO(EmptyEDSLIT.class)); @@ -85,7 +88,8 @@ public void testEmptyEDSL() { final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(EmptyEDSLITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(EmptyEDSLITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(EmptyEDSLITResult.class).getCharContent(false)); // check that we can use the result as intended EmptyEDSLITResult fluent = new EmptyEDSLITResult(); @@ -93,7 +97,7 @@ public void testEmptyEDSL() { } @Test - public void testOverlappingEDSL() { + public void testOverlappingEDSL() throws IOException { // we need to compile both files, otherwise the annotations are missing on the super classes final Compilation compilation = Compiler.javac().withProcessors(new EDSLProcessor()).compile(Util.toJFO(OverlappingEDSLIT.class)); @@ -101,7 +105,8 @@ public void testOverlappingEDSL() { final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(OverlappingEDSLITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(OverlappingEDSLITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(OverlappingEDSLITResult.class).getCharContent(false)); // check that we can use the result as intended OverlappingEDSLITResult fluent = new OverlappingEDSLITResult(); diff --git a/src/test/java/de/learnlib/tooling/processor/edsl/EmptyEDSLITResult.java b/src/test/java/de/learnlib/tooling/processor/edsl/EmptyEDSLITResult.java index 2e56c4f..a52a289 100644 --- a/src/test/java/de/learnlib/tooling/processor/edsl/EmptyEDSLITResult.java +++ b/src/test/java/de/learnlib/tooling/processor/edsl/EmptyEDSLITResult.java @@ -1,4 +1,3 @@ - package de.learnlib.tooling.processor.edsl; import de.learnlib.tooling.annotation.Generated; @@ -40,4 +39,4 @@ final class EmptyEDSLITResult0 { private EmptyEDSLITResult0() { } } -} \ No newline at end of file +} diff --git a/src/test/java/de/learnlib/tooling/processor/refinement/RefinementProcessorTest.java b/src/test/java/de/learnlib/tooling/processor/refinement/RefinementProcessorTest.java index 66727bd..4c1ec5b 100644 --- a/src/test/java/de/learnlib/tooling/processor/refinement/RefinementProcessorTest.java +++ b/src/test/java/de/learnlib/tooling/processor/refinement/RefinementProcessorTest.java @@ -14,10 +14,14 @@ */ package de.learnlib.tooling.processor.refinement; +import java.io.IOException; + import com.google.testing.compile.Compilation; import com.google.testing.compile.CompilationSubject; import com.google.testing.compile.Compiler; import de.learnlib.tooling.Util; +import de.learnlib.tooling.it.refinement.GenericRefinementIT; +import de.learnlib.tooling.it.refinement.GenericRefinementITResult; import de.learnlib.tooling.it.refinement.MultiRefinementIT; import de.learnlib.tooling.it.refinement.MultiRefinementITResult1; import de.learnlib.tooling.it.refinement.MultiRefinementITResult2; @@ -30,7 +34,7 @@ public class RefinementProcessorTest { @Test - public void testSimpleRefinement() { + public void testSimpleRefinement() throws IOException { final Compilation compilation = Compiler.javac() .withProcessors(new RefinementProcessor()) .compile(Util.toJFO(SimpleRefinementIT.class)); @@ -38,11 +42,12 @@ public void testSimpleRefinement() { final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(SimpleRefinementITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(SimpleRefinementITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(SimpleRefinementITResult.class).getCharContent(false)); } @Test - public void testSingleRefinement() { + public void testSingleRefinement() throws IOException { final Compilation compilation = Compiler.javac() .withProcessors(new RefinementProcessor()) .compile(Util.toJFO(SingleRefinementIT.class)); @@ -50,20 +55,34 @@ public void testSingleRefinement() { final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(SingleRefinementITResult.class)) - .hasSourceEquivalentTo(Util.toJFO(SingleRefinementITResult.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(SingleRefinementITResult.class).getCharContent(false)); } @Test - public void testMultiRefinement() { - final Compilation compilation = Compiler.javac() - .withProcessors(new RefinementProcessor()) - .compile(Util.toJFO(MultiRefinementIT.class)); + public void testMultiRefinement() throws IOException { + final Compilation compilation = + Compiler.javac().withProcessors(new RefinementProcessor()).compile(Util.toJFO(MultiRefinementIT.class)); final CompilationSubject subject = CompilationSubject.assertThat(compilation); subject.succeededWithoutWarnings(); subject.generatedSourceFile(Util.toFQN(MultiRefinementITResult1.class)) - .hasSourceEquivalentTo(Util.toJFO(MultiRefinementITResult1.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(MultiRefinementITResult1.class).getCharContent(false)); subject.generatedSourceFile(Util.toFQN(MultiRefinementITResult2.class)) - .hasSourceEquivalentTo(Util.toJFO(MultiRefinementITResult2.class)); + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(MultiRefinementITResult2.class).getCharContent(false)); + } + + @Test + public void testGenericRefinement() throws IOException { + final Compilation compilation = + Compiler.javac().withProcessors(new RefinementProcessor()).compile(Util.toJFO(GenericRefinementIT.class)); + + final CompilationSubject subject = CompilationSubject.assertThat(compilation); + subject.succeededWithoutWarnings(); + subject.generatedSourceFile(Util.toFQN(GenericRefinementITResult.class)) + .contentsAsUtf8String() + .isEqualTo(Util.toJFO(GenericRefinementITResult.class).getCharContent(false)); } }