Skip to content

Commit

Permalink
Merge pull request #305 from Vineflower/develop/1.9.3
Browse files Browse the repository at this point in the history
Release 1.9.3
  • Loading branch information
jaskarth authored Sep 4, 2023
2 parents c537d08 + 67267ee commit 3482e13
Show file tree
Hide file tree
Showing 17 changed files with 232 additions and 122 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Vineflower's features include:
Examples of Vineflower's output, compared to other decompilers, can be found on [the wiki.](https://github.com/Vineflower/vineflower/wiki)

## Use
Want to use Vineflower? There are a few ways! For Fabric and Architectury projects, [Loom Quiltflower](https://github.com/Juuxel/LoomQuiltflower) allows you to run genSources with Vineflower.
Want to use Vineflower? There are a few ways! For Minecraft modding, [Loom Vineflower](https://github.com/Juuxel/loom-vineflower) allows you to generate sources with Vineflower.
The [Vineflower Intellij IDEA plugin](https://plugins.jetbrains.com/plugin/18032-quiltflower) replaces Fernflower in IDEA with Vineflower, and allows you to modify its settings.

If you want to run Vineflower from the commandline, head over to the [Releases tab](https://github.com/Vineflower/vineflower/releases) and grab the latest release.
Expand All @@ -19,7 +19,7 @@ You can then run Vineflower with `java -jar vineflower.jar <arguments> <source>
`<source>` can be a jar, zip, folder, or class file, and `<destination>` can be a folder, zip, jar, or excluded, to print to the console.


To use Vineflower as a library, you can find distributions on maven central.
To use Vineflower as a library, you can find distributions on maven central. Vineflower 1.9+ requires Java 11 or higher to run.
Vineflower can be imported with gradle with:
```groovy
dependencies {
Expand All @@ -45,4 +45,4 @@ Vineflower is a fork of both Jetbrains' Fernflower and MinecraftForge's ForgeFlo

* Jetbrains- For maintaining Fernflower
* Forge Team- For maintaining ForgeFlower
* CFR- For it's large suite of very useful tests
* CFR- For its large suite of very useful tests
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ compileJava {
group = 'org.vineflower'
archivesBaseName = 'vineflower'

version = '1.9.2'
version = '1.9.3'

def ENV = System.getenv()
version = version + (ENV.GITHUB_ACTIONS ? "" : "+local")
Expand Down
28 changes: 16 additions & 12 deletions src/org/jetbrains/java/decompiler/main/ClassWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,25 +115,29 @@ private static boolean invokeProcessors(TextBuffer buffer, ClassNode node) {
DecompilerContext.getLogger().writeMessage("Class " + node.simpleName + " couldn't be written.",
IFernflowerLogger.Severity.WARN,
t);
buffer.append("// $VF: Couldn't be decompiled");
buffer.appendLineSeparator();
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR)) {
List<String> lines = new ArrayList<>();
lines.addAll(ClassWriter.getErrorComment());
collectErrorLines(t, lines);
for (String line : lines) {
buffer.append("//");
if (!line.isEmpty()) buffer.append(' ').append(line);
buffer.appendLineSeparator();
}
}
writeException(buffer, t);

return false;
}

return true;
}

public static void writeException(TextBuffer buffer, Throwable t) {
buffer.append("// $VF: Couldn't be decompiled");
buffer.appendLineSeparator();
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR)) {
List<String> lines = new ArrayList<>();
lines.addAll(ClassWriter.getErrorComment());
collectErrorLines(t, lines);
for (String line : lines) {
buffer.append("//");
if (!line.isEmpty()) buffer.append(' ').append(line);
buffer.appendLineSeparator();
}
}
}

public void classLambdaToJava(ClassNode node, TextBuffer buffer, Exprent method_object, int indent) {
ClassWrapper wrapper = node.getWrapper();
if (wrapper == null) {
Expand Down
93 changes: 37 additions & 56 deletions src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,38 @@ else if (cl.superClass == null) { // neither interface nor super class defined
return true;
}

public void processClass(StructClass cl) throws IOException {
ClassNode root = mapRootClasses.get(cl.qualifiedName);
if (root.type != ClassNode.Type.ROOT) {
return;
}

boolean packageInfo = cl.isSynthetic() && "package-info".equals(root.simpleName);
boolean moduleInfo = cl.hasModifier(CodeConstants.ACC_MODULE) && cl.hasAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);

DecompilerContext.getLogger().startProcessingClass(cl.qualifiedName);
ImportCollector importCollector = new ImportCollector(root);
DecompilerContext.startClass(importCollector);
try {
if (!packageInfo && !moduleInfo) {
new LambdaProcessor().processClass(root);

// add simple class names to implicit import
addClassNameToImport(root, importCollector);

// build wrappers for all nested classes (that's where actual processing takes place)
initWrappers(root);

// Java specific last minute processing
new NestedClassProcessor().processClass(root, root);

new NestedMemberAccess().propagateMemberAccess(root);
}
} finally {
DecompilerContext.getLogger().endProcessingClass();
}
}

public void writeClass(StructClass cl, TextBuffer buffer) throws IOException {
ClassNode root = mapRootClasses.get(cl.qualifiedName);
if (root.type != ClassNode.Type.ROOT) {
Expand All @@ -409,76 +441,25 @@ public void writeClass(StructClass cl, TextBuffer buffer) throws IOException {

DecompilerContext.getLogger().startReadingClass(cl.qualifiedName);
try {
ImportCollector importCollector = new ImportCollector(root);
DecompilerContext.startClass(importCollector);

if (packageInfo) {
ClassWriter.packageInfoToJava(cl, buffer);

importCollector.writeImports(buffer, false);
DecompilerContext.getImportCollector().writeImports(buffer, false);
}
else if (moduleInfo) {
TextBuffer moduleBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
ClassWriter.moduleInfoToJava(cl, moduleBuffer);

importCollector.writeImports(buffer, true);
DecompilerContext.getImportCollector().writeImports(buffer, true);

buffer.append(moduleBuffer);
}
else {
try {
new LambdaProcessor().processClass(root);
} catch (Throwable t) {
DecompilerContext.getLogger().writeMessage("Class " + root.simpleName + " couldn't be written.",
IFernflowerLogger.Severity.WARN,
t);
buffer.append("// $VF: Couldn't be decompiled");
buffer.appendLineSeparator();
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR)) {
List<String> lines = new ArrayList<>();
lines.addAll(ClassWriter.getErrorComment());
ClassWriter.collectErrorLines(t, lines);
for (String line : lines) {
buffer.append("//");
if (!line.isEmpty()) buffer.append(' ').append(line);
buffer.appendLineSeparator();
}
}
return;
}

// add simple class names to implicit import
addClassNameToImport(root, importCollector);

// build wrappers for all nested classes (that's where actual processing takes place)
initWrappers(root);

try {
new NestedClassProcessor().processClass(root, root);

new NestedMemberAccess().propagateMemberAccess(root);
} catch (Throwable t) {
DecompilerContext.getLogger().writeMessage("Class " + root.simpleName + " couldn't be written.",
IFernflowerLogger.Severity.WARN,
t);
buffer.append("// $VF: Couldn't be decompiled");
buffer.appendLineSeparator();
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_EXCEPTION_ON_ERROR)) {
List<String> lines = new ArrayList<>();
lines.addAll(ClassWriter.getErrorComment());
ClassWriter.collectErrorLines(t, lines);
for (String line : lines) {
buffer.append("//");
if (!line.isEmpty()) buffer.append(' ').append(line);
buffer.appendLineSeparator();
}
}
return;
}

TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);

new ClassWriter().classToJava(root, classBuffer, 0);
classBuffer.reformat();

classBuffer.getTracers().forEach((classAndMethod, tracer) -> {
// get the class by name
StructClass clazz = DecompilerContext.getStructContext().getClass(classAndMethod.a);
Expand All @@ -500,7 +481,7 @@ else if (moduleInfo) {
buffer.append("package ").append(packageName).append(';').appendLineSeparator().appendLineSeparator();
}

importCollector.writeImports(buffer, true);
DecompilerContext.getImportCollector().writeImports(buffer, true);

int offsetLines = buffer.countLines();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ public static DecompilerContext getCurrentContext() {
}

public static void setCurrentContext(DecompilerContext context) {
currentContext.set(context);
if (context == null) {
currentContext.remove();
} else {
currentContext.set(context);
}
}

public static void setProperty(String key, Object value) {
Expand Down
12 changes: 9 additions & 3 deletions src/org/jetbrains/java/decompiler/main/Fernflower.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.jetbrains.java.decompiler.util.TextBuffer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -168,15 +169,20 @@ else if (converter != null) {
}
}

@Override
public void processClass(final StructClass cl) throws IOException {
classProcessor.processClass(cl); // unhandled exceptions handled later on
}

@Override
public String getClassContent(StructClass cl) {
TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);
try {
TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);
buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString());
classProcessor.writeClass(cl, buffer);
String res = buffer.convertToStringAndAllowDataDiscard();
if (res == null) {
return "$ FF: Unable to decompile class " + cl.qualifiedName;
return "$ VF: Unable to decompile class " + cl.qualifiedName;
}

return res;
Expand All @@ -190,7 +196,7 @@ public String getClassContent(StructClass cl) {
lines.addAll(ClassWriter.getErrorComment());
ClassWriter.collectErrorLines(t, lines);
lines.add("*/");
return String.join("\n", lines);
return String.join(DecompilerContext.getNewLineSeparator(), lines);
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ public void writeMessage(String message, Severity severity, Throwable t) {
}
}

public void startProcessingClass(String className) {
if (accepts(Severity.INFO)) {
writeMessage("Preprocessing class " + className, Severity.INFO);
indent.get().incrementAndGet();
}
}

@Override
public void endProcessingClass() {
if (accepts(Severity.INFO)) {
indent.get().decrementAndGet();
writeMessage("... done", Severity.INFO);
}
}

@Override
public void startReadingClass(String className) {
if (accepts(Severity.INFO)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public void writeMessage(String message, Throwable t) {
writeMessage(message, Severity.ERROR, t);
}

public void startProcessingClass(String className) { }

public void endProcessingClass() { }

public void startReadingClass(String className) { }

public void endReadingClass() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ else if (UNINLINED_DOUBLES.containsKey(doubleVal)) {
// This patch is based on work in ForgeFlower submitted by Pokechu22.
float floatRepresentation = (float) doubleVal;
if (floatRepresentation == doubleVal) {
if (Float.toString(floatRepresentation).length() < Double.toString(doubleVal).length()) {
if (trimFloat(Float.toString(floatRepresentation), floatRepresentation).length() < trimDouble(Double.toString(doubleVal), doubleVal).length()) {
// Check the uninlined values to see if we have one of those
if (UNINLINED_FLOATS.containsKey(floatRepresentation)) {
return buf.append(UNINLINED_FLOATS.get(floatRepresentation).apply(bytecode));
Expand Down
Loading

0 comments on commit 3482e13

Please sign in to comment.