Skip to content

Commit 793b687

Browse files
authored
Move metadata out of global state (#515)
* De-globalize Kotlin metadata * Add missing null checks * Move wrapper requirements to support earlier extra parsing * Pull higher-level objects into Kotlin metadata attribute
1 parent 376b155 commit 793b687

File tree

14 files changed

+497
-421
lines changed

14 files changed

+497
-421
lines changed

plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinChooser.java

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
import org.jetbrains.java.decompiler.util.Key;
1717
import org.vineflower.kotlin.metadata.BitEncoding;
1818
import org.vineflower.kotlin.metadata.MetadataNameResolver;
19+
import org.vineflower.kotlin.metadata.StructKotlinMetadataAttribute;
1920

2021
import java.io.ByteArrayInputStream;
21-
import java.util.Objects;
2222

2323
public class KotlinChooser implements LanguageChooser {
2424
private static final Key<?>[] ANNOTATION_ATTRIBUTES = {
@@ -32,31 +32,32 @@ public class KotlinChooser implements LanguageChooser {
3232

3333
@Override
3434
public boolean isLanguage(StructClass cl) {
35-
if (!DecompilerContext.getOption(KotlinOptions.DECOMPILE_KOTLIN)) {
35+
boolean decompEnabled = DecompilerContext.getOption(KotlinOptions.DECOMPILE_KOTLIN);
36+
if (!decompEnabled && !DecompilerContext.getOption(KotlinOptions.ALWAYS_EXPORT_METADATA)) {
3637
return false;
3738
}
3839

3940
// Try to find @Metadata()
40-
4141
for (Key<?> key : ANNOTATION_ATTRIBUTES) {
4242
if (cl.hasAttribute(key)) {
4343
StructAnnotationAttribute attr = cl.getAttribute((Key<StructAnnotationAttribute>) key);
4444
for (AnnotationExprent anno : attr.getAnnotations()) {
4545
if (anno.getClassName().equals("kotlin/Metadata")) {
46-
// Line removed as it slows down decompilation significantly, and it doesn't seem to break anything
47-
//TODO double-check if it breaks anything
48-
// setContextVariables(cl);
49-
return true;
46+
parseMetadataFor(cl);
47+
return decompEnabled;
5048
}
5149
}
5250
}
5351
}
5452

55-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, null);
5653
return false;
5754
}
5855

59-
public static void setContextVariables(StructClass cl) {
56+
public static void parseMetadataFor(StructClass cl) {
57+
if (cl.getAttribute(StructKotlinMetadataAttribute.KEY) != null) {
58+
return;
59+
}
60+
6061
AnnotationExprent anno = null;
6162

6263
loop:
@@ -78,62 +79,58 @@ public static void setContextVariables(StructClass cl) {
7879
int d2Index = anno.getParNames().indexOf("d2");
7980

8081
if (kIndex == -1) {
81-
DecompilerContext.getLogger().writeMessage("No k attribute in class metadata for class " + cl.qualifiedName, IFernflowerLogger.Severity.WARN);
82-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, null);
82+
DecompilerContext.getLogger().writeMessage("No k attribute (type) in class metadata for class " + cl.qualifiedName + ", cannot continue Kotlin parsing", IFernflowerLogger.Severity.WARN);
8383
return;
8484
}
8585

8686
if (d1Index == -1) {
87-
DecompilerContext.getLogger().writeMessage("No d1 attribute in class metadata for class " + cl.qualifiedName, IFernflowerLogger.Severity.WARN);
88-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, null);
87+
DecompilerContext.getLogger().writeMessage("No d1 attribute (data) in class metadata for class " + cl.qualifiedName + ", cannot continue Kotlin parsing", IFernflowerLogger.Severity.WARN);
8988
return;
9089
}
9190

9291
if (d2Index == -1) {
93-
DecompilerContext.getLogger().writeMessage("No d2 attribute in class metadata for class " + cl.qualifiedName, IFernflowerLogger.Severity.WARN);
94-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, null);
95-
return;
92+
DecompilerContext.getLogger().writeMessage("No d2 attribute (strings) in class metadata for class " + cl.qualifiedName, IFernflowerLogger.Severity.WARN);
9693
}
9794

9895
int k = (int) ((ConstExprent) anno.getParValues().get(kIndex)).getValue();
9996
Exprent d1 = anno.getParValues().get(d1Index);
100-
Exprent d2 = anno.getParValues().get(d2Index);
97+
Exprent d2 = d2Index != -1 ? anno.getParValues().get(d2Index) : null;
10198

10299
String[] data1 = getDataFromExpr((NewExprent) d1);
103100

104-
String[] data2 = getDataFromExpr((NewExprent) d2);
105-
106101
byte[] buf = BitEncoding.decodeBytes(data1);
107102

108103
ByteArrayInputStream input = new ByteArrayInputStream(buf);
109-
JvmProtoBuf.StringTableTypes types = JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, EXTENSIONS);
110104

111-
DecompilerContext.setProperty(KotlinDecompilationContext.NAME_RESOLVER, new MetadataNameResolver(types, data2));
105+
MetadataNameResolver resolver;
106+
if (d2 != null) {
107+
String[] data2 = getDataFromExpr((NewExprent) d2);
108+
JvmProtoBuf.StringTableTypes types = JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, EXTENSIONS);
109+
resolver = new MetadataNameResolver(types, data2);
110+
} else {
111+
resolver = null;
112+
}
112113

114+
StructKotlinMetadataAttribute.Metadata metadata;
113115
if (k == 1) { // Class file
114116
ProtoBuf.Class pcl = ProtoBuf.Class.parseFrom(input, EXTENSIONS);
115-
116-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, KotlinDecompilationContext.KotlinType.CLASS);
117-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_CLASS, pcl);
118-
117+
metadata = new StructKotlinMetadataAttribute.Class(cl, pcl);
119118
} else if (k == 2) { // File facade
120119
ProtoBuf.Package pcl = ProtoBuf.Package.parseFrom(input, EXTENSIONS);
121-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, KotlinDecompilationContext.KotlinType.FILE);
122-
DecompilerContext.setProperty(KotlinDecompilationContext.FILE_PACKAGE, pcl);
120+
metadata = new StructKotlinMetadataAttribute.File(cl, pcl);
123121
} else if (k == 3) { // Synthetic class
124122
ProtoBuf.Function func = ProtoBuf.Function.parseFrom(input, EXTENSIONS);
125-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, KotlinDecompilationContext.KotlinType.SYNTHETIC_CLASS);
126-
DecompilerContext.setProperty(KotlinDecompilationContext.SYNTHETIC_CLASS, func);
123+
metadata = new StructKotlinMetadataAttribute.SyntheticClass(cl, func);
127124
} else if (k == 5) { // Multi-file facade
128125
ProtoBuf.Package pcl = ProtoBuf.Package.parseFrom(input, EXTENSIONS);
129-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, KotlinDecompilationContext.KotlinType.MULTIFILE_CLASS);
130-
DecompilerContext.setProperty(KotlinDecompilationContext.MULTIFILE_PACKAGE, pcl);
126+
metadata = new StructKotlinMetadataAttribute.MultifileClass(cl, pcl);
131127
} else {
132-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, null);
128+
return;
133129
}
130+
131+
cl.getAttributes().put(StructKotlinMetadataAttribute.KEY.name, new StructKotlinMetadataAttribute(metadata, resolver));
134132
} catch (Exception e) {
135133
DecompilerContext.getLogger().writeMessage("Failed to parse metadata for class " + cl.qualifiedName, IFernflowerLogger.Severity.WARN, e);
136-
DecompilerContext.setProperty(KotlinDecompilationContext.CURRENT_TYPE, null);
137134
}
138135
}
139136

plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinDecompilationContext.java

Lines changed: 0 additions & 47 deletions
This file was deleted.

plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinOptions.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@ public interface KotlinOptions {
2424
@Description("Convert string concatenations to Kotlin string templates.")
2525
@Type(DecompilerOption.Type.BOOLEAN)
2626
String COLLAPSE_STRING_CONCATENATION = "kt-collapse-string-concat";
27+
28+
@Name("Always export metadata")
29+
@Description("If Kotlin decompilation is disabled, metadata will not be parsed. If enabled, this will always parse Kotlin metadata for use by other plugins.")
30+
@Type(DecompilerOption.Type.BOOLEAN)
31+
String ALWAYS_EXPORT_METADATA = "kt-export-metadata";
2732

2833
static void addDefaults(PluginOptions.AddDefaults cons) {
2934
cons.addDefault(SHOW_PUBLIC_VISIBILITY, "1");
3035
cons.addDefault(DECOMPILE_KOTLIN, "1");
3136
cons.addDefault(UNKNOWN_DEFAULT_ARG_STRING, "...");
3237
cons.addDefault(COLLAPSE_STRING_CONCATENATION, "1");
38+
cons.addDefault(ALWAYS_EXPORT_METADATA, "0");
3339
}
3440
}

plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinPlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.vineflower.kotlin;
22

33
import org.jetbrains.annotations.Nullable;
4+
import org.jetbrains.java.decompiler.api.ClassAttributeRegistry;
45
import org.jetbrains.java.decompiler.api.plugin.Plugin;
56
import org.jetbrains.java.decompiler.api.plugin.LanguageSpec;
67
import org.jetbrains.java.decompiler.api.plugin.PluginOptions;
@@ -11,6 +12,7 @@
1112
import org.jetbrains.java.decompiler.modules.decompiler.*;
1213
import org.jetbrains.java.decompiler.modules.decompiler.decompose.DomHelper;
1314
import org.jetbrains.java.decompiler.util.Pair;
15+
import org.vineflower.kotlin.metadata.StructKotlinMetadataAttribute;
1416
import org.vineflower.kotlin.pass.*;
1517

1618
public class KotlinPlugin implements Plugin {

0 commit comments

Comments
 (0)