Merge pull request 'LinkageOptimizations' (#48) from LinkageOptimizations into master
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Reviewed-on: #48 Reviewed-by: Lixfel <lixfel@steamwar.de>
Dieser Commit ist enthalten in:
Commit
36bb4db515
@ -23,12 +23,16 @@ import de.steamwar.linkage.plan.BuildPlan;
|
|||||||
import de.steamwar.linkage.plan.FieldBuilder;
|
import de.steamwar.linkage.plan.FieldBuilder;
|
||||||
import de.steamwar.linkage.plan.MethodBuilder;
|
import de.steamwar.linkage.plan.MethodBuilder;
|
||||||
import de.steamwar.linkage.types.Plain_GENERIC;
|
import de.steamwar.linkage.types.Plain_GENERIC;
|
||||||
|
import lombok.Cleanup;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
import javax.lang.model.SourceVersion;
|
import javax.lang.model.SourceVersion;
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.Modifier;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.tools.Diagnostic;
|
import javax.tools.Diagnostic;
|
||||||
@ -39,6 +43,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@SupportedAnnotationTypes("de.steamwar.linkage.Linked")
|
@SupportedAnnotationTypes("de.steamwar.linkage.Linked")
|
||||||
public class LinkageProcessor extends AbstractProcessor {
|
public class LinkageProcessor extends AbstractProcessor {
|
||||||
@ -49,7 +54,6 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
private static String pluginMain;
|
private static String pluginMain;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String packageName;
|
|
||||||
private String className;
|
private String className;
|
||||||
|
|
||||||
private Messager messager;
|
private Messager messager;
|
||||||
@ -69,7 +73,6 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
|
|
||||||
messager = processingEnv.getMessager();
|
messager = processingEnv.getMessager();
|
||||||
|
|
||||||
packageName = "de.steamwar." + name + ".linkage";
|
|
||||||
className = "LinkageUtils";
|
className = "LinkageUtils";
|
||||||
mainClass();
|
mainClass();
|
||||||
}
|
}
|
||||||
@ -87,22 +90,15 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context = pluginYMLFile.get().getName().equals("bungee.yml") ? Context.BUNGEE : Context.SPIGOT;
|
context = pluginYMLFile.get().getName().equals("bungee.yml") ? Context.BUNGEE : Context.SPIGOT;
|
||||||
Optional<String> mainName = getMainName(pluginYMLFile.get());
|
@Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYMLFile.get())));
|
||||||
if (!mainName.isPresent()) {
|
Optional<String> mainName = reader.lines()
|
||||||
|
.filter(line -> line.startsWith("main:"))
|
||||||
|
.map(line -> line.substring(line.indexOf(':') + 1).trim())
|
||||||
|
.findFirst();
|
||||||
|
if (mainName.isPresent()) {
|
||||||
|
pluginMain = mainName.get();
|
||||||
|
} else {
|
||||||
messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml");
|
messager.printMessage(Diagnostic.Kind.ERROR, "Could not find main class in plugin.yml or bungee.yml");
|
||||||
return;
|
|
||||||
}
|
|
||||||
pluginMain = mainName.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private Optional<String> getMainName(File pluginYML) {
|
|
||||||
if (!pluginYML.exists()) return Optional.empty();
|
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(pluginYML)))) {
|
|
||||||
return reader.lines()
|
|
||||||
.filter(line -> line.startsWith("main:"))
|
|
||||||
.map(line -> line.substring(line.indexOf(':') + 1).trim())
|
|
||||||
.findFirst();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,31 +109,30 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
processed = true;
|
processed = true;
|
||||||
|
|
||||||
Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter();
|
Writer writer = processingEnv.getFiler().createSourceFile("de.steamwar." + name + ".linkage.LinkageUtils").openWriter();
|
||||||
|
BuildPlan buildPlan = new BuildPlan("de.steamwar." + name + ".linkage", className);
|
||||||
|
|
||||||
BuildPlan buildPlan = new BuildPlan(packageName, className);
|
Set<TypeElement> elements = roundEnv.getElementsAnnotatedWith(Linked.class).stream()
|
||||||
|
.filter(element -> element.getKind() == ElementKind.CLASS)
|
||||||
|
.map(TypeElement.class::cast)
|
||||||
|
.peek(typeElement -> System.out.println("Found element: " + typeElement.getQualifiedName().toString()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
Map<Set<String>, List<TypeElement>> groupedByChecks = elements.stream()
|
||||||
|
.collect(Collectors.groupingBy(element -> checks(element, buildPlan)));
|
||||||
|
|
||||||
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Linked.class);
|
|
||||||
Map<String, TypeElement> neededFields = new HashMap<>();
|
Map<String, TypeElement> neededFields = new HashMap<>();
|
||||||
Set<Runnable> fieldInjections = new HashSet<>();
|
Set<Runnable> fieldInjections = new HashSet<>();
|
||||||
for (Element element : elements) {
|
for (TypeElement typeElement : elements) {
|
||||||
if (element.getKind() != ElementKind.CLASS) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TypeElement typeElement = (TypeElement) element;
|
|
||||||
Linked linked = element.getAnnotation(Linked.class);
|
|
||||||
if (linked == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (getLinkagesOfType(typeElement).size() > 1) {
|
if (getLinkagesOfType(typeElement).size() > 1) {
|
||||||
neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
|
neededFields.put(typeElement.getQualifiedName().toString(), typeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<VariableElement> variableElements = typeElement.getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.FIELD).map(VariableElement.class::cast).filter(e -> {
|
List<VariableElement> variableElements = typeElement.getEnclosedElements().stream()
|
||||||
return e.getAnnotation(LinkedInstance.class) != null;
|
.filter(e -> e.getKind() == ElementKind.FIELD)
|
||||||
}).collect(Collectors.toList());
|
.map(VariableElement.class::cast)
|
||||||
if (variableElements.isEmpty()) {
|
.filter(e -> e.getAnnotation(LinkedInstance.class) != null)
|
||||||
continue;
|
.collect(Collectors.toList());
|
||||||
}
|
if (variableElements.isEmpty()) continue;
|
||||||
|
|
||||||
for (VariableElement variableElement : variableElements) {
|
for (VariableElement variableElement : variableElements) {
|
||||||
if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) {
|
if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) {
|
||||||
@ -177,30 +172,37 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
fieldInjections.forEach(Runnable::run);
|
fieldInjections.forEach(Runnable::run);
|
||||||
|
|
||||||
Map<String, MethodBuilder> methods = new HashMap<>();
|
Map<String, MethodBuilder> methods = new HashMap<>();
|
||||||
for (Element element : elements) {
|
for (Map.Entry<Set<String>, List<TypeElement>> entry : groupedByChecks.entrySet()) {
|
||||||
if (element.getKind() != ElementKind.CLASS) {
|
Map<String, Map<TypeElement, List<LinkageType>>> groupedByMethod = new HashMap<>();
|
||||||
continue;
|
for (TypeElement typeElement : entry.getValue()) {
|
||||||
}
|
for (Map.Entry<String, List<LinkageType>> linkages : getLinkagesOfType(typeElement).entrySet()) {
|
||||||
TypeElement typeElement = (TypeElement) element;
|
groupedByMethod.computeIfAbsent(linkages.getKey(), ignored -> new HashMap<>())
|
||||||
|
.put(typeElement, linkages.getValue());
|
||||||
System.out.println("Found element: " + typeElement.getQualifiedName().toString());
|
}
|
||||||
Map<String, List<LinkageType>> linkages = getLinkagesOfType(typeElement);
|
|
||||||
if (linkages.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, List<LinkageType>> entry : linkages.entrySet()) {
|
for (Map.Entry<String, Map<TypeElement, List<LinkageType>>> group : groupedByMethod.entrySet()) {
|
||||||
MethodBuilder method = methods.computeIfAbsent(entry.getKey(), s -> {
|
MethodBuilder method = methods.computeIfAbsent(group.getKey(), s -> {
|
||||||
MethodBuilder methodBuilder = new MethodBuilder(s, "void");
|
MethodBuilder methodBuilder = new MethodBuilder(s, "void");
|
||||||
buildPlan.addMethod(methodBuilder);
|
buildPlan.addMethod(methodBuilder);
|
||||||
return methodBuilder;
|
return methodBuilder;
|
||||||
});
|
});
|
||||||
for (LinkageType type : entry.getValue()) {
|
|
||||||
specialElements(typeElement, buildPlan, method::addLine, () -> {
|
if (!entry.getKey().isEmpty()) method.addLine("if (" + String.join(" && ", entry.getKey()) + ") {");
|
||||||
|
for (Map.Entry<TypeElement, List<LinkageType>> toGenerate : group.getValue().entrySet()) {
|
||||||
|
TypeElement typeElement = toGenerate.getKey();
|
||||||
|
String instance = getElement(typeElement, neededFields);
|
||||||
|
if (toGenerate.getValue().size() > 1 && instance.startsWith("new ")) {
|
||||||
|
method.addLine(typeElement.getSimpleName() + " local" + typeElement.getSimpleName().toString() + " = " + instance + ";");
|
||||||
|
instance = "local" + typeElement.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
String finalInstance = instance;
|
||||||
|
toGenerate.getValue().forEach(linkageType -> {
|
||||||
buildPlan.addImport(typeElement.getQualifiedName().toString());
|
buildPlan.addImport(typeElement.getQualifiedName().toString());
|
||||||
type.generateCode(buildPlan, method, getElement(typeElement, neededFields), typeElement);
|
linkageType.generateCode(buildPlan, method, finalInstance, typeElement);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!entry.getKey().isEmpty()) method.addLine("}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,21 +213,21 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getElement(TypeElement typeElement, Map<String, TypeElement> neededFields) {
|
private String getElement(TypeElement typeElement, Map<String, TypeElement> neededFields) {
|
||||||
|
String s = typeElement.getSimpleName().toString();
|
||||||
if (neededFields.containsKey(typeElement.getQualifiedName().toString())) {
|
if (neededFields.containsKey(typeElement.getQualifiedName().toString())) {
|
||||||
String s = typeElement.getSimpleName().toString();
|
|
||||||
return s.substring(0, 1).toLowerCase() + s.substring(1);
|
return s.substring(0, 1).toLowerCase() + s.substring(1);
|
||||||
}
|
}
|
||||||
return "new " + typeElement.getSimpleName().toString() + "()";
|
return "new " + s + "()";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer<String> stringConsumer, Runnable inner) {
|
private Set<String> checks(TypeElement typeElement, BuildPlan buildPlan) {
|
||||||
|
Set<String> checks = new HashSet<>();
|
||||||
MinVersion minVersion = typeElement.getAnnotation(MinVersion.class);
|
MinVersion minVersion = typeElement.getAnnotation(MinVersion.class);
|
||||||
MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class);
|
MaxVersion maxVersion = typeElement.getAnnotation(MaxVersion.class);
|
||||||
EventMode eventMode = typeElement.getAnnotation(EventMode.class);
|
EventMode eventMode = typeElement.getAnnotation(EventMode.class);
|
||||||
PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class);
|
PluginCheck[] pluginChecks = typeElement.getAnnotationsByType(PluginCheck.class);
|
||||||
if (context == Context.SPIGOT) {
|
if (context == Context.SPIGOT) {
|
||||||
errorOnNonNull(typeElement, eventMode);
|
errorOnNonNull(typeElement, eventMode);
|
||||||
List<String> checks = new ArrayList<>();
|
|
||||||
if (minVersion != null) {
|
if (minVersion != null) {
|
||||||
buildPlan.addImport("de.steamwar.core.Core");
|
buildPlan.addImport("de.steamwar.core.Core");
|
||||||
checks.add("Core.getVersion() >= " + minVersion.value());
|
checks.add("Core.getVersion() >= " + minVersion.value());
|
||||||
@ -240,12 +242,8 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
return "Bukkit.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
||||||
}).forEach(checks::add);
|
}).forEach(checks::add);
|
||||||
}
|
}
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
|
|
||||||
inner.run();
|
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("}");
|
|
||||||
} else {
|
} else {
|
||||||
errorOnNonNull(typeElement, minVersion, maxVersion);
|
errorOnNonNull(typeElement, minVersion, maxVersion);
|
||||||
List<String> checks = new ArrayList<>();
|
|
||||||
if (eventMode != null) {
|
if (eventMode != null) {
|
||||||
buildPlan.addImport("de.steamwar.bungeecore.BungeeCore");
|
buildPlan.addImport("de.steamwar.bungeecore.BungeeCore");
|
||||||
checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE");
|
checks.add(eventMode.value().getPrefix() + "BungeeCore.EVENT_MODE");
|
||||||
@ -256,10 +254,15 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
return "BungeeCord.getPluginManager().getPlugin(\"" + pluginCheck.value() + "\") " + (pluginCheck.has() == PluginCheck.Has.THIS ? "!" : "=") + "= null";
|
||||||
}).forEach(checks::add);
|
}).forEach(checks::add);
|
||||||
}
|
}
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
|
|
||||||
inner.run();
|
|
||||||
if (!checks.isEmpty()) stringConsumer.accept("}");
|
|
||||||
}
|
}
|
||||||
|
return checks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void specialElements(TypeElement typeElement, BuildPlan buildPlan, Consumer<String> stringConsumer, Runnable inner) {
|
||||||
|
Set<String> checks = checks(typeElement, buildPlan);
|
||||||
|
if (!checks.isEmpty()) stringConsumer.accept("if (" + String.join(" && ", checks) + ") {");
|
||||||
|
inner.run();
|
||||||
|
if (!checks.isEmpty()) stringConsumer.accept("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) {
|
private void errorOnNonNull(TypeElement typeElement, Annotation... annotations) {
|
||||||
@ -274,16 +277,10 @@ public class LinkageProcessor extends AbstractProcessor {
|
|||||||
|
|
||||||
private Map<String, List<LinkageType>> getLinkagesOfType(TypeElement typeElement) {
|
private Map<String, List<LinkageType>> getLinkagesOfType(TypeElement typeElement) {
|
||||||
Map<String, List<LinkageType>> linkages = new HashMap<>();
|
Map<String, List<LinkageType>> linkages = new HashMap<>();
|
||||||
LinkageType superClassType = resolveSingle(typeElement.getSuperclass());
|
Stream.concat(Stream.of(typeElement.getSuperclass()), typeElement.getInterfaces().stream())
|
||||||
if (superClassType != null) {
|
.map(this::resolveSingle)
|
||||||
linkages.computeIfAbsent(superClassType.method(), s -> new ArrayList<>()).add(superClassType);
|
.filter(Objects::nonNull)
|
||||||
}
|
.forEach(linkageType -> linkages.computeIfAbsent(linkageType.method(), s -> new ArrayList<>()).add(linkageType));
|
||||||
for (TypeMirror typeMirror : typeElement.getInterfaces()) {
|
|
||||||
LinkageType interfaceType = resolveSingle(typeMirror);
|
|
||||||
if (interfaceType != null) {
|
|
||||||
linkages.computeIfAbsent(interfaceType.method(), s -> new ArrayList<>()).add(interfaceType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (linkages.size() == 1 && linkages.containsKey("unlink")) {
|
if (linkages.size() == 1 && linkages.containsKey("unlink")) {
|
||||||
linkages.put(plain_GENERIC.method(), Collections.singletonList(plain_GENERIC));
|
linkages.put(plain_GENERIC.method(), Collections.singletonList(plain_GENERIC));
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren