Merging changes from private branch
This commit is contained in:
@@ -54,6 +54,8 @@ public class Annotations{
|
||||
/** Whether to generate a base class for this components.
|
||||
* An entity cannot have two base classes, so only one component can have base be true. */
|
||||
boolean base() default false;
|
||||
/** Whether to generate a proper interface for this component class. */
|
||||
boolean genInterface() default true;
|
||||
}
|
||||
|
||||
/** Indicates that a method is implemented by the annotation processor. */
|
||||
|
||||
@@ -19,6 +19,7 @@ import javax.annotation.processing.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.*;
|
||||
import java.lang.annotation.*;
|
||||
import java.util.*;
|
||||
|
||||
@SupportedAnnotationTypes({
|
||||
"mindustry.annotations.Annotations.EntityDef",
|
||||
@@ -97,6 +98,8 @@ public class EntityProcess extends BaseProcessor{
|
||||
|
||||
//create component interfaces
|
||||
for(Stype component : allComponents){
|
||||
|
||||
|
||||
TypeSpec.Builder inter = TypeSpec.interfaceBuilder(interfaceName(component))
|
||||
.addModifiers(Modifier.PUBLIC).addAnnotation(EntityInterface.class);
|
||||
|
||||
@@ -116,45 +119,47 @@ public class EntityProcess extends BaseProcessor{
|
||||
inter.addSuperinterface(ClassName.get(packageName, interfaceName(type)));
|
||||
}
|
||||
|
||||
ObjectSet<String> signatures = new ObjectSet<>();
|
||||
if(component.annotation(Component.class).genInterface()){
|
||||
ObjectSet<String> signatures = new ObjectSet<>();
|
||||
|
||||
//add utility methods to interface
|
||||
for(Smethod method : component.methods()){
|
||||
//skip private methods, those are for internal use.
|
||||
if(method.isAny(Modifier.PRIVATE, Modifier.STATIC)) continue;
|
||||
//add utility methods to interface
|
||||
for(Smethod method : component.methods()){
|
||||
//skip private methods, those are for internal use.
|
||||
if(method.isAny(Modifier.PRIVATE, Modifier.STATIC)) continue;
|
||||
|
||||
//keep track of signatures used to prevent dupes
|
||||
signatures.add(method.e.toString());
|
||||
//keep track of signatures used to prevent dupes
|
||||
signatures.add(method.e.toString());
|
||||
|
||||
inter.addMethod(MethodSpec.methodBuilder(method.name())
|
||||
.addJavadoc(method.doc() == null ? "" : method.doc())
|
||||
.addExceptions(method.thrownt())
|
||||
.addTypeVariables(method.typeVariables().map(TypeVariableName::get))
|
||||
.returns(method.ret().toString().equals("void") ? TypeName.VOID : method.retn())
|
||||
.addParameters(method.params().map(v -> ParameterSpec.builder(v.tname(), v.name())
|
||||
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
|
||||
}
|
||||
|
||||
//generate interface getters and setters for all "standard" fields
|
||||
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.has(Import.class))){
|
||||
String cname = field.name();
|
||||
|
||||
//getter
|
||||
if(!signatures.contains(cname + "()")){
|
||||
inter.addMethod(MethodSpec.methodBuilder(cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
|
||||
.addAnnotations(Seq.with(field.annotations()).select(a -> a.toString().contains("Null") || a.toString().contains("Deprecated")).map(AnnotationSpec::get))
|
||||
.addJavadoc(field.doc() == null ? "" : field.doc())
|
||||
.returns(field.tname()).build());
|
||||
inter.addMethod(MethodSpec.methodBuilder(method.name())
|
||||
.addJavadoc(method.doc() == null ? "" : method.doc())
|
||||
.addExceptions(method.thrownt())
|
||||
.addTypeVariables(method.typeVariables().map(TypeVariableName::get))
|
||||
.returns(method.ret().toString().equals("void") ? TypeName.VOID : method.retn())
|
||||
.addParameters(method.params().map(v -> ParameterSpec.builder(v.tname(), v.name())
|
||||
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
|
||||
}
|
||||
|
||||
//setter
|
||||
if(!field.is(Modifier.FINAL) && !signatures.contains(cname + "(" + field.mirror().toString() + ")") &&
|
||||
!field.annotations().contains(f -> f.toString().equals("@mindustry.annotations.Annotations.ReadOnly"))){
|
||||
inter.addMethod(MethodSpec.methodBuilder(cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
|
||||
.addJavadoc(field.doc() == null ? "" : field.doc())
|
||||
.addParameter(ParameterSpec.builder(field.tname(), field.name())
|
||||
.addAnnotations(Seq.with(field.annotations())
|
||||
.select(a -> a.toString().contains("Null") || a.toString().contains("Deprecated")).map(AnnotationSpec::get)).build()).build());
|
||||
//generate interface getters and setters for all "standard" fields
|
||||
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.has(Import.class))){
|
||||
String cname = field.name();
|
||||
|
||||
//getter
|
||||
if(!signatures.contains(cname + "()")){
|
||||
inter.addMethod(MethodSpec.methodBuilder(cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
|
||||
.addAnnotations(Seq.with(field.annotations()).select(a -> a.toString().contains("Null") || a.toString().contains("Deprecated")).map(AnnotationSpec::get))
|
||||
.addJavadoc(field.doc() == null ? "" : field.doc())
|
||||
.returns(field.tname()).build());
|
||||
}
|
||||
|
||||
//setter
|
||||
if(!field.is(Modifier.FINAL) && !signatures.contains(cname + "(" + field.mirror().toString() + ")") &&
|
||||
!field.annotations().contains(f -> f.toString().equals("@mindustry.annotations.Annotations.ReadOnly"))){
|
||||
inter.addMethod(MethodSpec.methodBuilder(cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
|
||||
.addJavadoc(field.doc() == null ? "" : field.doc())
|
||||
.addParameter(ParameterSpec.builder(field.tname(), field.name())
|
||||
.addAnnotations(Seq.with(field.annotations())
|
||||
.select(a -> a.toString().contains("Null") || a.toString().contains("Deprecated")).map(AnnotationSpec::get)).build()).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,19 +421,34 @@ public class EntityProcess extends BaseProcessor{
|
||||
|
||||
//add all methods from components
|
||||
for(ObjectMap.Entry<String, Seq<Smethod>> entry : methods){
|
||||
if(entry.value.contains(m -> m.has(Replace.class))){
|
||||
//check replacements
|
||||
if(entry.value.count(m -> m.has(Replace.class)) > 1){
|
||||
err("Type " + type + " has multiple components replacing method " + entry.key + ".");
|
||||
}
|
||||
Smethod base = entry.value.find(m -> m.has(Replace.class));
|
||||
entry.value.clear();
|
||||
entry.value.add(base);
|
||||
}
|
||||
|
||||
//check multi return
|
||||
if(entry.value.count(m -> !m.isAny(Modifier.NATIVE, Modifier.ABSTRACT) && !m.isVoid()) > 1){
|
||||
err("Type " + type + " has multiple components implementing non-void method " + entry.key + ".");
|
||||
//there are multiple @Replace implementations, or multiple non-void implementations.
|
||||
if(entry.value.size > 1 && (entry.value.contains(m -> m.has(Replace.class)) || entry.value.count(m -> !m.isAny(Modifier.NATIVE, Modifier.ABSTRACT) && !m.isVoid()) > 1)){
|
||||
|
||||
//remove clutter
|
||||
entry.value.removeAll(s -> s.is(Modifier.ABSTRACT));
|
||||
|
||||
Comparator<Smethod> comp = Structs.comps(
|
||||
Structs.comps(
|
||||
//highest priority first
|
||||
Structs.comparingFloat(m -> m.has(MethodPriority.class) ? m.annotation(MethodPriority.class).value() : 0f),
|
||||
//replacement means priority
|
||||
Structs.comparingBool(m -> m.has(Replace.class))
|
||||
),
|
||||
|
||||
//otherwise, the 'highest' subclass (most dependencies)
|
||||
Structs.comparingInt(m -> getDependencies(m.type()).size)
|
||||
);
|
||||
|
||||
Smethod best = entry.value.max(comp);
|
||||
|
||||
if(entry.value.contains(s -> best != s && comp.compare(s, best) == 0)){
|
||||
err("Type " + type + " has multiple components implementing method " + entry.value.first() + " in an ambiguous way. Use MethodPriority to designate which one should be used. Implementations: " +
|
||||
entry.value.map(s -> s.descString()));
|
||||
}
|
||||
|
||||
entry.value.clear();
|
||||
entry.value.add(best);
|
||||
}
|
||||
|
||||
entry.value.sort(Structs.comps(Structs.comparingFloat(m -> m.has(MethodPriority.class) ? m.annotation(MethodPriority.class).value() : 0), Structs.comparing(s -> s.up().getSimpleName().toString())));
|
||||
|
||||
@@ -28,6 +28,10 @@ public class Stype extends Selement<TypeElement>{
|
||||
return interfaces().flatMap(s -> s.allInterfaces().add(s)).distinct();
|
||||
}
|
||||
|
||||
public boolean isInterface(){
|
||||
return e.getKind() == ElementKind.INTERFACE;
|
||||
}
|
||||
|
||||
public Seq<Stype> superclasses(){
|
||||
return Seq.with(BaseProcessor.typeu.directSupertypes(mirror())).map(Stype::of);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user