mirror of
https://github.com/zaaarf/lillero-processor.git
synced 2024-11-14 05:29:20 +01:00
feat: major rework of obfuscation system
This commit is contained in:
parent
9900e370a7
commit
d966e7a37b
7 changed files with 182 additions and 187 deletions
|
@ -40,7 +40,7 @@ import static ftbsc.lll.processor.tools.JavaPoetUtils.*;
|
||||||
*/
|
*/
|
||||||
@SupportedAnnotationTypes("ftbsc.lll.processor.annotations.Patch")
|
@SupportedAnnotationTypes("ftbsc.lll.processor.annotations.Patch")
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||||
@SupportedOptions({"mappingsFile", "badPracticeWarnings", "anonymousClassWarning", "obfuscateInjectorMetadata"})
|
@SupportedOptions({"mappingsFile", "anonymousClassWarning", "obfuscateInjectorMetadata"})
|
||||||
public class LilleroProcessor extends AbstractProcessor {
|
public class LilleroProcessor extends AbstractProcessor {
|
||||||
/**
|
/**
|
||||||
* A {@link Set} of {@link String}s that will contain the fully qualified names
|
* A {@link Set} of {@link String}s that will contain the fully qualified names
|
||||||
|
@ -52,13 +52,7 @@ public class LilleroProcessor extends AbstractProcessor {
|
||||||
* The {@link ObfuscationMapper} used to convert classes and variables
|
* The {@link ObfuscationMapper} used to convert classes and variables
|
||||||
* to their obfuscated equivalent. Will be null when no mapper is in use.
|
* to their obfuscated equivalent. Will be null when no mapper is in use.
|
||||||
*/
|
*/
|
||||||
private ObfuscationMapper mapper;
|
private ObfuscationMapper mapper = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the processor should issue warnings when compiling code adopting
|
|
||||||
* bad practices.
|
|
||||||
*/
|
|
||||||
public static boolean badPracticeWarnings = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the processor should issue warnings when compiling code anonymous
|
* Whether the processor should issue warnings when compiling code anonymous
|
||||||
|
@ -108,9 +102,6 @@ public class LilleroProcessor extends AbstractProcessor {
|
||||||
this.mapper = new ObfuscationMapper(new BufferedReader(new InputStreamReader(targetStream,
|
this.mapper = new ObfuscationMapper(new BufferedReader(new InputStreamReader(targetStream,
|
||||||
StandardCharsets.UTF_8)).lines());
|
StandardCharsets.UTF_8)).lines());
|
||||||
}
|
}
|
||||||
String warns = processingEnv.getOptions().get("badPracticeWarnings");
|
|
||||||
if(warns != null)
|
|
||||||
badPracticeWarnings = parseBooleanArg(warns);
|
|
||||||
String anonymousClassWarn = processingEnv.getOptions().get("anonymousClassWarning");
|
String anonymousClassWarn = processingEnv.getOptions().get("anonymousClassWarning");
|
||||||
if(anonymousClassWarn != null)
|
if(anonymousClassWarn != null)
|
||||||
anonymousClassWarning = parseBooleanArg(anonymousClassWarn);
|
anonymousClassWarning = parseBooleanArg(anonymousClassWarn);
|
||||||
|
@ -249,8 +240,15 @@ public class LilleroProcessor extends AbstractProcessor {
|
||||||
clazz.fqnObf, //use obf name, at runtime it will be obfuscated
|
clazz.fqnObf, //use obf name, at runtime it will be obfuscated
|
||||||
clazz.elem == null ? 0 : mapModifiers(clazz.elem.getModifiers())
|
clazz.elem == null ? 0 : mapModifiers(clazz.elem.getModifiers())
|
||||||
);
|
);
|
||||||
} else if(type == ProxyType.FIELD || type == ProxyType.METHOD)
|
} else if(type == ProxyType.FIELD)
|
||||||
appendMemberFinderDefinition(targetClass, proxyVar, null, null, constructorBuilder, this.processingEnv, this.mapper);
|
appendMemberFinderDefinition(
|
||||||
|
proxyVar,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
constructorBuilder,
|
||||||
|
this.processingEnv,
|
||||||
|
this.mapper
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//this will contain the classes to generate: the key is the class name
|
//this will contain the classes to generate: the key is the class name
|
||||||
|
@ -316,7 +314,6 @@ public class LilleroProcessor extends AbstractProcessor {
|
||||||
VariableElement finder = finderCandidates.get(0);
|
VariableElement finder = finderCandidates.get(0);
|
||||||
matchedMethodFinders.add(finder);
|
matchedMethodFinders.add(finder);
|
||||||
appendMemberFinderDefinition(
|
appendMemberFinderDefinition(
|
||||||
targetClass,
|
|
||||||
finder,
|
finder,
|
||||||
tg,
|
tg,
|
||||||
targetAnn,
|
targetAnn,
|
||||||
|
|
|
@ -8,23 +8,17 @@ import ftbsc.lll.processor.annotations.Target;
|
||||||
import ftbsc.lll.processor.tools.containers.ClassContainer;
|
import ftbsc.lll.processor.tools.containers.ClassContainer;
|
||||||
import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper;
|
import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper;
|
||||||
import ftbsc.lll.proxies.ProxyType;
|
import ftbsc.lll.proxies.ProxyType;
|
||||||
|
import ftbsc.lll.tools.DescriptorBuilder;
|
||||||
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.*;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.type.*;
|
||||||
import javax.lang.model.element.Modifier;
|
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.MirroredTypeException;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static ftbsc.lll.processor.tools.JavaPoetUtils.descriptorFromExecutableElement;
|
|
||||||
import static ftbsc.lll.processor.tools.JavaPoetUtils.descriptorFromType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of AST-related static utils that didn't really fit into the main class.
|
* Collection of AST-related static utils that didn't really fit into the main class.
|
||||||
*/
|
*/
|
||||||
|
@ -111,12 +105,129 @@ public class ASTUtils {
|
||||||
T ann, Function<T, Class<?>> classFunction, ProcessingEnvironment env) {
|
T ann, Function<T, Class<?>> classFunction, ProcessingEnvironment env) {
|
||||||
try {
|
try {
|
||||||
String fqn = classFunction.apply(ann).getCanonicalName();
|
String fqn = classFunction.apply(ann).getCanonicalName();
|
||||||
|
if(fqn == null)
|
||||||
|
fqn = "";
|
||||||
return env.getElementUtils().getTypeElement(fqn).asType();
|
return env.getElementUtils().getTypeElement(fqn).asType();
|
||||||
} catch(MirroredTypeException e) {
|
} catch(MirroredTypeException e) {
|
||||||
return e.getTypeMirror();
|
return e.getTypeMirror();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the internal name from an {@link Element}.
|
||||||
|
* @param elem the {@link Element} in question
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
|
* @return the internal name at compile time, or null if it wasn't a qualifiable
|
||||||
|
* @since 0.5.1
|
||||||
|
*/
|
||||||
|
public static String internalNameFromElement(Element elem, ProcessingEnvironment env) {
|
||||||
|
//needed to actually turn elem into a TypeVariable, find it ignoring generics
|
||||||
|
elem = env.getElementUtils().getTypeElement(elem.asType().toString().split("<")[0]);
|
||||||
|
StringBuilder fqnBuilder = new StringBuilder();
|
||||||
|
while(elem.getEnclosingElement() != null && elem.getEnclosingElement().getKind() != ElementKind.PACKAGE) {
|
||||||
|
fqnBuilder
|
||||||
|
.insert(0, elem.getSimpleName().toString())
|
||||||
|
.insert(0, "$");
|
||||||
|
elem = elem.getEnclosingElement();
|
||||||
|
}
|
||||||
|
return fqnBuilder.insert(0, elem.asType().toString()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the descriptor from an {@link Element}.
|
||||||
|
* In particular, it will ensure to conver the internal class name to the
|
||||||
|
* one used at compile time
|
||||||
|
* @param elem the {@link Element} in question
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
|
* @return the descriptor
|
||||||
|
* @since 0.5.1
|
||||||
|
*/
|
||||||
|
public static String descriptorFromElement(Element elem, ProcessingEnvironment env) {
|
||||||
|
if(elem instanceof ExecutableElement)
|
||||||
|
return descriptorFromExecutableElement((ExecutableElement) elem, env);
|
||||||
|
|
||||||
|
TypeMirror tk = elem.asType();
|
||||||
|
int arrayLevel = 0;
|
||||||
|
while(tk.getKind() == TypeKind.ARRAY) {
|
||||||
|
tk = ((ArrayType) tk).getComponentType();
|
||||||
|
arrayLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tk.getKind() != TypeKind.DECLARED)
|
||||||
|
return descriptorFromType(elem.asType(), env);
|
||||||
|
|
||||||
|
return DescriptorBuilder.nameToDescriptor(internalNameFromElement(elem, env), arrayLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a type descriptor from the given {@link TypeMirror}.
|
||||||
|
* @param t the {@link TypeMirror} representing the desired type
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
|
* @return a {@link String} containing the relevant descriptor
|
||||||
|
*/
|
||||||
|
public static String descriptorFromType(TypeMirror t, ProcessingEnvironment env) {
|
||||||
|
StringBuilder desc = new StringBuilder();
|
||||||
|
//add array brackets
|
||||||
|
while(t.getKind() == TypeKind.ARRAY) {
|
||||||
|
desc.append("[");
|
||||||
|
t = ((ArrayType) t).getComponentType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(t.getKind() == TypeKind.TYPEVAR)
|
||||||
|
t = ((TypeVariable) t).getUpperBound();
|
||||||
|
|
||||||
|
if(t.getKind() == TypeKind.DECLARED)
|
||||||
|
return descriptorFromElement(env.getTypeUtils().asElement(t), env);
|
||||||
|
|
||||||
|
|
||||||
|
switch(t.getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
desc.append("Z");
|
||||||
|
break;
|
||||||
|
case CHAR:
|
||||||
|
desc.append("C");
|
||||||
|
break;
|
||||||
|
case BYTE:
|
||||||
|
desc.append("B");
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
desc.append("S");
|
||||||
|
break;
|
||||||
|
case INT:
|
||||||
|
desc.append("I");
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
desc.append("F");
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
desc.append("J");
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
desc.append("D");
|
||||||
|
break;
|
||||||
|
case VOID:
|
||||||
|
desc.append("V");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a method descriptor from the given {@link ExecutableElement}.
|
||||||
|
* @param m the {@link ExecutableElement} for the method
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
|
* @return a {@link String} containing the relevant descriptor
|
||||||
|
*/
|
||||||
|
public static String descriptorFromExecutableElement(ExecutableElement m, ProcessingEnvironment env) {
|
||||||
|
StringBuilder methodSignature = new StringBuilder();
|
||||||
|
methodSignature.append("(");
|
||||||
|
m.getParameters().forEach(p -> methodSignature.append(descriptorFromType(p.asType(), env)));
|
||||||
|
methodSignature.append(")");
|
||||||
|
methodSignature.append(descriptorFromType(m.getReturnType(), env));
|
||||||
|
return methodSignature.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the class name and maps it to the correct format.
|
* Finds the class name and maps it to the correct format.
|
||||||
* @param name the fully qualified name of the class to convert
|
* @param name the fully qualified name of the class to convert
|
||||||
|
@ -156,12 +267,15 @@ public class ASTUtils {
|
||||||
* @param descr the descriptor to search for, or null if it's not a method
|
* @param descr the descriptor to search for, or null if it's not a method
|
||||||
* @param strict whether to perform lookup in strict mode (see {@link Target#strict()} for more information)
|
* @param strict whether to perform lookup in strict mode (see {@link Target#strict()} for more information)
|
||||||
* @param field whether the member being searched is a field
|
* @param field whether the member being searched is a field
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
* @return the desired member, if it exists
|
* @return the desired member, if it exists
|
||||||
* @throws AmbiguousDefinitionException if it finds more than one candidate
|
* @throws AmbiguousDefinitionException if it finds more than one candidate
|
||||||
* @throws TargetNotFoundException if it finds no valid candidate
|
* @throws TargetNotFoundException if it finds no valid candidate
|
||||||
* @since 0.3.0
|
* @since 0.3.0
|
||||||
*/
|
*/
|
||||||
public static Element findMember(ClassContainer parent, String name, String descr, boolean strict, boolean field) {
|
public static Element findMember(
|
||||||
|
ClassContainer parent, String name, String descr,
|
||||||
|
boolean strict, boolean field, ProcessingEnvironment env) {
|
||||||
if(parent.elem == null)
|
if(parent.elem == null)
|
||||||
throw new TargetNotFoundException("parent class", parent.fqn);
|
throw new TargetNotFoundException("parent class", parent.fqn);
|
||||||
//try to find by name
|
//try to find by name
|
||||||
|
@ -185,14 +299,14 @@ public class ASTUtils {
|
||||||
if(field) {
|
if(field) {
|
||||||
//fields can verify the signature for extra safety
|
//fields can verify the signature for extra safety
|
||||||
//but there can only be 1 field with a given name
|
//but there can only be 1 field with a given name
|
||||||
if(!descriptorFromType(candidates.get(0).asType()).equals(descr))
|
if(!descriptorFromElement(candidates.get(0), env).equals(descr))
|
||||||
throw new TargetNotFoundException("field", String.format("%s with descriptor %s", name, descr), parent.fqn);
|
throw new TargetNotFoundException("field", String.format("%s with descriptor %s", name, descr), parent.fqn);
|
||||||
} else {
|
} else {
|
||||||
candidates = candidates.stream()
|
candidates = candidates.stream()
|
||||||
.map(e -> (ExecutableElement) e)
|
.map(e -> (ExecutableElement) e)
|
||||||
.filter(strict
|
.filter(strict
|
||||||
? c -> descr.equals(descriptorFromExecutableElement(c))
|
? c -> descr.equals(descriptorFromExecutableElement(c, env))
|
||||||
: c -> descr.split("\\)")[0].equalsIgnoreCase(descriptorFromExecutableElement(c).split("\\)")[0])
|
: c -> descr.split("\\)")[0].equalsIgnoreCase(descriptorFromExecutableElement(c, env).split("\\)")[0])
|
||||||
).collect(Collectors.toList());
|
).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if(candidates.size() == 0)
|
if(candidates.size() == 0)
|
||||||
|
|
|
@ -10,14 +10,12 @@ import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper;
|
||||||
import ftbsc.lll.proxies.ProxyType;
|
import ftbsc.lll.proxies.ProxyType;
|
||||||
import ftbsc.lll.proxies.impl.FieldProxy;
|
import ftbsc.lll.proxies.impl.FieldProxy;
|
||||||
import ftbsc.lll.proxies.impl.MethodProxy;
|
import ftbsc.lll.proxies.impl.MethodProxy;
|
||||||
import ftbsc.lll.tools.DescriptorBuilder;
|
|
||||||
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
@ -43,70 +41,8 @@ public class JavaPoetUtils {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a type descriptor from the given {@link TypeName}.
|
|
||||||
* @param type the {@link TypeName} representing the desired type
|
|
||||||
* @return a {@link String} containing the relevant descriptor
|
|
||||||
*/
|
|
||||||
public static String descriptorFromType(TypeName type) {
|
|
||||||
StringBuilder desc = new StringBuilder();
|
|
||||||
//add array brackets
|
|
||||||
while(type instanceof ArrayTypeName) {
|
|
||||||
desc.append("[");
|
|
||||||
type = ((ArrayTypeName) type).componentType;
|
|
||||||
}
|
|
||||||
if(type instanceof ClassName || type instanceof ParameterizedTypeName) {
|
|
||||||
ClassName var = type instanceof ParameterizedTypeName ? ((ParameterizedTypeName) type).rawType : (ClassName) type;
|
|
||||||
desc.append(DescriptorBuilder.nameToDescriptor(var.canonicalName(), 0));
|
|
||||||
} else {
|
|
||||||
if(TypeName.BOOLEAN.equals(type))
|
|
||||||
desc.append("Z");
|
|
||||||
else if(TypeName.CHAR.equals(type))
|
|
||||||
desc.append("C");
|
|
||||||
else if(TypeName.BYTE.equals(type))
|
|
||||||
desc.append("B");
|
|
||||||
else if(TypeName.SHORT.equals(type))
|
|
||||||
desc.append("S");
|
|
||||||
else if(TypeName.INT.equals(type))
|
|
||||||
desc.append("I");
|
|
||||||
else if(TypeName.FLOAT.equals(type))
|
|
||||||
desc.append("F");
|
|
||||||
else if(TypeName.LONG.equals(type))
|
|
||||||
desc.append("J");
|
|
||||||
else if(TypeName.DOUBLE.equals(type))
|
|
||||||
desc.append("D");
|
|
||||||
else if(TypeName.VOID.equals(type))
|
|
||||||
desc.append("V");
|
|
||||||
}
|
|
||||||
return desc.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a type descriptor from the given {@link TypeMirror}.
|
|
||||||
* @param t the {@link TypeMirror} representing the desired type
|
|
||||||
* @return a {@link String} containing the relevant descriptor
|
|
||||||
*/
|
|
||||||
public static String descriptorFromType(TypeMirror t) {
|
|
||||||
return descriptorFromType(TypeName.get(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a method descriptor from the given {@link ExecutableElement}.
|
|
||||||
* @param m the {@link ExecutableElement} for the method
|
|
||||||
* @return a {@link String} containing the relevant descriptor
|
|
||||||
*/
|
|
||||||
public static String descriptorFromExecutableElement(ExecutableElement m) {
|
|
||||||
StringBuilder methodSignature = new StringBuilder();
|
|
||||||
methodSignature.append("(");
|
|
||||||
m.getParameters().forEach(p -> methodSignature.append(descriptorFromType(p.asType())));
|
|
||||||
methodSignature.append(")");
|
|
||||||
methodSignature.append(descriptorFromType(m.getReturnType()));
|
|
||||||
return methodSignature.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends to a given {@link MethodSpec.Builder} definitions for a proxy.
|
* Appends to a given {@link MethodSpec.Builder} definitions for a proxy.
|
||||||
* @param fallback the {@link ClassContainer} to fall back on
|
|
||||||
* @param var the {@link VariableElement} representing the proxy
|
* @param var the {@link VariableElement} representing the proxy
|
||||||
* @param stub the stub {@link ExecutableElement} if present or relevant, null otherwise
|
* @param stub the stub {@link ExecutableElement} if present or relevant, null otherwise
|
||||||
* @param t the {@link Target} relevant to this finder if present or relevant, null otherwise
|
* @param t the {@link Target} relevant to this finder if present or relevant, null otherwise
|
||||||
|
@ -116,7 +52,7 @@ public class JavaPoetUtils {
|
||||||
* @since 0.5.0
|
* @since 0.5.0
|
||||||
*/
|
*/
|
||||||
public static void appendMemberFinderDefinition(
|
public static void appendMemberFinderDefinition(
|
||||||
ClassContainer fallback, VariableElement var, ExecutableElement stub, Target t,
|
VariableElement var, ExecutableElement stub, Target t,
|
||||||
MethodSpec.Builder con, ProcessingEnvironment env, ObfuscationMapper mapper) {
|
MethodSpec.Builder con, ProcessingEnvironment env, ObfuscationMapper mapper) {
|
||||||
ProxyType type = getProxyType(var);
|
ProxyType type = getProxyType(var);
|
||||||
if(type != ProxyType.METHOD && type != ProxyType.FIELD)
|
if(type != ProxyType.METHOD && type != ProxyType.FIELD)
|
||||||
|
|
|
@ -13,8 +13,7 @@ import java.lang.annotation.Annotation;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static ftbsc.lll.processor.tools.ASTUtils.findClassName;
|
import static ftbsc.lll.processor.tools.ASTUtils.*;
|
||||||
import static ftbsc.lll.processor.tools.ASTUtils.getTypeFromAnnotation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for information about a class.
|
* Container for information about a class.
|
||||||
|
@ -49,14 +48,17 @@ public class ClassContainer {
|
||||||
*/
|
*/
|
||||||
public ClassContainer(String fqn, String[] innerNames, ProcessingEnvironment env, ObfuscationMapper mapper) {
|
public ClassContainer(String fqn, String[] innerNames, ProcessingEnvironment env, ObfuscationMapper mapper) {
|
||||||
//find and validate
|
//find and validate
|
||||||
Element elem = env.getElementUtils().getTypeElement(fqn); //use unobfuscated name
|
Element elem = env.getElementUtils().getTypeElement(fqn);
|
||||||
|
|
||||||
if(elem == null)
|
if(elem == null)
|
||||||
throw new TargetNotFoundException("class", fqn);
|
throw new TargetNotFoundException("class", fqn);
|
||||||
|
|
||||||
|
StringBuilder fqnBuilder = new StringBuilder(internalNameFromElement(elem, env));
|
||||||
|
|
||||||
if(innerNames != null) {
|
if(innerNames != null) {
|
||||||
StringBuilder newFQN = new StringBuilder(fqn);
|
|
||||||
for(String inner : innerNames) {
|
for(String inner : innerNames) {
|
||||||
newFQN.append("$").append(inner);
|
if(inner == null) continue;
|
||||||
|
fqnBuilder.append("$").append(inner);
|
||||||
try {
|
try {
|
||||||
int anonClassCounter = Integer.parseInt(inner);
|
int anonClassCounter = Integer.parseInt(inner);
|
||||||
//anonymous classes cannot be validated!
|
//anonymous classes cannot be validated!
|
||||||
|
@ -65,7 +67,7 @@ public class ClassContainer {
|
||||||
Diagnostic.Kind.WARNING,
|
Diagnostic.Kind.WARNING,
|
||||||
String.format(
|
String.format(
|
||||||
"Anonymous classes cannot be verified by the processor. The existence of %s$%s is not guaranteed!",
|
"Anonymous classes cannot be verified by the processor. The existence of %s$%s is not guaranteed!",
|
||||||
fqn, anonClassCounter
|
fqnBuilder, anonClassCounter
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
elem = null;
|
elem = null;
|
||||||
|
@ -82,8 +84,9 @@ public class ClassContainer {
|
||||||
if(elem == null)
|
if(elem == null)
|
||||||
throw new TargetNotFoundException("class", inner);
|
throw new TargetNotFoundException("class", inner);
|
||||||
}
|
}
|
||||||
this.fqn = newFQN.toString();
|
}
|
||||||
} else this.fqn = fqn;
|
|
||||||
|
this.fqn = fqnBuilder.toString();
|
||||||
this.fqnObf = findClassName(this.fqn, mapper);
|
this.fqnObf = findClassName(this.fqn, mapper);
|
||||||
this.elem = elem;
|
this.elem = elem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,7 @@ import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
import static ftbsc.lll.processor.tools.ASTUtils.*;
|
import static ftbsc.lll.processor.tools.ASTUtils.*;
|
||||||
import static ftbsc.lll.processor.tools.JavaPoetUtils.descriptorFromExecutableElement;
|
import static ftbsc.lll.processor.tools.ASTUtils.descriptorFromType;
|
||||||
import static ftbsc.lll.processor.tools.JavaPoetUtils.descriptorFromType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for information about a field.
|
* Container for information about a field.
|
||||||
|
@ -45,8 +44,6 @@ public class FieldContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ClassContainer} representing the parent of this field.
|
* The {@link ClassContainer} representing the parent of this field.
|
||||||
* May be null if the parent is a class type that can not be checked
|
|
||||||
* at processing time (such as an anonymous class)
|
|
||||||
*/
|
*/
|
||||||
public final ClassContainer parent;
|
public final ClassContainer parent;
|
||||||
|
|
||||||
|
@ -62,9 +59,12 @@ public class FieldContainer {
|
||||||
* @param parent the {@link ClassContainer} representing the parent
|
* @param parent the {@link ClassContainer} representing the parent
|
||||||
* @param name the fully-qualified name of the target field
|
* @param name the fully-qualified name of the target field
|
||||||
* @param descriptor the descriptor of the target field, may be null for verifiable fields
|
* @param descriptor the descriptor of the target field, may be null for verifiable fields
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
* @param mapper the {@link ObfuscationMapper} to be used, may be null
|
* @param mapper the {@link ObfuscationMapper} to be used, may be null
|
||||||
*/
|
*/
|
||||||
public FieldContainer(ClassContainer parent, String name, String descriptor, ObfuscationMapper mapper) {
|
public FieldContainer(
|
||||||
|
ClassContainer parent, String name, String descriptor,
|
||||||
|
ProcessingEnvironment env, ObfuscationMapper mapper) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
if(parent.elem == null) { //unverified
|
if(parent.elem == null) { //unverified
|
||||||
if(descriptor == null)
|
if(descriptor == null)
|
||||||
|
@ -72,13 +72,12 @@ public class FieldContainer {
|
||||||
this.elem = null;
|
this.elem = null;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
this.descriptorObf = mapper == null ? this.descriptor : mapper.obfuscateType(Type.getType(this.descriptor)).getDescriptor();
|
|
||||||
} else {
|
} else {
|
||||||
this.elem = (VariableElement) findMember(parent, name, descriptor, descriptor != null, true);
|
this.elem = (VariableElement) findMember(parent, name, descriptor, descriptor != null, true, env);
|
||||||
this.name = this.elem.getSimpleName().toString();
|
this.name = this.elem.getSimpleName().toString();
|
||||||
this.descriptor = descriptorFromType(this.elem.asType());
|
this.descriptor = descriptorFromElement(this.elem, env);
|
||||||
this.descriptorObf = mapper == null ? this.descriptor : mapper.obfuscateType(Type.getType(this.descriptor)).getDescriptor();
|
|
||||||
}
|
}
|
||||||
|
this.descriptorObf = mapper == null ? this.descriptor : mapper.obfuscateType(Type.getType(this.descriptor)).getDescriptor();
|
||||||
this.nameObf = findMemberName(parent.fqnObf, this.name, null, mapper);
|
this.nameObf = findMemberName(parent.fqnObf, this.name, null, mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,20 +103,17 @@ public class FieldContainer {
|
||||||
String name = f.name().equals("") ? finder.getSimpleName().toString() : f.name();
|
String name = f.name().equals("") ? finder.getSimpleName().toString() : f.name();
|
||||||
String descriptor;
|
String descriptor;
|
||||||
TypeMirror fieldType = getTypeFromAnnotation(f, Find::type, env);
|
TypeMirror fieldType = getTypeFromAnnotation(f, Find::type, env);
|
||||||
if(fieldType.toString().equals("java.lang.Object"))
|
if(fieldType.toString().equals("java.lang.Object")) {
|
||||||
descriptor = null;
|
descriptor = null;
|
||||||
else {
|
} else {
|
||||||
if(fieldType.getKind() == TypeKind.DECLARED)
|
if(fieldType.getKind() != TypeKind.VOID && !fieldType.getKind().isPrimitive())
|
||||||
descriptor = //jank af but this is temporary anyway
|
descriptor = //jank af but this is temporary anyway
|
||||||
"L" + new ClassContainer(
|
"L" + ClassContainer.from(
|
||||||
fieldType.toString(),
|
f, Find::type, f.typeInner(), env, mapper
|
||||||
f.typeInner().equals("") ? null : f.typeInner().split("//$"),
|
).fqnObf.replace('.', '/') + ";";
|
||||||
env,
|
else descriptor = descriptorFromType(fieldType, env);
|
||||||
mapper
|
|
||||||
).fqn.replace('.', '/') + ";";
|
|
||||||
else descriptor = descriptorFromType(fieldType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FieldContainer(parent, name, descriptor, mapper);
|
return new FieldContainer(parent, name, descriptor, env, mapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@ package ftbsc.lll.processor.tools.containers;
|
||||||
|
|
||||||
import ftbsc.lll.exceptions.AmbiguousDefinitionException;
|
import ftbsc.lll.exceptions.AmbiguousDefinitionException;
|
||||||
import ftbsc.lll.exceptions.TargetNotFoundException;
|
import ftbsc.lll.exceptions.TargetNotFoundException;
|
||||||
import ftbsc.lll.processor.LilleroProcessor;
|
|
||||||
import ftbsc.lll.processor.annotations.Find;
|
import ftbsc.lll.processor.annotations.Find;
|
||||||
import ftbsc.lll.processor.annotations.Patch;
|
import ftbsc.lll.processor.annotations.Patch;
|
||||||
import ftbsc.lll.processor.annotations.Target;
|
import ftbsc.lll.processor.annotations.Target;
|
||||||
|
@ -10,11 +9,8 @@ import ftbsc.lll.processor.tools.obfuscation.ObfuscationMapper;
|
||||||
|
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.tools.Diagnostic;
|
|
||||||
|
|
||||||
import static ftbsc.lll.processor.tools.ASTUtils.findMember;
|
import static ftbsc.lll.processor.tools.ASTUtils.*;
|
||||||
import static ftbsc.lll.processor.tools.ASTUtils.findMemberName;
|
|
||||||
import static ftbsc.lll.processor.tools.JavaPoetUtils.descriptorFromExecutableElement;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for information about a method.
|
* Container for information about a method.
|
||||||
|
@ -46,8 +42,6 @@ public class MethodContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ClassContainer} representing the parent of this method.
|
* The {@link ClassContainer} representing the parent of this method.
|
||||||
* May be null if the parent is a class type that can not be checked
|
|
||||||
* at processing time (such as an anonymous class)
|
|
||||||
*/
|
*/
|
||||||
public final ClassContainer parent;
|
public final ClassContainer parent;
|
||||||
|
|
||||||
|
@ -64,9 +58,12 @@ public class MethodContainer {
|
||||||
* @param name the fully-qualified name of the target method
|
* @param name the fully-qualified name of the target method
|
||||||
* @param descriptor the descriptor of the target method
|
* @param descriptor the descriptor of the target method
|
||||||
* @param strict whether the matching should be strict (see {@link Target#strict()} for more info).
|
* @param strict whether the matching should be strict (see {@link Target#strict()} for more info).
|
||||||
|
* @param env the {@link ProcessingEnvironment} to perform the operation in
|
||||||
* @param mapper the {@link ObfuscationMapper} to be used, may be null
|
* @param mapper the {@link ObfuscationMapper} to be used, may be null
|
||||||
*/
|
*/
|
||||||
public MethodContainer(ClassContainer parent, String name, String descriptor, boolean strict, ObfuscationMapper mapper) {
|
public MethodContainer(
|
||||||
|
ClassContainer parent, String name, String descriptor,
|
||||||
|
boolean strict, ProcessingEnvironment env, ObfuscationMapper mapper) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
if(parent.elem == null) { //unverified
|
if(parent.elem == null) { //unverified
|
||||||
if(descriptor == null)
|
if(descriptor == null)
|
||||||
|
@ -74,13 +71,12 @@ public class MethodContainer {
|
||||||
this.elem = null;
|
this.elem = null;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
this.descriptorObf = mapper == null ? this.descriptor : mapper.obfuscateMethodDescriptor(this.descriptor);
|
|
||||||
} else {
|
} else {
|
||||||
this.elem = (ExecutableElement) findMember(parent, name, descriptor, descriptor != null && strict, false);
|
this.elem = (ExecutableElement) findMember(parent, name, descriptor, descriptor != null && strict, false, env);
|
||||||
this.name = this.elem.getSimpleName().toString();
|
this.name = this.elem.getSimpleName().toString();
|
||||||
this.descriptor = descriptorFromExecutableElement(this.elem);
|
this.descriptor = descriptorFromExecutableElement(this.elem, env);
|
||||||
this.descriptorObf = mapper == null ? this.descriptor : mapper.obfuscateMethodDescriptor(this.descriptor);
|
|
||||||
}
|
}
|
||||||
|
this.descriptorObf = mapper == null ? this.descriptor : mapper.obfuscateMethodDescriptor(this.descriptor);
|
||||||
this.nameObf = findMemberName(parent.fqn, this.name, this.descriptor, mapper);
|
this.nameObf = findMemberName(parent.fqn, this.name, this.descriptor, mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,20 +100,13 @@ public class MethodContainer {
|
||||||
f, env, mapper
|
f, env, mapper
|
||||||
);
|
);
|
||||||
|
|
||||||
String name, descriptor;
|
String name = t != null && !t.methodName().equals("")
|
||||||
if(f != null && !f.name().equals("")) { //match by name alone
|
? t.methodName() //name was specified in target
|
||||||
if(LilleroProcessor.badPracticeWarnings) //warn user that he is doing bad stuff
|
: stub.getSimpleName().toString();
|
||||||
env.getMessager().printMessage(Diagnostic.Kind.WARNING,
|
String descriptor = t != null && t.strict()
|
||||||
String.format("Matching method %s by name, this is bad practice and may lead to unexpected behaviour. Use @Target stubs instead!", f.name()));
|
? descriptorFromExecutableElement(stub, env)
|
||||||
name = f.name();
|
: null;
|
||||||
descriptor = null;
|
|
||||||
} else {
|
|
||||||
if(t != null && !t.methodName().equals(""))
|
|
||||||
name = t.methodName(); //name was specified in target
|
|
||||||
else name = stub.getSimpleName().toString();
|
|
||||||
descriptor = t != null && t.strict() ? descriptorFromExecutableElement(stub) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MethodContainer(parent, name, descriptor, t != null && t.strict(), mapper);
|
return new MethodContainer(parent, name, descriptor, t != null && t.strict(), env, mapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,6 +39,7 @@ public class ObfuscationMapper {
|
||||||
public ObfuscationMapper(Stream<String> str) {
|
public ObfuscationMapper(Stream<String> str) {
|
||||||
AtomicReference<String> currentClass = new AtomicReference<>("");
|
AtomicReference<String> currentClass = new AtomicReference<>("");
|
||||||
str.forEach(l -> {
|
str.forEach(l -> {
|
||||||
|
if(l == null) return;
|
||||||
if(l.startsWith("\t"))
|
if(l.startsWith("\t"))
|
||||||
mapper.get(currentClass.get()).addMember(l);
|
mapper.get(currentClass.get()).addMember(l);
|
||||||
else {
|
else {
|
||||||
|
@ -63,18 +64,6 @@ public class ObfuscationMapper {
|
||||||
else return data.obf;
|
else return data.obf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unobfuscated name of the class.
|
|
||||||
* Due to how it's implemented, it's considerably less efficient than its
|
|
||||||
* opposite operation.
|
|
||||||
* @param obfName the obfuscated internal name of the desired class
|
|
||||||
* @return the deobfuscated name of the class
|
|
||||||
*/
|
|
||||||
public String deobfuscateClass(String obfName) {
|
|
||||||
ObfuscationData data = getObfuscationData(obfName);
|
|
||||||
return data.unobf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the obfuscated name of a class member (field or method).
|
* Gets the obfuscated name of a class member (field or method).
|
||||||
* The method signature must be in this format: "methodName methodDescriptor",
|
* The method signature must be in this format: "methodName methodDescriptor",
|
||||||
|
@ -141,35 +130,6 @@ public class ObfuscationMapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unobfuscated name of the given member.
|
|
||||||
* Due to how it's implemented, it's considerably less efficient than its
|
|
||||||
* opposite operation.
|
|
||||||
* @param parentObf the obfuscated internal name of the container class
|
|
||||||
* @param memberObf the field name or method signature
|
|
||||||
* @return the deobfuscated name of the given member
|
|
||||||
*/
|
|
||||||
public String deobfuscateMember(String parentObf, String memberObf) {
|
|
||||||
ObfuscationData data = getObfuscationData(parentObf);
|
|
||||||
for(String unobf : data.members.keySet())
|
|
||||||
if(data.members.get(unobf).equals(memberObf))
|
|
||||||
return unobf;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally. Gets the obfuscation data corresponding to the given obfuscated class name.
|
|
||||||
* @param classObfuscatedName the internal name of the obfuscated class
|
|
||||||
* @return the desired {@link ObfuscationData} object
|
|
||||||
* @throws MappingNotFoundException if no {@link ObfuscationData} object is found
|
|
||||||
*/
|
|
||||||
private ObfuscationData getObfuscationData(String classObfuscatedName) {
|
|
||||||
for(ObfuscationData s : mapper.values())
|
|
||||||
if(s.obf.equals(classObfuscatedName))
|
|
||||||
return s;
|
|
||||||
throw new MappingNotFoundException(classObfuscatedName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private class used internally for storing information about each
|
* Private class used internally for storing information about each
|
||||||
* class. It's private because there is no good reason anyone would
|
* class. It's private because there is no good reason anyone would
|
||||||
|
|
Loading…
Reference in a new issue