diff --git a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java index f9a83c80fd..effbb72400 100644 --- a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java @@ -3,6 +3,7 @@ package mindustry.annotations; import javax.annotation.processing.*; import javax.lang.model.*; import javax.lang.model.element.*; +import javax.lang.model.util.*; import java.util.*; @SupportedSourceVersion(SourceVersion.RELEASE_8) @@ -10,20 +11,34 @@ public abstract class BaseProcessor extends AbstractProcessor{ /** Name of the base package to put all the generated classes. */ public static final String packageName = "mindustry.gen"; - private int round; + public static Types typeu; + public static Elements elementu; + public static Filer filer; + public static Messager messager; + + protected int round; + + public static String getMethodName(Element element){ + return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName(); + } + + public static boolean isPrimitive(String type){ + return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int") + || type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char"); + } @Override public synchronized void init(ProcessingEnvironment processingEnv){ super.init(processingEnv); - //put all relevant utils into utils class - Utils.typeUtils = processingEnv.getTypeUtils(); - Utils.elementUtils = processingEnv.getElementUtils(); - Utils.filer = processingEnv.getFiler(); - Utils.messager = processingEnv.getMessager(); + + typeu = processingEnv.getTypeUtils(); + elementu = processingEnv.getElementUtils(); + filer = processingEnv.getFiler(); + messager = processingEnv.getMessager(); } @Override - public final boolean process(Set annotations, RoundEnvironment roundEnv){ + public boolean process(Set annotations, RoundEnvironment roundEnv){ if(round++ != 0) return false; //only process 1 round try{ process(roundEnv); @@ -39,5 +54,7 @@ public abstract class BaseProcessor extends AbstractProcessor{ return SourceVersion.RELEASE_8; } - public abstract void process(RoundEnvironment env) throws Exception; + public void process(RoundEnvironment env) throws Exception{ + + } } diff --git a/annotations/src/main/java/mindustry/annotations/CallSuperAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/CallSuperAnnotationProcessor.java deleted file mode 100644 index 01a3fdb0e1..0000000000 --- a/annotations/src/main/java/mindustry/annotations/CallSuperAnnotationProcessor.java +++ /dev/null @@ -1,62 +0,0 @@ -package mindustry.annotations; - -import com.sun.source.util.*; -import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.tree.JCTree.*; -import mindustry.annotations.Annotations.*; - -import javax.annotation.processing.*; -import javax.lang.model.*; -import javax.lang.model.element.*; -import javax.tools.Diagnostic.*; -import java.util.*; - -@SupportedAnnotationTypes({"java.lang.Override"}) -public class CallSuperAnnotationProcessor extends AbstractProcessor{ - private Trees trees; - - @Override - public void init(ProcessingEnvironment pe){ - super.init(pe); - trees = Trees.instance(pe); - } - - public boolean process(Set annotations, RoundEnvironment roundEnv){ - for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){ - if(e.getAnnotation(OverrideCallSuper.class) != null) return false; - - CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner(); - codeScanner.setMethodName(e.getSimpleName().toString()); - - TreePath tp = trees.getPath(e.getEnclosingElement()); - codeScanner.scan(tp, trees); - - if(codeScanner.isCallSuperUsed()){ - List list = codeScanner.getMethod().getBody().getStatements(); - - if(!doesCallSuper(list, codeScanner.getMethodName())){ - processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.getMethodName() + "' must explicitly call super method from its parent class.", e); - } - } - } - - return false; - } - - private boolean doesCallSuper(List list, String methodName){ - for(Object object : list){ - if(object instanceof JCTree.JCExpressionStatement){ - JCTree.JCExpressionStatement expr = (JCExpressionStatement)object; - String exprString = expr.toString(); - if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true; - } - } - - return false; - } - - @Override - public SourceVersion getSupportedSourceVersion(){ - return SourceVersion.RELEASE_8; - } -} diff --git a/annotations/src/main/java/mindustry/annotations/CodeAnalyzerTreeScanner.java b/annotations/src/main/java/mindustry/annotations/CodeAnalyzerTreeScanner.java deleted file mode 100644 index 13059b38b8..0000000000 --- a/annotations/src/main/java/mindustry/annotations/CodeAnalyzerTreeScanner.java +++ /dev/null @@ -1,110 +0,0 @@ -package mindustry.annotations; - -import com.sun.source.tree.*; -import com.sun.source.util.TreePathScanner; -import com.sun.source.util.Trees; -import com.sun.tools.javac.code.Scope; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.tree.JCTree.JCIdent; -import com.sun.tools.javac.tree.JCTree.JCTypeApply; -import mindustry.annotations.Annotations.CallSuper; - -import java.lang.annotation.Annotation; - -class CodeAnalyzerTreeScanner extends TreePathScanner { - private String methodName; - private MethodTree method; - private boolean callSuperUsed; - - @Override - public Object visitClass (ClassTree classTree, Trees trees) { - Tree extendTree = classTree.getExtendsClause(); - - if (extendTree instanceof JCTypeApply) { //generic classes case - JCTypeApply generic = (JCTypeApply) extendTree; - extendTree = generic.clazz; - } - - if (extendTree instanceof JCIdent) { - JCIdent tree = (JCIdent) extendTree; - Scope members = tree.sym.members(); - - if (checkScope(members)) - return super.visitClass(classTree, trees); - - if (checkSuperTypes((ClassType) tree.type)) - return super.visitClass(classTree, trees); - - } - callSuperUsed = false; - - return super.visitClass(classTree, trees); - } - - public boolean checkSuperTypes (ClassType type) { - if (type.supertype_field != null && type.supertype_field.tsym != null) { - if (checkScope(type.supertype_field.tsym.members())) - return true; - else - return checkSuperTypes((ClassType) type.supertype_field); - } - - return false; - } - - @SuppressWarnings("unchecked") - public boolean checkScope (Scope members) { - Iterable it; - try{ - it = (Iterable)members.getClass().getMethod("getElements").invoke(members); - }catch(Throwable t){ - try{ - it = (Iterable)members.getClass().getMethod("getSymbols").invoke(members); - }catch(Exception e){ - throw new RuntimeException(e); - } - } - - for (Symbol s : it) { - if (s instanceof MethodSymbol) { - MethodSymbol ms = (MethodSymbol) s; - - if (ms.getSimpleName().toString().equals(methodName)) { - Annotation annotation = ms.getAnnotation(CallSuper.class); - if (annotation != null) { - callSuperUsed = true; - return true; - } - } - } - } - - return false; - } - - @Override - public Object visitMethod (MethodTree methodTree, Trees trees) { - if (methodTree.getName().toString().equals(methodName)) - method = methodTree; - - return super.visitMethod(methodTree, trees); - } - - public void setMethodName (String methodName) { - this.methodName = methodName; - } - - public String getMethodName () { - return methodName; - } - - public MethodTree getMethod () { - return method; - } - - public boolean isCallSuperUsed () { - return callSuperUsed; - } -} \ No newline at end of file diff --git a/annotations/src/main/java/mindustry/annotations/Utils.java b/annotations/src/main/java/mindustry/annotations/Utils.java deleted file mode 100644 index 773d6561d2..0000000000 --- a/annotations/src/main/java/mindustry/annotations/Utils.java +++ /dev/null @@ -1,24 +0,0 @@ -package mindustry.annotations; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.Messager; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; - -public class Utils{ - public static Types typeUtils; - public static Elements elementUtils; - public static Filer filer; - public static Messager messager; - - public static String getMethodName(Element element){ - return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName(); - } - - public static boolean isPrimitive(String type){ - return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int") - || type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char"); - } -} diff --git a/annotations/src/main/java/mindustry/annotations/AssetsAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/impl/AssetsAnnotationProcessor.java similarity index 94% rename from annotations/src/main/java/mindustry/annotations/AssetsAnnotationProcessor.java rename to annotations/src/main/java/mindustry/annotations/impl/AssetsAnnotationProcessor.java index 0ef33f671d..2ac95b7b40 100644 --- a/annotations/src/main/java/mindustry/annotations/AssetsAnnotationProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/impl/AssetsAnnotationProcessor.java @@ -1,10 +1,11 @@ -package mindustry.annotations; +package mindustry.annotations.impl; import arc.files.*; import arc.scene.style.*; import arc.struct.*; import arc.util.serialization.*; import com.squareup.javapoet.*; +import mindustry.annotations.*; import mindustry.annotations.Annotations.*; import javax.annotation.processing.*; @@ -20,7 +21,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{ @Override public void process(RoundEnvironment env) throws Exception{ - path = Fi.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") + path = Fi.get(BaseProcessor.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") .toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length())) .parent().parent().parent().parent().parent().parent().toString(); path = path.replace("%20", " "); @@ -85,12 +86,12 @@ public class AssetsAnnotationProcessor extends BaseProcessor{ } ictype.addMethod(icload.build()); - JavaFile.builder(packageName, ichtype.build()).build().writeTo(Utils.filer); - JavaFile.builder(packageName, ictype.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, ichtype.build()).build().writeTo(BaseProcessor.filer); + JavaFile.builder(packageName, ictype.build()).build().writeTo(BaseProcessor.filer); type.addMethod(load.build()); type.addMethod(loadStyles.build()); - JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer); } void processSounds(String classname, String path, String rtype) throws Exception{ @@ -104,7 +105,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{ String name = p.nameWithoutExtension(); if(names.contains(name)){ - Utils.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!"); + BaseProcessor.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!"); }else{ names.add(name); } @@ -130,7 +131,7 @@ public class AssetsAnnotationProcessor extends BaseProcessor{ type.addMethod(loadBegin.build()); type.addMethod(dispose.build()); - JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer); } static String capitalize(String s){ diff --git a/annotations/src/main/java/mindustry/annotations/impl/CallSuperAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/impl/CallSuperAnnotationProcessor.java new file mode 100644 index 0000000000..1d3a2ae4c4 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/impl/CallSuperAnnotationProcessor.java @@ -0,0 +1,165 @@ +package mindustry.annotations.impl; + +import com.sun.source.tree.*; +import com.sun.source.util.*; +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.tree.*; +import com.sun.tools.javac.tree.JCTree.*; +import mindustry.annotations.Annotations.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; +import java.lang.annotation.*; +import java.util.*; + +@SupportedAnnotationTypes({"java.lang.Override"}) +public class CallSuperAnnotationProcessor extends AbstractProcessor{ + private Trees trees; + + @Override + public void init(ProcessingEnvironment pe){ + super.init(pe); + trees = Trees.instance(pe); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv){ + for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){ + if(e.getAnnotation(OverrideCallSuper.class) != null) return false; + + CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner(); + codeScanner.setMethodName(e.getSimpleName().toString()); + + TreePath tp = trees.getPath(e.getEnclosingElement()); + codeScanner.scan(tp, trees); + + if(codeScanner.isCallSuperUsed()){ + List list = codeScanner.getMethod().getBody().getStatements(); + + if(!doesCallSuper(list, codeScanner.getMethodName())){ + processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.getMethodName() + "' must explicitly call super method from its parent class.", e); + } + } + } + + return false; + } + + private boolean doesCallSuper(List list, String methodName){ + for(Object object : list){ + if(object instanceof JCTree.JCExpressionStatement){ + JCTree.JCExpressionStatement expr = (JCExpressionStatement)object; + String exprString = expr.toString(); + if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true; + } + } + + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion(){ + return SourceVersion.RELEASE_8; + } + + static class CodeAnalyzerTreeScanner extends TreePathScanner { + private String methodName; + private MethodTree method; + private boolean callSuperUsed; + + @Override + public Object visitClass (ClassTree classTree, Trees trees) { + Tree extendTree = classTree.getExtendsClause(); + + if (extendTree instanceof JCTypeApply) { //generic classes case + JCTypeApply generic = (JCTypeApply) extendTree; + extendTree = generic.clazz; + } + + if (extendTree instanceof JCIdent) { + JCIdent tree = (JCIdent) extendTree; + com.sun.tools.javac.code.Scope members = tree.sym.members(); + + if (checkScope(members)) + return super.visitClass(classTree, trees); + + if (checkSuperTypes((ClassType) tree.type)) + return super.visitClass(classTree, trees); + + } + callSuperUsed = false; + + return super.visitClass(classTree, trees); + } + + public boolean checkSuperTypes (ClassType type) { + if (type.supertype_field != null && type.supertype_field.tsym != null) { + if (checkScope(type.supertype_field.tsym.members())) + return true; + else + return checkSuperTypes((ClassType) type.supertype_field); + } + + return false; + } + + @SuppressWarnings("unchecked") + public boolean checkScope (Scope members) { + Iterable it; + try{ + it = (Iterable)members.getClass().getMethod("getElements").invoke(members); + }catch(Throwable t){ + try{ + it = (Iterable)members.getClass().getMethod("getSymbols").invoke(members); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + for (Symbol s : it) { + if (s instanceof MethodSymbol) { + MethodSymbol ms = (MethodSymbol) s; + + if (ms.getSimpleName().toString().equals(methodName)) { + Annotation annotation = ms.getAnnotation(CallSuper.class); + if (annotation != null) { + callSuperUsed = true; + return true; + } + } + } + } + + return false; + } + + @Override + public Object visitMethod (MethodTree methodTree, Trees trees) { + if (methodTree.getName().toString().equals(methodName)) + method = methodTree; + + return super.visitMethod(methodTree, trees); + } + + public void setMethodName (String methodName) { + this.methodName = methodName; + } + + public String getMethodName () { + return methodName; + } + + public MethodTree getMethod () { + return method; + } + + public boolean isCallSuperUsed () { + return callSuperUsed; + } + } +} diff --git a/annotations/src/main/java/mindustry/annotations/SerializeAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/impl/SerializeAnnotationProcessor.java similarity index 93% rename from annotations/src/main/java/mindustry/annotations/SerializeAnnotationProcessor.java rename to annotations/src/main/java/mindustry/annotations/impl/SerializeAnnotationProcessor.java index 16ebcc9ead..3d07b2abce 100644 --- a/annotations/src/main/java/mindustry/annotations/SerializeAnnotationProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/impl/SerializeAnnotationProcessor.java @@ -1,14 +1,14 @@ -package mindustry.annotations; +package mindustry.annotations.impl; import com.squareup.javapoet.*; +import mindustry.annotations.*; import mindustry.annotations.Annotations.*; +import mindustry.annotations.remote.*; import javax.annotation.processing.*; -import javax.lang.model.*; import javax.lang.model.element.Modifier; import javax.lang.model.element.*; import javax.lang.model.util.*; -import javax.tools.Diagnostic.*; import java.io.*; import java.lang.reflect.*; import java.util.*; @@ -55,13 +55,13 @@ public class SerializeAnnotationProcessor extends BaseProcessor{ readMethod.addStatement("$L object = new $L()", type, type); - List fields = ElementFilter.fieldsIn(Utils.elementUtils.getAllMembers(elem)); + List fields = ElementFilter.fieldsIn(BaseProcessor.elementu.getAllMembers(elem)); for(VariableElement field : fields){ if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE)) continue; String name = field.getSimpleName().toString(); - String typeName = Utils.typeUtils.erasure(field.asType()).toString().replace('$', '.'); + String typeName = BaseProcessor.typeu.erasure(field.asType()).toString().replace('$', '.'); String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); if(field.asType().getKind().isPrimitive()){ @@ -78,7 +78,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{ serializer.addMethod(writeMethod.build()); serializer.addMethod(readMethod.build()); - method.addStatement("arc.Core.settings.setSerializer($N, $L)", Utils.elementUtils.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build()); + method.addStatement("arc.Core.settings.setSerializer($N, $L)", BaseProcessor.elementu.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build()); name(writeMethod, "write" + simpleTypeName); name(readMethod, "read" + simpleTypeName); @@ -93,7 +93,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{ classBuilder.addMethod(method.build()); //write result - JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer); } static void name(MethodSpec.Builder builder, String name){ diff --git a/annotations/src/main/java/mindustry/annotations/StructAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/impl/StructAnnotationProcessor.java similarity index 95% rename from annotations/src/main/java/mindustry/annotations/StructAnnotationProcessor.java rename to annotations/src/main/java/mindustry/annotations/impl/StructAnnotationProcessor.java index 48d5cf33f0..e4387245c5 100644 --- a/annotations/src/main/java/mindustry/annotations/StructAnnotationProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/impl/StructAnnotationProcessor.java @@ -1,11 +1,11 @@ -package mindustry.annotations; +package mindustry.annotations.impl; import com.squareup.javapoet.*; +import mindustry.annotations.*; import mindustry.annotations.Annotations.Struct; import mindustry.annotations.Annotations.StructField; import javax.annotation.processing.*; -import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.type.TypeKind; import javax.lang.model.util.ElementFilter; @@ -29,7 +29,7 @@ public class StructAnnotationProcessor extends BaseProcessor{ for(TypeElement elem : elements){ if(!elem.getSimpleName().toString().endsWith("Struct")){ - Utils.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem); + BaseProcessor.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem); continue; } @@ -45,7 +45,7 @@ public class StructAnnotationProcessor extends BaseProcessor{ int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64); if(variables.size() == 0){ - Utils.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem); + BaseProcessor.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem); continue; } @@ -130,10 +130,10 @@ public class StructAnnotationProcessor extends BaseProcessor{ constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3)); classBuilder.addMethod(constructor.build()); - JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer); }catch(IllegalArgumentException e){ e.printStackTrace(); - Utils.messager.printMessage(Kind.ERROR, e.getMessage(), elem); + BaseProcessor.messager.printMessage(Kind.ERROR, e.getMessage(), elem); } } diff --git a/annotations/src/main/java/mindustry/annotations/ClassEntry.java b/annotations/src/main/java/mindustry/annotations/remote/ClassEntry.java similarity index 90% rename from annotations/src/main/java/mindustry/annotations/ClassEntry.java rename to annotations/src/main/java/mindustry/annotations/remote/ClassEntry.java index 002dcac88c..3474eff468 100644 --- a/annotations/src/main/java/mindustry/annotations/ClassEntry.java +++ b/annotations/src/main/java/mindustry/annotations/remote/ClassEntry.java @@ -1,4 +1,4 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import java.util.ArrayList; diff --git a/annotations/src/main/java/mindustry/annotations/IOFinder.java b/annotations/src/main/java/mindustry/annotations/remote/IOFinder.java similarity index 82% rename from annotations/src/main/java/mindustry/annotations/IOFinder.java rename to annotations/src/main/java/mindustry/annotations/remote/IOFinder.java index e586cbd4a8..16384f241a 100644 --- a/annotations/src/main/java/mindustry/annotations/IOFinder.java +++ b/annotations/src/main/java/mindustry/annotations/remote/IOFinder.java @@ -1,5 +1,6 @@ -package mindustry.annotations; +package mindustry.annotations.remote; +import mindustry.annotations.*; import mindustry.annotations.Annotations.ReadClass; import mindustry.annotations.Annotations.WriteClass; @@ -11,8 +12,8 @@ import java.util.HashMap; import java.util.Set; /** - * This class finds reader and writer methods annotated by the {@link Annotations.WriteClass} - * and {@link Annotations.ReadClass} annotations. + * This class finds reader and writer methods annotated by the {@link WriteClass} + * and {@link ReadClass} annotations. */ public class IOFinder{ @@ -34,21 +35,21 @@ public class IOFinder{ //make sure there's only one read method if(readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count() > 1){ - Utils.messager.printMessage(Kind.ERROR, "Multiple writer methods for type '" + typeName + "'", writer); + BaseProcessor.messager.printMessage(Kind.ERROR, "Multiple writer methods for type '" + typeName + "'", writer); } //make sure there's only one write method long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count(); if(count == 0){ - Utils.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer); + BaseProcessor.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer); }else if(count > 1){ - Utils.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer); + BaseProcessor.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer); } Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).findFirst().get(); //add to result list - result.put(typeName, new ClassSerializer(Utils.getMethodName(reader), Utils.getMethodName(writer), typeName)); + result.put(typeName, new ClassSerializer(BaseProcessor.getMethodName(reader), BaseProcessor.getMethodName(writer), typeName)); } return result; diff --git a/annotations/src/main/java/mindustry/annotations/MethodEntry.java b/annotations/src/main/java/mindustry/annotations/remote/MethodEntry.java similarity index 98% rename from annotations/src/main/java/mindustry/annotations/MethodEntry.java rename to annotations/src/main/java/mindustry/annotations/remote/MethodEntry.java index 0010d4b4d4..68ea81dec0 100644 --- a/annotations/src/main/java/mindustry/annotations/MethodEntry.java +++ b/annotations/src/main/java/mindustry/annotations/remote/MethodEntry.java @@ -1,4 +1,4 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import mindustry.annotations.Annotations.*; diff --git a/annotations/src/main/java/mindustry/annotations/RemoteMethodAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteMethodAnnotationProcessor.java similarity index 79% rename from annotations/src/main/java/mindustry/annotations/RemoteMethodAnnotationProcessor.java rename to annotations/src/main/java/mindustry/annotations/remote/RemoteMethodAnnotationProcessor.java index 2da9ddb35c..7f3acc0c86 100644 --- a/annotations/src/main/java/mindustry/annotations/RemoteMethodAnnotationProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteMethodAnnotationProcessor.java @@ -1,32 +1,28 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import com.squareup.javapoet.*; -import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.Annotations.Remote; -import mindustry.annotations.IOFinder.ClassSerializer; +import mindustry.annotations.*; +import mindustry.annotations.Annotations.*; +import mindustry.annotations.remote.IOFinder.*; import javax.annotation.processing.*; -import javax.lang.model.SourceVersion; import javax.lang.model.element.*; -import javax.tools.Diagnostic.Kind; +import javax.tools.Diagnostic.*; import java.util.*; -import java.util.stream.Collectors; +import java.util.stream.*; /** The annotation processor for generating remote method call code. */ -@SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes({ "mindustry.annotations.Annotations.Remote", "mindustry.annotations.Annotations.WriteClass", "mindustry.annotations.Annotations.ReadClass", }) -public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ +public class RemoteMethodAnnotationProcessor extends BaseProcessor{ /** Maximum size of each event packet. */ public static final int maxPacketSize = 4096; /** Warning on top of each autogenerated file. */ public static final String autogenWarning = "Autogenerated file. Do not modify!\n"; - /** Name of the base package to put all the generated classes. */ - private static final String packageName = "mindustry.gen"; /** Name of class that handles reading and invoking packets on the server. */ private static final String readServerName = "RemoteReadServer"; @@ -35,9 +31,6 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ /** Simple class name of generated class name. */ private static final String callLocation = "Call"; - /** Processing round number. */ - private int round; - //class serializers private HashMap serializers; //all elements with the Remote annotation @@ -49,16 +42,6 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ //list of all method entries private ArrayList classes; - @Override - public synchronized void init(ProcessingEnvironment processingEnv){ - super.init(processingEnv); - //put all relevant utils into utils class - Utils.typeUtils = processingEnv.getTypeUtils(); - Utils.elementUtils = processingEnv.getElementUtils(); - Utils.filer = processingEnv.getFiler(); - Utils.messager = processingEnv.getMessager(); - } - @Override public boolean process(Set annotations, RoundEnvironment roundEnv){ if(round > 1) return false; //only process 2 rounds @@ -91,12 +74,12 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ //check for static if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){ - Utils.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element); + BaseProcessor.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element); } //can't generate none methods if(annotation.targets() == Loc.none){ - Utils.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element); + BaseProcessor.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element); } //get and create class entry if needed @@ -109,7 +92,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ ClassEntry entry = classMap.get(callLocation); //create and add entry - MethodEntry method = new MethodEntry(entry.name, Utils.getMethodName(element), annotation.targets(), annotation.variants(), + MethodEntry method = new MethodEntry(entry.name, BaseProcessor.getMethodName(element), annotation.targets(), annotation.variants(), annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority()); entry.methods.add(method); @@ -139,7 +122,7 @@ public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ //build and write resulting hash class TypeSpec spec = hashBuilder.build(); - JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); + JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer); return true; } diff --git a/annotations/src/main/java/mindustry/annotations/RemoteReadGenerator.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteReadGenerator.java similarity index 94% rename from annotations/src/main/java/mindustry/annotations/RemoteReadGenerator.java rename to annotations/src/main/java/mindustry/annotations/remote/RemoteReadGenerator.java index 166c7c5ce5..ab7abb2538 100644 --- a/annotations/src/main/java/mindustry/annotations/RemoteReadGenerator.java +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteReadGenerator.java @@ -1,7 +1,8 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import com.squareup.javapoet.*; -import mindustry.annotations.IOFinder.ClassSerializer; +import mindustry.annotations.*; +import mindustry.annotations.remote.IOFinder.ClassSerializer; import javax.lang.model.element.*; import javax.tools.Diagnostic.Kind; @@ -82,7 +83,7 @@ public class RemoteReadGenerator{ String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); //write primitives automatically - if(Utils.isPrimitive(typeName)){ + if(BaseProcessor.isPrimitive(typeName)){ if(typeName.equals("boolean")){ readBlock.addStatement("boolean " + varName + " = buffer.get() == 1"); }else{ @@ -93,7 +94,7 @@ public class RemoteReadGenerator{ ClassSerializer ser = serializers.get(typeName); if(ser == null){ //make sure a serializer exists! - Utils.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var); + BaseProcessor.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var); return; } @@ -139,6 +140,6 @@ public class RemoteReadGenerator{ //build and write resulting class TypeSpec spec = classBuilder.build(); - JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); + JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer); } } diff --git a/annotations/src/main/java/mindustry/annotations/RemoteWriteGenerator.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java similarity index 93% rename from annotations/src/main/java/mindustry/annotations/RemoteWriteGenerator.java rename to annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java index dfe3f1fa00..19c5d73df3 100644 --- a/annotations/src/main/java/mindustry/annotations/RemoteWriteGenerator.java +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java @@ -1,8 +1,9 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import com.squareup.javapoet.*; +import mindustry.annotations.*; import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.IOFinder.ClassSerializer; +import mindustry.annotations.remote.IOFinder.ClassSerializer; import javax.lang.model.element.*; import javax.tools.Diagnostic.Kind; @@ -52,7 +53,7 @@ public class RemoteWriteGenerator{ //build and write resulting class TypeSpec spec = classBuilder.build(); - JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); + JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer); } } @@ -73,12 +74,12 @@ public class RemoteWriteGenerator{ //validate client methods to make sure if(methodEntry.where.isClient){ if(elem.getParameters().isEmpty()){ - Utils.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem); + BaseProcessor.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem); return; } if(!elem.getParameters().get(0).asType().toString().equals("mindustry.entities.type.Player")){ - Utils.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem); + BaseProcessor.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem); return; } } @@ -162,7 +163,7 @@ public class RemoteWriteGenerator{ method.beginControlFlow("if(mindustry.Vars.net.server())"); } - if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it + if(BaseProcessor.isPrimitive(typeName)){ //check if it's a primitive, and if so write it if(typeName.equals("boolean")){ //booleans are special method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)"); }else{ @@ -174,7 +175,7 @@ public class RemoteWriteGenerator{ ClassSerializer ser = serializers.get(typeName); if(ser == null){ //make sure a serializer exists! - Utils.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var); + BaseProcessor.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var); return; } diff --git a/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor index 0888df74ee..8bae50dbf8 100644 --- a/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -1,5 +1,5 @@ -mindustry.annotations.RemoteMethodAnnotationProcessor -mindustry.annotations.SerializeAnnotationProcessor -mindustry.annotations.StructAnnotationProcessor -mindustry.annotations.CallSuperAnnotationProcessor -mindustry.annotations.AssetsAnnotationProcessor \ No newline at end of file +mindustry.annotations.remote.RemoteMethodAnnotationProcessor +mindustry.annotations.impl.StructAnnotationProcessor +mindustry.annotations.impl.SerializeAnnotationProcessor +mindustry.annotations.impl.AssetsAnnotationProcessor +mindustry.annotations.impl.CallSuperAnnotationProcessor diff --git a/build.gradle b/build.gradle index 957eddbde9..2d86961911 100644 --- a/build.gradle +++ b/build.gradle @@ -132,6 +132,19 @@ allprojects{ props.store(pfile.newWriter(), "Autogenerated file. Do not modify.") } } + + writeProcessors = { + def processorFile = new File(rootDir, "annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor") + def text = new StringBuilder() + def files = new File(rootDir, "annotations/src/main/java") + files.eachFileRecurse(groovy.io.FileType.FILES){ file -> + if(file.name.endsWith(".java") && (file.text.contains(" extends BaseProcessor") || (file.text.contains(" extends AbstractProcessor") && !file.text.contains("abstract class")))){ + text.append(file.path.substring(files.path.length() + 1)).append("\n") + } + } + + processorFile.text = text.toString().replace(".java", "").replace("/", ".").replace("\\", ".") + } } repositories{ @@ -205,6 +218,7 @@ project(":core"){ outputs.upToDateWhen{ false } generateLocales() writeVersion() + writeProcessors() } task copyChangelog{ @@ -229,31 +243,6 @@ project(":core"){ } dependencies{ - if(System.properties["user.name"] == "anuke"){ - task cleanGen{ - doFirst{ - delete{ - delete "../core/src/mindustry/gen/" - } - } - } - - task copyGen{ - doLast{ - copy{ - from("../core/build/generated/sources/annotationProcessor/java/main/mindustry/gen"){ - include "**/*.java" - } - - into "../core/src/mindustry/gen" - } - } - } - - compileJava.dependsOn(cleanGen) - compileJava.finalizedBy(copyGen) - } - compileJava.dependsOn(preGen) compile "org.lz4:lz4-java:1.4.1" diff --git a/core/build.gradle b/core/build.gradle index abcec6d8f6..ea07c810b3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,4 +1,4 @@ apply plugin: "java" sourceCompatibility = 1.8 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' -sourceSets.main.java.srcDirs = ["src/"] \ No newline at end of file +sourceSets.main.java.srcDirs = ["src/", "$buildDir/generated/sources/annotationProcessor/java/main"] \ No newline at end of file