Skip to content

Commit

Permalink
Improve defaults detection and parsing, and add option for unknown de…
Browse files Browse the repository at this point in the history
…faults
  • Loading branch information
sschr15 committed Feb 16, 2024
1 parent 9a2da64 commit 00d053e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ public interface KotlinOptions {
@Type(Type.BOOLEAN)
String SHOW_PUBLIC_VISIBILITY = "kt-show-public";

@Name("Decompile Kotlin")
@Name("Enable Kotlin plugin")
@Description("Decompile Kotlin classes as Kotlin instead of Java")
@Type(Type.BOOLEAN)
String DECOMPILE_KOTLIN = "kt-decompile-kotlin";
String DECOMPILE_KOTLIN = "kt-enable";

@Name("Unknown default arg string")
@Description("String to use for unknown default arguments, or empty to not indicate defaults")
@Type(Type.STRING)
String UNKNOWN_DEFAULT_ARG_STRING = "kt-unknown-defaults";

static void addDefaults(PluginOptions.AddDefaults cons) {
cons.addDefault(SHOW_PUBLIC_VISIBILITY, "1");
cons.addDefault(DECOMPILE_KOTLIN, "1");
cons.addDefault(UNKNOWN_DEFAULT_ARG_STRING, "...");
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.vineflower.kotlin.struct;

import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.flow.DirectGraph;
import org.jetbrains.java.decompiler.modules.decompiler.flow.DirectNode;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
import org.jetbrains.java.decompiler.util.TextBuffer;
import org.vineflower.kotlin.KotlinOptions;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -18,29 +21,30 @@ private DefaultArgsMap(Map<KParameter, Exprent> map) {
this.map = map;
}

public static DefaultArgsMap from(MethodWrapper defaults, MethodWrapper calling, KParameter[] params, int startIndex) {
public static DefaultArgsMap from(MethodWrapper defaults, MethodWrapper calling, KParameter[] params) {
if (defaults == null) {
return new DefaultArgsMap(Map.of());
}

Map<KParameter, Exprent> map = new HashMap<>();

SequenceStatement sequence = ((SequenceStatement) defaults.root.getFirst());
for (Statement statement : sequence.getStats()) {
DirectGraph graph = defaults.getOrBuildGraph();
for (DirectNode node : graph.nodes) {
Statement statement = node.statement;
if (statement instanceof IfStatement) {
IfStatement ifStatement = (IfStatement) statement;
Exprent condition = ifStatement.getHeadexprent().getCondition();
if (!(condition instanceof FunctionExprent)) throw new IllegalStateException("Unexpected exprent type parsing default argument");
if (!(condition instanceof FunctionExprent)) continue;
FunctionExprent function = (FunctionExprent) condition;

if (!(function.getLstOperands().get(0) instanceof FunctionExprent)) throw new IllegalStateException("Unexpected exprent type parsing default argument");
if (!(function.getLstOperands().get(0) instanceof FunctionExprent)) continue;
FunctionExprent bitmask = (FunctionExprent) function.getLstOperands().get(0);

if (bitmask.getLstOperands().size() != 2) throw new IllegalStateException("Unexpected number of operands parsing default argument");
if (bitmask.getLstOperands().size() != 2) continue;
Exprent var = bitmask.getLstOperands().get(0);
Exprent mask = bitmask.getLstOperands().get(1);

if (!(var instanceof VarExprent) || !(mask instanceof ConstExprent)) throw new IllegalStateException("Unexpected exprent type parsing default argument");
if (!(var instanceof VarExprent) || !(mask instanceof ConstExprent)) continue;

int maskValue = ((ConstExprent) mask).getIntValue();
int maskIndex = 0;
Expand Down Expand Up @@ -71,13 +75,18 @@ public static DefaultArgsMap from(MethodWrapper defaults, MethodWrapper calling,

public TextBuffer toJava(KParameter parameter, int indent) {
TextBuffer buffer = new TextBuffer();
String argString = DecompilerContext.getProperty(KotlinOptions.UNKNOWN_DEFAULT_ARG_STRING).toString();

Exprent expr = map.get(parameter);
if (expr == null) {
return buffer.append("...");
if (!argString.isEmpty()) {
buffer.append(" = ").append(argString);
}

return buffer;
}

buffer.append(expr.toJava(indent));
buffer.append(" = ").append(expr.toJava(indent));

return buffer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,13 @@ public static Data parse(ClassesProcessor.ClassNode node) {

boolean isPrimary = !flags.isSecondary;

boolean isStatic = (method.methodStruct.getAccessFlags() & CodeConstants.ACC_STATIC) != 0;
StringBuilder defaultArgsDesc = new StringBuilder("(");
for (KParameter parameter : parameters) {
defaultArgsDesc.append(parameter.type);
}
defaultArgsDesc.append("ILkotlin/jvm/internal/DefaultConstructorMarker;)V");

DefaultArgsMap defaultArgs = DefaultArgsMap.from(wrapper.getMethodWrapper("<init>", defaultArgsDesc.toString()), method, parameters, isStatic ? 0 : 1);
DefaultArgsMap defaultArgs = DefaultArgsMap.from(wrapper.getMethodWrapper("<init>", defaultArgsDesc.toString()), method, parameters);

KConstructor kConstructor = new KConstructor(parameters, flags, method, isPrimary, defaultArgs, node);
constructors.put(method.methodStruct, kConstructor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,27 +162,40 @@ public static Map<StructMethod, KFunction> parse(ClassesProcessor.ClassNode node
}
}

List<KTypeParameter> typeParameters = function.getTypeParameterList().stream()
.map(typeParameter -> KTypeParameter.from(typeParameter, resolver))
.collect(Collectors.toList());

List<KType> contextReceiverTypes = function.getContextReceiverTypeList().stream()
.map(ctxType -> KType.from(ctxType, resolver))
.collect(Collectors.toList());

boolean isStatic = (method.methodStruct.getAccessFlags() & CodeConstants.ACC_STATIC) != 0;
String defaultArgsName = name + "$default";
StringBuilder defaultArgsDesc = new StringBuilder("(");
if (!isStatic) {
defaultArgsDesc.append("L").append(struct.qualifiedName).append(";");
}
if (receiverType != null) {
defaultArgsDesc.append(receiverType);
}
for (KParameter parameter : parameters) {
defaultArgsDesc.append(parameter.type);
if (parameter.type.typeParameterName != null) {
typeParameters.stream()
.filter(typeParameter -> typeParameter.name.equals(parameter.type.typeParameterName))
.findAny()
.map(typeParameter -> typeParameter.upperBounds)
.filter(bounds -> bounds.size() == 1)
.map(bounds -> bounds.get(0))
.ifPresentOrElse(defaultArgsDesc::append, () -> defaultArgsDesc.append("Ljava/lang/Object;"));
} else {
defaultArgsDesc.append(parameter.type);
}
}
defaultArgsDesc.append("ILjava/lang/Object;)");
defaultArgsDesc.append(returnType);

DefaultArgsMap defaultArgs = DefaultArgsMap.from(wrapper.getMethodWrapper(defaultArgsName, defaultArgsDesc.toString()), method, parameters, isStatic ? 0 : 1);

List<KTypeParameter> typeParameters = function.getTypeParameterList().stream()
.map(typeParameter -> KTypeParameter.from(typeParameter, resolver))
.collect(Collectors.toList());

List<KType> contextReceiverTypes = function.getContextReceiverTypeList().stream()
.map(ctxType -> KType.from(ctxType, resolver))
.collect(Collectors.toList());
DefaultArgsMap defaultArgs = DefaultArgsMap.from(wrapper.getMethodWrapper(defaultArgsName, defaultArgsDesc.toString()), method, parameters);

boolean knownOverride = flags.visibility != ProtoBuf.Visibility.PRIVATE
&& flags.visibility != ProtoBuf.Visibility.PRIVATE_TO_THIS
Expand Down Expand Up @@ -340,7 +353,6 @@ public TextBuffer stringify(int indent) {

parameter.stringify(indent + 1, buf);
if (parameter.flags.declaresDefault) {
buf.append(" = ");
buf.append(defaultArgs.toJava(parameter, indent + 1), node.classStruct.qualifiedName, methodKey);
}
}
Expand Down

0 comments on commit 00d053e

Please sign in to comment.