Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add override annotation injector #10

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/main/java/de/oceanlabs/mcp/mcinjector/MCInjector.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class MCInjector
private Path excIn, excOut;
private Path accIn, accOut;
private Path ctrIn, ctrOut;
private Path overrides;
private LVTNaming lvt;

public MCInjector(Path fileIn, Path fileOut)
Expand Down Expand Up @@ -110,6 +111,12 @@ public MCInjector constructorsOut(Path out)
return this;
}

public MCInjector overrides(Path overrides)
{
this.overrides = overrides;
return this;
}

public MCInjector lvt(LVTNaming lvt)
{
this.lvt = lvt;
Expand All @@ -123,7 +130,7 @@ public void process() throws IOException
accIn, accOut,
ctrIn, ctrOut,
excIn, excOut,
lvt);
overrides, lvt);
}

private static ValueConverter<Path> PATH_ARG = new ValueConverter<Path>()
Expand Down Expand Up @@ -175,6 +182,7 @@ public static void main(String[] args) throws Exception
OptionSpec<Path> accOut = parser.accepts("accOut").withRequiredArg().withValuesConvertedBy(PATH_ARG);
OptionSpec<Path> ctr = parser.accepts("ctr") .withRequiredArg().withValuesConvertedBy(PATH_ARG);
OptionSpec<Path> ctrOut = parser.accepts("ctrOut").withRequiredArg().withValuesConvertedBy(PATH_ARG);
OptionSpec<Path> over = parser.accepts("overrides").withRequiredArg().withValuesConvertedBy(PATH_ARG);
OptionSpec<Level> logLvl = parser.accepts("level") .withRequiredArg().withValuesConvertedBy(LEVEL_ARG).defaultsTo(Level.INFO);
OptionSpec<LVTNaming> lvt = parser.accepts("lvt").withRequiredArg().ofType(LVTNaming.class).defaultsTo(LVTNaming.STRIP);

Expand Down Expand Up @@ -206,6 +214,7 @@ else if (o.has(ver))
LOG.info(" " + o.valueOf(accOut));
LOG.info("Constructors: " + o.valueOf(ctr));
LOG.info(" " + o.valueOf(ctrOut));
LOG.info("Overrides: " + o.valueOf(over));
LOG.info("LVT: " + o.valueOf(lvt));

try
Expand All @@ -220,6 +229,7 @@ else if (o.has(ver))
.accessOut(o.valueOf(accOut))
.constructors(o.valueOf(ctr))
.constructorsOut(o.valueOf(ctrOut))
.overrides(o.valueOf(over))
.process();
}
catch (Exception e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
import de.oceanlabs.mcp.mcinjector.adaptors.ApplyMap;
import de.oceanlabs.mcp.mcinjector.adaptors.InnerClassInitAdder;
import de.oceanlabs.mcp.mcinjector.adaptors.ParameterAnnotationFixer;
import de.oceanlabs.mcp.mcinjector.adaptors.OverrideAnnotationInjector;
import de.oceanlabs.mcp.mcinjector.data.Access;
import de.oceanlabs.mcp.mcinjector.data.Constructors;
import de.oceanlabs.mcp.mcinjector.data.Exceptions;
import de.oceanlabs.mcp.mcinjector.data.Overrides;
import de.oceanlabs.mcp.mcinjector.lvt.LVTFernflower;
import de.oceanlabs.mcp.mcinjector.lvt.LVTLvt;
import de.oceanlabs.mcp.mcinjector.lvt.LVTNaming;
Expand All @@ -49,7 +51,7 @@ static void process(
Path accIn, Path accOut,
Path ctrIn, Path ctrOut,
Path excIn, Path excOut,
LVTNaming naming)
Path overrides, LVTNaming naming)
throws IOException
{
if (accIn != null)
Expand All @@ -58,6 +60,8 @@ static void process(
Constructors.INSTANCE.load(ctrIn);
if (excIn != null)
Exceptions.INSTANCE.load(excIn);
if (overrides != null)
Overrides.INSTANCE.load(overrides);

MCInjector.LOG.info("Processing: " + in);
MCInjector.LOG.info(" Output: " + out);
Expand Down Expand Up @@ -176,6 +180,8 @@ public byte[] processClass(byte[] cls, boolean readOnly)
ca = new AccessFixer(ca);

ca = new ParameterAnnotationFixer(ca, this);

ca = new OverrideAnnotationInjector(ca);
}

ca = new InnerClassInitAdder(ca);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package de.oceanlabs.mcp.mcinjector.adaptors;

import de.oceanlabs.mcp.mcinjector.MCInjector;
import de.oceanlabs.mcp.mcinjector.MCInjectorImpl;
import de.oceanlabs.mcp.mcinjector.data.Overrides;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.ArrayList;
import java.util.Set;

public class OverrideAnnotationInjector extends ClassVisitor
{
private Set<String> overrides;
public OverrideAnnotationInjector(ClassVisitor cv)
{
super(Opcodes.ASM6, cv);
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
{
this.overrides = Overrides.INSTANCE.getOverrides(name);
super.visit(version, access, name, signature, superName, interfaces);
}

@Override
public void visitEnd()
{
super.visitEnd();
if (!this.overrides.isEmpty())
{
ClassNode cls = MCInjectorImpl.getClassNode(cv);
for (MethodNode mn : cls.methods)
{
if (this.overrides.contains(mn.name + " " + mn.desc))
{
MCInjector.LOG.fine(" Override annotation injected for " + cls.name + " " + mn.name + " " + mn.desc);
if (mn.invisibleAnnotations == null)
{
mn.invisibleAnnotations = new ArrayList<>(1);
}
mn.invisibleAnnotations.add(new AnnotationNode("Ljava/lang/Override;"));
}
}
}
}
}
60 changes: 60 additions & 0 deletions src/main/java/de/oceanlabs/mcp/mcinjector/data/Overrides.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package de.oceanlabs.mcp.mcinjector.data;

import de.oceanlabs.mcp.mcinjector.MCInjector;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public enum Overrides
{
INSTANCE;

private Map<String, Set<String>> classMemberOverrides = new HashMap<>();

public boolean load(Path file)
{
this.classMemberOverrides.clear();
try
{
MCInjector.LOG.fine("Loading Override list from: " + file);
Set<String> mthSet = null;
for(String line : Files.readAllLines(file))
{
line = line.trim();
if (line.isEmpty() || line.startsWith("#"))
continue;

String[] parts = line.split(" " );
if (parts[0].charAt(0) == '\t')
{
if (mthSet == null)
{
throw new IOException("Invalid TSRG line, missing class: " + line);
}
mthSet.add(parts[1] + " " + parts[2]);
}
else
{
mthSet = this.classMemberOverrides.computeIfAbsent(parts[0], k -> new HashSet<>());
}
}
}
catch (IOException e)
{
e.printStackTrace();
MCInjector.LOG.warning("Could not load Override list: " + e.toString());
return false;
}
return true;
}

public Set<String> getOverrides(String className)
{
return this.classMemberOverrides.getOrDefault(className, Collections.emptySet());
}
}