From a9e03fa0e75b5b338021de982acbbb8277e08706 Mon Sep 17 00:00:00 2001 From: Fudge Date: Mon, 2 Dec 2019 15:43:23 +0200 Subject: Allow attaching class, method, field, and parameter javadocs (#185) * bring liach pr to modern enigma * bump version * fuck off vscode * switch to COMMENT and write comments before * it was already after, what do you want * oops * put inner classes at the end * remove indents and use all caps * add refreshmappings command * Update src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java * Delete RefreshEnigmaMappingsCommand.java * Update CommandMain.java * ok --- build.gradle | 2 +- src/main/java/cuchaz/enigma/SourceProvider.java | 17 +- .../enigma/analysis/AddJavadocsAstTransform.java | 135 ++++++++ .../enigma/analysis/SourceIndexClassVisitor.java | 8 +- .../enigma/analysis/SourceIndexMethodVisitor.java | 20 +- .../cuchaz/enigma/analysis/SourceIndexVisitor.java | 356 +-------------------- .../cuchaz/enigma/analysis/TreeDumpVisitor.java | 354 +------------------- .../translators/TranslationMethodVisitor.java | 2 +- src/main/java/cuchaz/enigma/gui/Gui.java | 45 +++ src/main/java/cuchaz/enigma/gui/GuiController.java | 35 +- .../cuchaz/enigma/gui/dialog/JavadocDialog.java | 88 +++++ .../cuchaz/enigma/gui/elements/PopupMenuBar.java | 9 + .../java/cuchaz/enigma/gui/panels/PanelEditor.java | 4 + .../cuchaz/enigma/gui/stats/StatsGenerator.java | 2 +- .../enigma/translation/mapping/EntryMapping.java | 28 ++ .../enigma/translation/mapping/EntryRemapper.java | 9 +- .../translation/mapping/serde/EnigmaFormat.java | 9 + .../mapping/serde/EnigmaMappingsReader.java | 79 +++-- .../mapping/serde/EnigmaMappingsWriter.java | 67 ++-- .../translation/mapping/serde/MappingFormat.java | 1 + .../translation/mapping/serde/MappingHelper.java | 51 +++ .../translation/mapping/serde/RawEntryMapping.java | 11 +- .../mapping/serde/TinyMappingsReader.java | 2 +- .../translation/mapping/serde/TinyV2Reader.java | 22 +- .../translation/mapping/serde/TinyV2Writer.java | 12 +- .../representation/entry/ClassDefEntry.java | 16 +- .../representation/entry/ClassEntry.java | 15 +- .../translation/representation/entry/Entry.java | 2 + .../representation/entry/FieldDefEntry.java | 17 +- .../representation/entry/FieldEntry.java | 15 +- .../entry/LocalVariableDefEntry.java | 11 +- .../representation/entry/LocalVariableEntry.java | 11 +- .../representation/entry/MethodDefEntry.java | 17 +- .../representation/entry/MethodEntry.java | 15 +- .../representation/entry/ParentedEntry.java | 10 +- 35 files changed, 668 insertions(+), 829 deletions(-) create mode 100644 src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java create mode 100644 src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java create mode 100644 src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaFormat.java create mode 100644 src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java diff --git a/build.gradle b/build.gradle index 5a743603..d704bfa0 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'maven' group = 'cuchaz' -version = '0.14.2' +version = '0.14.3' def generatedSourcesDir = "$buildDir/generated-src" diff --git a/src/main/java/cuchaz/enigma/SourceProvider.java b/src/main/java/cuchaz/enigma/SourceProvider.java index 704424aa..d3d30038 100644 --- a/src/main/java/cuchaz/enigma/SourceProvider.java +++ b/src/main/java/cuchaz/enigma/SourceProvider.java @@ -19,8 +19,10 @@ import oml.ast.transformers.*; import java.io.StringWriter; import java.io.Writer; +import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.List; +import java.util.Objects; public class SourceProvider { private final DecompilerSettings settings; @@ -28,6 +30,9 @@ public class SourceProvider { private final ITypeLoader typeLoader; private final MetadataSystem metadataSystem; + private String lastLookUpName; + private WeakReference lastDecompiled; + public SourceProvider(DecompilerSettings settings, ITypeLoader typeLoader, MetadataSystem metadataSystem) { this.settings = settings; this.typeLoader = typeLoader; @@ -55,6 +60,13 @@ public class SourceProvider { } public CompilationUnit getSources(String name) { + // Optimization for javadoc-caused decompilations + if (Objects.equals(lastLookUpName, name)) { + CompilationUnit last = lastDecompiled.get(); + if (last != null) + return last; + } + TypeReference type = metadataSystem.lookupType(name); if (type == null) { throw new Error(String.format("Unable to find desc: %s", name)); @@ -74,7 +86,10 @@ public class SourceProvider { builder.runTransformations(null); runCustomTransforms(builder, context); - return builder.getCompilationUnit(); + CompilationUnit ret = builder.getCompilationUnit(); + lastLookUpName = name; + lastDecompiled = new WeakReference<>(ret); + return ret; } public void writeSource(Writer writer, CompilationUnit sourceTree) { diff --git a/src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java b/src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java new file mode 100644 index 00000000..17ae63df --- /dev/null +++ b/src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java @@ -0,0 +1,135 @@ +package cuchaz.enigma.analysis; + +import com.google.common.base.Function; +import com.google.common.base.Strings; +import com.strobel.assembler.metadata.ParameterDefinition; +import com.strobel.decompiler.languages.java.ast.*; +import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; +import cuchaz.enigma.translation.mapping.EntryMapping; +import cuchaz.enigma.translation.mapping.EntryRemapper; +import cuchaz.enigma.translation.mapping.EntryResolver; +import cuchaz.enigma.translation.mapping.ResolutionStrategy; +import cuchaz.enigma.translation.representation.TypeDescriptor; +import cuchaz.enigma.translation.representation.entry.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +public final class AddJavadocsAstTransform implements IAstTransform { + + private final EntryRemapper remapper; + + public AddJavadocsAstTransform(EntryRemapper remapper) { + this.remapper = remapper; + } + + @Override + public void run(AstNode compilationUnit) { + compilationUnit.acceptVisitor(new Visitor(remapper), null); + } + + static class Visitor extends DepthFirstAstVisitor { + + private final EntryRemapper remapper; + + Visitor(EntryRemapper remapper) { + this.remapper = remapper; + } + + private void addDoc(T node, Function> retriever) { + final Comment[] comments = getComments(node, retriever); + if (comments != null) { + node.insertChildrenBefore(node.getFirstChild(), Roles.COMMENT, comments); + } + } + + private Comment[] getComments(T node, Function> retriever) { + final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); + final String docs = mapping == null ? null : Strings.emptyToNull(mapping.getJavadoc()); + return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, + CommentType.Documentation)).toArray(Comment[]::new); + } + + private Comment[] getParameterComments(ParameterDeclaration node, Function> retriever) { + final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); + final Comment[] ret = getComments(node, retriever); + if (ret != null) { + final String paramPrefix = "@param " + mapping.getTargetName() + " "; + final String indent = Strings.repeat(" ", paramPrefix.length()); + ret[0].setContent(paramPrefix + ret[0].getContent()); + for (int i = 1; i < ret.length; i++) { + ret[i].setContent(indent + ret[i].getContent()); + } + } + return ret; + } + + private void visitMethod(AstNode node) { + final MethodDefEntry methodDefEntry = MethodDefEntry.parse(node.getUserData(Keys.METHOD_DEFINITION)); + final Comment[] baseComments = getComments(node, $ -> methodDefEntry); + List comments = new ArrayList<>(); + if (baseComments != null) + Collections.addAll(comments, baseComments); + + for (ParameterDeclaration dec : node.getChildrenByRole(Roles.PARAMETER)) { + ParameterDefinition def = dec.getUserData(Keys.PARAMETER_DEFINITION); + final Comment[] paramComments = getParameterComments(dec, $ -> new LocalVariableDefEntry(methodDefEntry, def.getSlot(), def.getName(), + true, + TypeDescriptor.parse(def.getParameterType()), null)); + if (paramComments != null) + Collections.addAll(comments, paramComments); + } + + if (!comments.isEmpty()) { + if (remapper.getObfResolver().resolveEntry(methodDefEntry, ResolutionStrategy.RESOLVE_ROOT).stream().noneMatch(e -> Objects.equals(e, methodDefEntry))) { + comments.add(0, new Comment("{@inheritDoc}", CommentType.Documentation)); + } + final AstNode oldFirst = node.getFirstChild(); + for (Comment comment : comments) { + node.insertChildBefore(oldFirst, comment, Roles.COMMENT); + } + } + } + + @Override + protected Void visitChildren(AstNode node, Void data) { + for (final AstNode child : node.getChildren()) { + child.acceptVisitor(this, data); + } + return null; + } + + @Override + public Void visitMethodDeclaration(MethodDeclaration node, Void data) { + visitMethod(node); + return super.visitMethodDeclaration(node, data); + } + + @Override + public Void visitConstructorDeclaration(ConstructorDeclaration node, Void data) { + visitMethod(node); + return super.visitConstructorDeclaration(node, data); + } + + @Override + public Void visitFieldDeclaration(FieldDeclaration node, Void data) { + addDoc(node, dec -> FieldDefEntry.parse(dec.getUserData(Keys.FIELD_DEFINITION))); + return super.visitFieldDeclaration(node, data); + } + + @Override + public Void visitTypeDeclaration(TypeDeclaration node, Void data) { + addDoc(node, dec -> ClassDefEntry.parse(dec.getUserData(Keys.TYPE_DEFINITION))); + return super.visitTypeDeclaration(node, data); + } + + @Override + public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void data) { + addDoc(node, dec -> FieldDefEntry.parse(dec.getUserData(Keys.FIELD_DEFINITION))); + return super.visitEnumValueDeclaration(node, data); + } + } +} diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index c9777030..2a72cb1a 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -40,7 +40,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -51,7 +51,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { index.addReference(node.getIdentifierToken(), classEntry, this.classEntry); } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -82,7 +82,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { assert (node.getVariables().size() == 1); VariableInitializer variable = node.getVariables().firstOrNullObject(); index.addDeclaration(variable.getNameToken(), fieldEntry); - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -91,6 +91,6 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); FieldDefEntry fieldEntry = FieldDefEntry.parse(def); index.addDeclaration(node.getNameToken(), fieldEntry); - return recurse(node, index); + return visitChildren(node, index); } } diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java index fde6edf9..dfe58bad 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java @@ -63,7 +63,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { // Check for identifier node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -81,7 +81,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { index.addReference(node.getMemberNameToken(), fieldEntry, this.methodEntry); } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -92,7 +92,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { index.addReference(node.getIdentifierToken(), classEntry, this.methodEntry); } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -107,14 +107,14 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { } TypeDescriptor parameterType = TypeDescriptor.parse(def.getParameterType()); - LocalVariableDefEntry localVariableEntry = new LocalVariableDefEntry(ownerMethod, parameterIndex, node.getName(), true, parameterType); + LocalVariableDefEntry localVariableEntry = new LocalVariableDefEntry(ownerMethod, parameterIndex, node.getName(), true, parameterType, null); Identifier identifier = node.getNameToken(); // cache the argument entry and the identifier identifierEntryCache.put(identifier.getName(), localVariableEntry); index.addDeclaration(identifier, localVariableEntry); } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -126,7 +126,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { index.addReference(node.getIdentifierToken(), fieldEntry, this.methodEntry); } else this.checkIdentifier(node, index); - return recurse(node, index); + return visitChildren(node, index); } private void checkIdentifier(IdentifierExpression node, SourceIndex index) { @@ -157,7 +157,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, this.methodEntry); } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -177,7 +177,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { if (variableIndex >= 0) { MethodDefEntry ownerMethod = MethodDefEntry.parse(originalVariable.getDeclaringMethod()); TypeDescriptor variableType = TypeDescriptor.parse(originalVariable.getVariableType()); - LocalVariableDefEntry localVariableEntry = new LocalVariableDefEntry(ownerMethod, variableIndex, initializer.getName(), false, variableType); + LocalVariableDefEntry localVariableEntry = new LocalVariableDefEntry(ownerMethod, variableIndex, initializer.getName(), false, variableType, null); identifierEntryCache.put(identifier.getName(), localVariableEntry); addDeclarationToUnmatched(identifier.getName(), index); index.addDeclaration(identifier, localVariableEntry); @@ -186,7 +186,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { } } } - return recurse(node, index); + return visitChildren(node, index); } @Override @@ -211,6 +211,6 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { } } - return recurse(node, index); + return visitChildren(node, index); } } diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java index 75a66a2d..8bd00a86 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -12,11 +12,13 @@ package cuchaz.enigma.analysis; import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.decompiler.languages.java.ast.*; -import com.strobel.decompiler.patterns.Pattern; +import com.strobel.decompiler.languages.java.ast.AstNode; +import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.TypeDeclaration; import cuchaz.enigma.translation.representation.entry.ClassDefEntry; -public class SourceIndexVisitor implements IAstVisitor { +public class SourceIndexVisitor extends DepthFirstAstVisitor { @Override public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); @@ -26,355 +28,11 @@ public class SourceIndexVisitor implements IAstVisitor { return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); } - protected Void recurse(AstNode node, SourceIndex index) { + @Override + protected Void visitChildren(AstNode node, SourceIndex index) { for (final AstNode child : node.getChildren()) { child.acceptVisitor(this, index); } return null; } - - @Override - public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSimpleType(SimpleType node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitComment(Comment node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIdentifier(Identifier node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitBlockStatement(BlockStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitBreakStatement(BreakStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitContinueStatement(ContinueStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLabelStatement(LabelStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitReturnStatement(ReturnStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSwitchSection(SwitchSection node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCaseLabel(CaseLabel node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitThrowStatement(ThrowStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCatchClause(CatchClause node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAnnotation(Annotation node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitNewLine(NewLineNode node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitText(TextNode node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitComposedType(ComposedType node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitWhileStatement(WhileStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCastExpression(CastExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitForStatement(ForStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitGotoStatement(GotoStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitWildcardType(WildcardType node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAssertStatement(AssertStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) { - return recurse(node, index); - } } diff --git a/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java index c98fb9ef..c85d97a5 100644 --- a/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -18,7 +18,7 @@ import com.strobel.decompiler.patterns.Pattern; import java.io.*; import java.nio.charset.Charset; -public class TreeDumpVisitor implements IAstVisitor { +public class TreeDumpVisitor extends DepthFirstAstVisitor { private File file; private Writer out; @@ -31,7 +31,7 @@ public class TreeDumpVisitor implements IAstVisitor { public Void visitCompilationUnit(CompilationUnit node, Void ignored) { try { out = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8")); - recurse(node, ignored); + visitChildren(node, ignored); out.close(); return null; } catch (IOException ex) { @@ -39,7 +39,8 @@ public class TreeDumpVisitor implements IAstVisitor { } } - private Void recurse(AstNode node, Void ignored) { + @Override + protected Void visitChildren(AstNode node, Void ignored) { // show the tree try { out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n"); @@ -89,351 +90,4 @@ public class TreeDumpVisitor implements IAstVisitor { } return depth; } - - // OVERRIDES WE DON'T CARE ABOUT - - @Override - public Void visitInvocationExpression(InvocationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSimpleType(SimpleType node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitComment(Comment node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTypeReference(TypeReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIdentifier(Identifier node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitClassOfExpression(ClassOfExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitBlockStatement(BlockStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitExpressionStatement(ExpressionStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitBreakStatement(BreakStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitContinueStatement(ContinueStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitEmptyStatement(EmptyStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIfElseStatement(IfElseStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLabelStatement(LabelStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLabeledStatement(LabeledStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitReturnStatement(ReturnStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSwitchStatement(SwitchStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSwitchSection(SwitchSection node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitCaseLabel(CaseLabel node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitThrowStatement(ThrowStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitCatchClause(CatchClause node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAnnotation(Annotation node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitNewLine(NewLineNode node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitVariableInitializer(VariableInitializer node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitText(TextNode node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitImportDeclaration(ImportDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitInitializerBlock(InstanceInitializer node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitArraySpecifier(ArraySpecifier node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitComposedType(ComposedType node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitWhileStatement(WhileStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitCastExpression(CastExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIndexerExpression(IndexerExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitConditionalExpression(ConditionalExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitForStatement(ForStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitForEachStatement(ForEachStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitGotoStatement(GotoStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitWildcardType(WildcardType node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAssertStatement(AssertStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLambdaExpression(LambdaExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) { - return recurse(node, ignored); - } } diff --git a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java index 4bce5333..a82df1b0 100644 --- a/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java +++ b/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java @@ -132,7 +132,7 @@ public class TranslationMethodVisitor extends MethodVisitor { } private String translateVariableName(int index, String name) { - LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true); + LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true,null); LocalVariableEntry translatedEntry = translator.translate(entry); String translatedName = translatedEntry.getName(); diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java index 3ab1ceea..1ea3e44f 100644 --- a/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/src/main/java/cuchaz/enigma/gui/Gui.java @@ -11,6 +11,7 @@ package cuchaz.enigma.gui; +import com.google.common.base.Strings; import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.EnigmaProfile; @@ -19,6 +20,7 @@ import cuchaz.enigma.analysis.*; import cuchaz.enigma.config.Config; import cuchaz.enigma.config.Themes; import cuchaz.enigma.gui.dialog.CrashDialog; +import cuchaz.enigma.gui.dialog.JavadocDialog; import cuchaz.enigma.gui.elements.MenuBar; import cuchaz.enigma.gui.elements.PopupMenuBar; import cuchaz.enigma.gui.filechooser.FileChooserAny; @@ -82,6 +84,7 @@ public class Gui { private JTabbedPane tabs; public JTextField renameTextField; + public JTextArea javadocTextArea; public void setEditorTheme(Config.LookAndFeel feel) { if (editor != null && (editorFeel == null || editorFeel != feel)) { @@ -559,6 +562,7 @@ public class Gui { } this.popupMenu.renameMenu.setEnabled(isRenamable); + this.popupMenu.editJavadocMenu.setEnabled(isRenamable); this.popupMenu.showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); this.popupMenu.showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); this.popupMenu.showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); @@ -575,6 +579,47 @@ public class Gui { } } + public void startDocChange() { + + // init the text box + javadocTextArea = new JTextArea(10, 40); + + EntryReference, Entry> translatedReference = controller.project.getMapper().deobfuscate(cursorReference); + javadocTextArea.setText(Strings.nullToEmpty(translatedReference.entry.getJavadocs())); + + JavadocDialog.init(frame, javadocTextArea, this::finishDocChange); + javadocTextArea.grabFocus(); + + redraw(); + } + + private void finishDocChange(JFrame ui, boolean saveName) { + String newName = javadocTextArea.getText(); + if (saveName) { + try { + this.controller.changeDocs(cursorReference, newName); + } catch (IllegalNameException ex) { + javadocTextArea.setBorder(BorderFactory.createLineBorder(Color.red, 1)); + javadocTextArea.setToolTipText(ex.getReason()); + Utils.showToolTipNow(javadocTextArea); + return; + } + + ui.setVisible(false); + showCursorReference(cursorReference); + return; + } + + // abort the jd change + javadocTextArea = null; + ui.setVisible(false); + showCursorReference(cursorReference); + + this.editor.grabFocus(); + + redraw(); + } + public void startRename() { // init the text box diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java index 69f12e2e..0b2fe27d 100644 --- a/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/src/main/java/cuchaz/enigma/gui/GuiController.java @@ -368,20 +368,29 @@ public class GuiController { } private void refreshCurrentClass(EntryReference, Entry> reference) { + refreshCurrentClass(reference, false); + } + + private void refreshCurrentClass(EntryReference, Entry> reference, boolean forceDecomp) { if (currentSource != null) { loadClass(currentSource.getEntry(), () -> { if (reference != null) { showReference(reference); } - }); + }, forceDecomp); } } private void loadClass(ClassEntry classEntry, Runnable callback) { + loadClass(classEntry, callback, false); + } + + private void loadClass(ClassEntry classEntry, Runnable callback, boolean forceDecomp) { ClassEntry targetClass = classEntry.getOutermostClass(); - boolean requiresDecompile = currentSource == null || !currentSource.getEntry().equals(targetClass); + boolean requiresDecompile = forceDecomp || currentSource == null || !currentSource.getEntry().equals(targetClass); if (requiresDecompile) { + currentSource = null; // Or the GUI may try to find a nonexistent token gui.setEditorText("(decompiling...)"); } @@ -402,7 +411,7 @@ public class GuiController { private DecompiledClassSource decompileSource(ClassEntry targetClass) { try { - CompilationUnit sourceTree = sourceProvider.getSources(targetClass.getFullName()); + CompilationUnit sourceTree = (CompilationUnit) sourceProvider.getSources(targetClass.getFullName()).clone(); if (sourceTree == null) { gui.setEditorText("Unable to find class: " + targetClass); return DecompiledClassSource.text(targetClass, "Unable to find class"); @@ -410,6 +419,7 @@ public class GuiController { DropImportAstTransform.INSTANCE.run(sourceTree); DropVarModifiersAstTransform.INSTANCE.run(sourceTree); + new AddJavadocsAstTransform(project.getMapper()).run(sourceTree); String sourceString = sourceProvider.writeSourceToString(sourceTree); @@ -521,6 +531,25 @@ public class GuiController { refreshCurrentClass(reference); } + public void changeDocs(EntryReference, Entry> reference, String updatedDocs) { + changeDoc(reference.getNameableEntry(), updatedDocs); + + refreshCurrentClass(reference, true); + } + + public void changeDoc(Entry obfEntry, String newDoc) { + EntryRemapper mapper = project.getMapper(); + if (mapper.getDeobfMapping(obfEntry) == null) { + markAsDeobfuscated(obfEntry,false); // NPE + } + mapper.mapFromObf(obfEntry, mapper.getDeobfMapping(obfEntry).withDocs(newDoc), false); + } + + public void markAsDeobfuscated(Entry obfEntry, boolean renaming) { + EntryRemapper mapper = project.getMapper(); + mapper.mapFromObf(obfEntry, new EntryMapping(mapper.deobfuscate(obfEntry).getName()), renaming); + } + public void markAsDeobfuscated(EntryReference, Entry> reference) { EntryRemapper mapper = project.getMapper(); Entry entry = reference.getNameableEntry(); diff --git a/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java new file mode 100644 index 00000000..84e4d8fc --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2015 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html + *

+ * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ + +package cuchaz.enigma.gui.dialog; + +import cuchaz.enigma.utils.Utils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +public class JavadocDialog { + + private static JavadocDialog instance = null; + + private JFrame frame; + + private JavadocDialog(JFrame parent, JTextArea text, Callback callback) { + // init frame + frame = new JFrame("Edit Javadocs"); + final Container pane = frame.getContentPane(); + pane.setLayout(new BorderLayout()); + + // editor panel + text.setTabSize(2); + pane.add(new JScrollPane(text), BorderLayout.CENTER); + text.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent event) { + switch (event.getKeyCode()) { + case KeyEvent.VK_ENTER: + if (event.isControlDown()) + callback.closeUi(frame, true); + break; + case KeyEvent.VK_ESCAPE: + callback.closeUi(frame, false); + break; + default: + break; + } + } + }); + + // buttons panel + JPanel buttonsPanel = new JPanel(); + FlowLayout buttonsLayout = new FlowLayout(); + buttonsLayout.setAlignment(FlowLayout.RIGHT); + buttonsPanel.setLayout(buttonsLayout); + buttonsPanel.add(Utils.unboldLabel(new JLabel("Edit javadocs here."))); + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener(event -> { + // close (hide) the dialog + callback.closeUi(frame, false); + }); + buttonsPanel.add(cancelButton); + JButton saveButton = new JButton("Save"); + saveButton.addActionListener(event -> { + // exit enigma + callback.closeUi(frame, true); + }); + buttonsPanel.add(saveButton); + pane.add(buttonsPanel, BorderLayout.SOUTH); + + // show the frame + frame.setSize(600, 400); + frame.setLocationRelativeTo(parent); + frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + } + + public static void init(JFrame parent, JTextArea area, Callback callback) { + instance = new JavadocDialog(parent, area, callback); + instance.frame.doLayout(); + instance.frame.setVisible(true); + } + + public interface Callback { + void closeUi(JFrame frame, boolean save); + } +} diff --git a/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java index fbf39ac6..b9d459f3 100644 --- a/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java +++ b/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java @@ -9,6 +9,7 @@ import java.awt.event.KeyEvent; public class PopupMenuBar extends JPopupMenu { public final JMenuItem renameMenu; + public final JMenuItem editJavadocMenu; public final JMenuItem showInheritanceMenu; public final JMenuItem showImplementationsMenu; public final JMenuItem showCallsMenu; @@ -27,6 +28,14 @@ public class PopupMenuBar extends JPopupMenu { this.add(menu); this.renameMenu = menu; } + { + JMenuItem menu = new JMenuItem("Edit Javadoc"); + menu.addActionListener(event -> gui.startDocChange()); + menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0)); + menu.setEnabled(false); + this.add(menu); + this.editJavadocMenu = menu; + } { JMenuItem menu = new JMenuItem("Show Inheritance"); menu.addActionListener(event -> gui.showInheritance()); diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java b/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java index 9e29699b..71ee34cd 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java @@ -87,6 +87,10 @@ public class PanelEditor extends JEditorPane { gui.popupMenu.renameMenu.doClick(); break; + case KeyEvent.VK_D: + gui.popupMenu.editJavadocMenu.doClick(); + break; + case KeyEvent.VK_F5: gui.getController().refreshCurrentClass(); break; diff --git a/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java b/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java index 88ed96f4..a6e465d3 100644 --- a/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java +++ b/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java @@ -67,7 +67,7 @@ public class StatsGenerator { if (includedMembers.contains(StatsMember.PARAMETERS)) { int index = ((MethodDefEntry) method).getAccess().isStatic() ? 0 : 1; for (TypeDescriptor argument : method.getDesc().getArgumentDescs()) { - update(counts, new LocalVariableEntry(method, index, "", true)); + update(counts, new LocalVariableEntry(method, index, "", true,null)); index += argument.getSize(); } } diff --git a/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java b/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java index b74cc0b3..c607817c 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java @@ -1,18 +1,29 @@ package cuchaz.enigma.translation.mapping; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class EntryMapping { private final String targetName; private final AccessModifier accessModifier; + private final @Nullable String javadoc; public EntryMapping(@Nonnull String targetName) { this(targetName, AccessModifier.UNCHANGED); } + public EntryMapping(@Nonnull String targetName, @Nullable String javadoc) { + this(targetName, AccessModifier.UNCHANGED, javadoc); + } + public EntryMapping(@Nonnull String targetName, AccessModifier accessModifier) { + this(targetName, accessModifier, null); + } + + public EntryMapping(@Nonnull String targetName, AccessModifier accessModifier, @Nullable String javadoc) { this.targetName = targetName; this.accessModifier = accessModifier; + this.javadoc = javadoc; } @Nonnull @@ -28,6 +39,23 @@ public class EntryMapping { return accessModifier; } + @Nullable + public String getJavadoc() { + return javadoc; + } + + public EntryMapping withName(String newName) { + return new EntryMapping(newName, accessModifier, javadoc); + } + + public EntryMapping withModifier(AccessModifier newModifier) { + return new EntryMapping(targetName, newModifier, javadoc); + } + + public EntryMapping withDocs(String newDocs) { + return new EntryMapping(targetName, accessModifier, newDocs); + } + @Override public boolean equals(Object obj) { if (obj == this) return true; diff --git a/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java b/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java index c9808cc9..ad36c97f 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java @@ -11,6 +11,7 @@ import cuchaz.enigma.translation.representation.entry.Entry; import javax.annotation.Nullable; import java.util.Collection; +import java.util.function.UnaryOperator; import java.util.stream.Stream; public class EntryRemapper { @@ -40,9 +41,13 @@ public class EntryRemapper { } public > void mapFromObf(E obfuscatedEntry, @Nullable EntryMapping deobfMapping) { - Collection resolvedEntries = obfResolver.resolveEntry(obfuscatedEntry, ResolutionStrategy.RESOLVE_ROOT); + mapFromObf(obfuscatedEntry, deobfMapping, true); + } + + public > void mapFromObf(E obfuscatedEntry, @Nullable EntryMapping deobfMapping, boolean renaming) { + Collection resolvedEntries = obfResolver.resolveEntry(obfuscatedEntry, renaming ? ResolutionStrategy.RESOLVE_ROOT : ResolutionStrategy.RESOLVE_CLOSEST); - if (deobfMapping != null) { + if (renaming && deobfMapping != null) { for (E resolvedEntry : resolvedEntries) { validator.validateRename(resolvedEntry, deobfMapping.getTargetName()); } diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaFormat.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaFormat.java new file mode 100644 index 00000000..af92ffbe --- /dev/null +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaFormat.java @@ -0,0 +1,9 @@ +package cuchaz.enigma.translation.mapping.serde; + +public class EnigmaFormat { + public static final String COMMENT = "COMMENT"; + public static final String CLASS = "CLASS"; + public static final String FIELD = "FIELD"; + public static final String METHOD = "METHOD"; + public static final String PARAMETER = "ARG"; +} diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java index 1e4c442c..2c993f44 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java @@ -64,7 +64,7 @@ public enum EnigmaMappingsReader implements MappingsReader { protected void readFile(Path path, EntryTree mappings) throws IOException, MappingParseException { List lines = Files.readAllLines(path, Charsets.UTF_8); - Deque> mappingStack = new ArrayDeque<>(); + Deque> mappingStack = new ArrayDeque<>(); for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { String line = lines.get(lineNumber); @@ -75,21 +75,33 @@ public enum EnigmaMappingsReader implements MappingsReader { continue; } - while (indentation < mappingStack.size()) { - mappingStack.pop(); - } + cleanMappingStack(indentation, mappingStack, mappings); try { - MappingPair pair = parseLine(mappingStack.peek(), line); - mappingStack.push(pair.getEntry()); - if (pair.getMapping() != null) { - mappings.insert(pair.getEntry(), pair.getMapping()); + MappingPair pair = parseLine(mappingStack.peek(), line); + if (pair != null) { + mappingStack.push(pair); + if (pair.getMapping() != null) { + + } } } catch (Throwable t) { t.printStackTrace(); throw new MappingParseException(path::toString, lineNumber, t.toString()); } } + + // Clean up rest + cleanMappingStack(0, mappingStack, mappings); + } + + private void cleanMappingStack(int indentation, Deque> mappingStack, EntryTree mappings) { + while (indentation < mappingStack.size()) { + MappingPair pair = mappingStack.pop(); + if (pair.getMapping() != null) { + mappings.insert(pair.getEntry(), pair.getMapping().bake()); + } + } } @Nullable @@ -123,25 +135,38 @@ public enum EnigmaMappingsReader implements MappingsReader { return indent; } - private MappingPair parseLine(@Nullable Entry parent, String line) { + private MappingPair parseLine(@Nullable MappingPair parent, String line) { String[] tokens = line.trim().split("\\s"); - String keyToken = tokens[0].toLowerCase(Locale.ROOT); + String keyToken = tokens[0].toUpperCase(Locale.ROOT); + Entry parentEntry = parent == null ? null : parent.getEntry(); switch (keyToken) { - case "class": - return parseClass(parent, tokens); - case "field": - return parseField(parent, tokens); - case "method": - return parseMethod(parent, tokens); - case "arg": - return parseArgument(parent, tokens); + case EnigmaFormat.CLASS: + return parseClass(parentEntry, tokens); + case EnigmaFormat.FIELD: + return parseField(parentEntry, tokens); + case EnigmaFormat.METHOD: + return parseMethod(parentEntry, tokens); + case EnigmaFormat.PARAMETER: + return parseArgument(parentEntry, tokens); + case EnigmaFormat.COMMENT: + readJavadoc(parent, tokens); + return null; default: throw new RuntimeException("Unknown token '" + keyToken + "'"); } } + + private void readJavadoc(MappingPair parent, String[] tokens) { + if (parent == null) + throw new IllegalStateException("Javadoc has no parent!"); + String jdLine = tokens.length > 1 ? tokens[1] : ""; // Empty string to concat + if (parent.getMapping() == null) + throw new IllegalStateException("Javadoc requires a mapping!"); + parent.getMapping().addJavadocLine(MappingHelper.unescape(jdLine)); + } - private MappingPair parseClass(@Nullable Entry parent, String[] tokens) { + private MappingPair parseClass(@Nullable Entry parent, String[] tokens) { String obfuscatedName = ClassEntry.getInnerName(tokens[1]); ClassEntry obfuscatedEntry; if (parent instanceof ClassEntry) { @@ -167,13 +192,13 @@ public enum EnigmaMappingsReader implements MappingsReader { } if (mapping != null) { - return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping, modifier)); + return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); } else { return new MappingPair<>(obfuscatedEntry); } } - private MappingPair parseField(@Nullable Entry parent, String[] tokens) { + private MappingPair parseField(@Nullable Entry parent, String[] tokens) { if (!(parent instanceof ClassEntry)) { throw new RuntimeException("Field must be a child of a class!"); } @@ -204,13 +229,13 @@ public enum EnigmaMappingsReader implements MappingsReader { FieldEntry obfuscatedEntry = new FieldEntry(ownerEntry, obfuscatedName, descriptor); if (mapping != null) { - return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping, modifier)); + return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); } else { return new MappingPair<>(obfuscatedEntry); } } - private MappingPair parseMethod(@Nullable Entry parent, String[] tokens) { + private MappingPair parseMethod(@Nullable Entry parent, String[] tokens) { if (!(parent instanceof ClassEntry)) { throw new RuntimeException("Method must be a child of a class!"); } @@ -244,22 +269,22 @@ public enum EnigmaMappingsReader implements MappingsReader { MethodEntry obfuscatedEntry = new MethodEntry(ownerEntry, obfuscatedName, descriptor); if (mapping != null) { - return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping, modifier)); + return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping, modifier)); } else { return new MappingPair<>(obfuscatedEntry); } } - private MappingPair parseArgument(@Nullable Entry parent, String[] tokens) { + private MappingPair parseArgument(@Nullable Entry parent, String[] tokens) { if (!(parent instanceof MethodEntry)) { throw new RuntimeException("Method arg must be a child of a method!"); } MethodEntry ownerEntry = (MethodEntry) parent; - LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerEntry, Integer.parseInt(tokens[1]), "", true); + LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerEntry, Integer.parseInt(tokens[1]), "", true, null); String mapping = tokens[2]; - return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping)); + return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); } @Nullable diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java index 7199be88..f490b1da 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java @@ -11,15 +11,6 @@ package cuchaz.enigma.translation.mapping.serde; -import cuchaz.enigma.ProgressListener; -import cuchaz.enigma.translation.MappingTranslator; -import cuchaz.enigma.translation.Translator; -import cuchaz.enigma.translation.mapping.*; -import cuchaz.enigma.translation.mapping.tree.EntryTree; -import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; -import cuchaz.enigma.translation.representation.entry.*; -import cuchaz.enigma.utils.LFPrintWriter; - import java.io.IOException; import java.io.PrintWriter; import java.nio.file.DirectoryStream; @@ -33,6 +24,24 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; +import cuchaz.enigma.ProgressListener; +import cuchaz.enigma.translation.MappingTranslator; +import cuchaz.enigma.translation.Translator; +import cuchaz.enigma.translation.mapping.AccessModifier; +import cuchaz.enigma.translation.mapping.EntryMapping; +import cuchaz.enigma.translation.mapping.MappingDelta; +import cuchaz.enigma.translation.mapping.MappingFileNameFormat; +import cuchaz.enigma.translation.mapping.MappingSaveParameters; +import cuchaz.enigma.translation.mapping.VoidEntryResolver; +import cuchaz.enigma.translation.mapping.tree.EntryTree; +import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; +import cuchaz.enigma.translation.representation.entry.ClassEntry; +import cuchaz.enigma.translation.representation.entry.Entry; +import cuchaz.enigma.translation.representation.entry.FieldEntry; +import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; +import cuchaz.enigma.translation.representation.entry.MethodEntry; +import cuchaz.enigma.utils.LFPrintWriter; + public enum EnigmaMappingsWriter implements MappingsWriter { FILE { @Override @@ -154,10 +163,26 @@ public enum EnigmaMappingsWriter implements MappingsWriter { protected void writeRoot(PrintWriter writer, EntryTree mappings, ClassEntry classEntry) { Collection> children = groupChildren(mappings.getChildren(classEntry)); - writer.println(writeClass(classEntry, mappings.get(classEntry)).trim()); + EntryMapping classEntryMapping = mappings.get(classEntry); + + writer.println(writeClass(classEntry, classEntryMapping).trim()); + if (classEntryMapping != null && classEntryMapping.getJavadoc() != null) { + writeDocs(writer, classEntryMapping, 0); + } + for (Entry child : children) { writeEntry(writer, mappings, child, 1); } + + } + + private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) { + String jd = mapping.getJavadoc(); + if (jd != null) { + for (String line : jd.split("\\R")) { + writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1)); + } + } } protected void writeEntry(PrintWriter writer, EntryTree mappings, Entry entry, int depth) { @@ -167,6 +192,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { } EntryMapping mapping = node.getValue(); + if (entry instanceof ClassEntry) { String line = writeClass((ClassEntry) entry, mapping); writer.println(indent(line, depth)); @@ -180,6 +206,9 @@ public enum EnigmaMappingsWriter implements MappingsWriter { String line = writeArgument((LocalVariableEntry) entry, mapping); writer.println(indent(line, depth)); } + if (mapping != null && mapping.getJavadoc() != null) { + writeDocs(writer, mapping, depth); + } Collection> children = groupChildren(node.getChildren()); for (Entry child : children) { @@ -190,11 +219,6 @@ public enum EnigmaMappingsWriter implements MappingsWriter { private Collection> groupChildren(Collection> children) { Collection> result = new ArrayList<>(children.size()); - children.stream().filter(e -> e instanceof ClassEntry) - .map(e -> (ClassEntry) e) - .sorted() - .forEach(result::add); - children.stream().filter(e -> e instanceof FieldEntry) .map(e -> (FieldEntry) e) .sorted() @@ -210,11 +234,16 @@ public enum EnigmaMappingsWriter implements MappingsWriter { .sorted() .forEach(result::add); + children.stream().filter(e -> e instanceof ClassEntry) + .map(e -> (ClassEntry) e) + .sorted() + .forEach(result::add); + return result; } protected String writeClass(ClassEntry entry, EntryMapping mapping) { - StringBuilder builder = new StringBuilder("CLASS "); + StringBuilder builder = new StringBuilder(EnigmaFormat.CLASS +" "); builder.append(entry.getName()).append(' '); writeMapping(builder, mapping); @@ -222,7 +251,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { } protected String writeMethod(MethodEntry entry, EntryMapping mapping) { - StringBuilder builder = new StringBuilder("METHOD "); + StringBuilder builder = new StringBuilder(EnigmaFormat.METHOD + " "); builder.append(entry.getName()).append(' '); writeMapping(builder, mapping); @@ -232,7 +261,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { } protected String writeField(FieldEntry entry, EntryMapping mapping) { - StringBuilder builder = new StringBuilder("FIELD "); + StringBuilder builder = new StringBuilder(EnigmaFormat.FIELD + " "); builder.append(entry.getName()).append(' '); writeMapping(builder, mapping); @@ -242,7 +271,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { } protected String writeArgument(LocalVariableEntry entry, EntryMapping mapping) { - return "ARG " + entry.getIndex() + ' ' + mapping.getTargetName(); + return EnigmaFormat.PARAMETER + " " + entry.getIndex() + ' ' + mapping.getTargetName(); } private void writeMapping(StringBuilder builder, EntryMapping mapping) { diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java index 7eae1c01..c04eec5e 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java @@ -19,6 +19,7 @@ public enum MappingFormat { SRG_FILE(SrgMappingsWriter.INSTANCE, null), PROGUARD(null, ProguardMappingsReader.INSTANCE); + private final MappingsWriter writer; private final MappingsReader reader; diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java new file mode 100644 index 00000000..7c8f6cc6 --- /dev/null +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java @@ -0,0 +1,51 @@ +package cuchaz.enigma.translation.mapping.serde; + +public final class MappingHelper { + private static final String TO_ESCAPE = "\\\n\r\0\t"; + private static final String ESCAPED = "\\nr0t"; + + public static String escape(String raw) { + StringBuilder builder = new StringBuilder(raw.length() + 1); + for (int i = 0; i < raw.length(); i++) { + final char c = raw.charAt(i); + final int r = TO_ESCAPE.indexOf(c); + if (r < 0) { + builder.append(c); + } else { + builder.append('\\').append(ESCAPED.charAt(r)); + } + } + return builder.toString(); + } + + public static String unescape(String str) { + int pos = str.indexOf('\\'); + if (pos < 0) return str; + + StringBuilder ret = new StringBuilder(str.length() - 1); + int start = 0; + + do { + ret.append(str, start, pos); + pos++; + int type; + + if (pos >= str.length()) { + throw new RuntimeException("incomplete escape sequence at the end"); + } else if ((type = ESCAPED.indexOf(str.charAt(pos))) < 0) { + throw new RuntimeException("invalid escape character: \\" + str.charAt(pos)); + } else { + ret.append(TO_ESCAPE.charAt(type)); + } + + start = pos + 1; + } while ((pos = str.indexOf('\\', start)) >= 0); + + ret.append(str, start, str.length()); + + return ret.toString(); + } + + private MappingHelper() { + } +} diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java index 5d63f38f..afb40e9a 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/RawEntryMapping.java @@ -1,12 +1,15 @@ package cuchaz.enigma.translation.mapping.serde; -import com.google.common.base.Strings; import cuchaz.enigma.translation.mapping.AccessModifier; import cuchaz.enigma.translation.mapping.EntryMapping; +import java.util.ArrayList; +import java.util.List; + final class RawEntryMapping { private final String targetName; private final AccessModifier access; + private List javadocs = new ArrayList<>(); RawEntryMapping(String targetName) { this(targetName, null); @@ -17,7 +20,11 @@ final class RawEntryMapping { this.targetName = targetName; } + void addJavadocLine(String line) { + javadocs.add(line); + } + EntryMapping bake() { - return Strings.isNullOrEmpty(targetName) ? null : new EntryMapping(targetName, access); + return new EntryMapping(targetName, access, javadocs.isEmpty() ? null : String.join("\n", javadocs)); } } diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java index 81d181ba..aceb02f0 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java @@ -108,7 +108,7 @@ public enum TinyMappingsReader implements MappingsReader { int variableIndex = Integer.parseInt(tokens[4]); String mapping = tokens[5]; - LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true); + LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true, null); return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping)); } } diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java index 2621f310..c0488e93 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java @@ -200,14 +200,6 @@ final class TinyV2Reader implements MappingsReader { addJavadoc(pair, parts[1]); } - private void addJavadoc(MappingPair pair, String javadoc) { - RawEntryMapping mapping = pair.getMapping(); - if (mapping == null) { - throw new IllegalArgumentException("Javadoc requires a mapping in enigma!"); - } -// mapping.addJavadocLine(javadoc); todo javadocs - } - private MappingPair parseClass(String[] tokens, boolean escapeNames) { ClassEntry obfuscatedEntry = new ClassEntry(unescapeOpt(tokens[1], escapeNames)); if (tokens.length <= 2) @@ -239,13 +231,25 @@ final class TinyV2Reader implements MappingsReader { return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); } + + + private void addJavadoc(MappingPair pair, String javadoc) { + RawEntryMapping mapping = pair.getMapping(); + if (mapping == null) { + throw new IllegalArgumentException("Javadoc requires a mapping in enigma!"); + } + mapping.addJavadocLine(javadoc); + } + + + private MappingPair parseArgument(MappingPair parent, String[] tokens, boolean escapeNames) { MethodEntry ownerMethod = (MethodEntry) parent.getEntry(); int variableIndex = Integer.parseInt(tokens[1]); // tokens[2] is the useless obf name - LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true); + LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true, null); if (tokens.length <= 3) return new MappingPair<>(obfuscatedEntry); String mapping = unescapeOpt(tokens[3], escapeNames); diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Writer.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Writer.java index a734ca2d..95e04c34 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Writer.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Writer.java @@ -155,12 +155,12 @@ public final class TinyV2Writer implements MappingsWriter { } private void writeComment(PrintWriter writer, EntryMapping mapping, int indent) { -// if (mapping != null && mapping.getJavadoc() != null) { todo javadocs -// writer.print(indent(indent)); -// writer.print("c\t"); -// writer.print(MappingHelper.escape(mapping.getJavadoc())); -// writer.println(); -// } + if (mapping != null && mapping.getJavadoc() != null) { + writer.print(indent(indent)); + writer.print("c\t"); + writer.print(MappingHelper.escape(mapping.getJavadoc())); + writer.println(); + } } private String indent(int level) { diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java index c4df891c..4b245bcb 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java @@ -28,11 +28,16 @@ public class ClassDefEntry extends ClassEntry implements DefEntry { private final ClassEntry[] interfaces; public ClassDefEntry(String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, ClassEntry[] interfaces) { - this(getOuterClass(className), getInnerName(className), signature, access, superClass, interfaces); + this(getOuterClass(className), getInnerName(className), signature, access, superClass, interfaces, null); } public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, ClassEntry[] interfaces) { - super(parent, className); + this(parent, className, signature, access, superClass, interfaces, null); + } + + public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, + ClassEntry[] interfaces, String javadocs) { + super(parent, className, javadocs); Preconditions.checkNotNull(signature, "Class signature cannot be null"); Preconditions.checkNotNull(access, "Class access cannot be null"); @@ -82,16 +87,17 @@ public class ClassDefEntry extends ClassEntry implements DefEntry { AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access; ClassEntry translatedSuper = translator.translate(superClass); ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new); - return new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces); + String docs = mapping != null ? mapping.getJavadoc() : null; + return new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs); } @Override public ClassDefEntry withName(String name) { - return new ClassDefEntry(parent, name, signature, access, superClass, interfaces); + return new ClassDefEntry(parent, name, signature, access, superClass, interfaces, javadocs); } @Override public ClassDefEntry withParent(ClassEntry parent) { - return new ClassDefEntry(parent, name, signature, access, superClass, interfaces); + return new ClassDefEntry(parent, name, signature, access, superClass, interfaces, javadocs); } } diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java index 6bf4f964..23ce4a24 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java @@ -27,11 +27,15 @@ public class ClassEntry extends ParentedEntry implements Comparable< private final String fullName; public ClassEntry(String className) { - this(getOuterClass(className), getInnerName(className)); + this(getOuterClass(className), getInnerName(className), null); } public ClassEntry(@Nullable ClassEntry parent, String className) { - super(parent, className); + this(parent, className, null); + } + + public ClassEntry(@Nullable ClassEntry parent, String className, @Nullable String javadocs) { + super(parent, className, javadocs); if (parent != null) { fullName = parent.getFullName() + "$" + name; } else { @@ -69,7 +73,8 @@ public class ClassEntry extends ParentedEntry implements Comparable< } String translatedName = mapping != null ? mapping.getTargetName() : name; - return new ClassEntry(parent, translatedName); + String docs = mapping != null ? mapping.getJavadoc() : null; + return new ClassEntry(parent, translatedName, docs); } @Override @@ -103,12 +108,12 @@ public class ClassEntry extends ParentedEntry implements Comparable< @Override public ClassEntry withName(String name) { - return new ClassEntry(parent, name); + return new ClassEntry(parent, name, javadocs); } @Override public ClassEntry withParent(ClassEntry parent) { - return new ClassEntry(parent, name); + return new ClassEntry(parent, name, javadocs); } @Override diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java index 29a55d89..72b03913 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java @@ -22,6 +22,8 @@ import java.util.List; public interface Entry

> extends Translatable { String getName(); + String getJavadocs(); + default String getSourceRemapName() { return getName(); } diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java index 74176fda..46c0b003 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java @@ -26,7 +26,11 @@ public class FieldDefEntry extends FieldEntry implements DefEntry { private final Signature signature; public FieldDefEntry(ClassEntry owner, String name, TypeDescriptor desc, Signature signature, AccessFlags access) { - super(owner, name, desc); + this(owner, name, desc, signature, access, null); + } + + public FieldDefEntry(ClassEntry owner, String name, TypeDescriptor desc, Signature signature, AccessFlags access, String javadocs) { + super(owner, name, desc, javadocs); Preconditions.checkNotNull(access, "Field access cannot be null"); Preconditions.checkNotNull(signature, "Field signature cannot be null"); this.access = access; @@ -34,7 +38,7 @@ public class FieldDefEntry extends FieldEntry implements DefEntry { } public static FieldDefEntry parse(ClassEntry owner, int access, String name, String desc, String signature) { - return new FieldDefEntry(owner, name, new TypeDescriptor(desc), Signature.createTypedSignature(signature), new AccessFlags(access)); + return new FieldDefEntry(owner, name, new TypeDescriptor(desc), Signature.createTypedSignature(signature), new AccessFlags(access), null); } public static FieldDefEntry parse(FieldDefinition definition) { @@ -42,7 +46,7 @@ public class FieldDefEntry extends FieldEntry implements DefEntry { TypeDescriptor descriptor = new TypeDescriptor(definition.getErasedSignature()); Signature signature = Signature.createTypedSignature(definition.getSignature()); AccessFlags access = new AccessFlags(definition.getModifiers()); - return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access); + return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access, null); } @Override @@ -60,16 +64,17 @@ public class FieldDefEntry extends FieldEntry implements DefEntry { Signature translatedSignature = translator.translate(signature); String translatedName = mapping != null ? mapping.getTargetName() : name; AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access; - return new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess); + String docs = mapping != null ? mapping.getJavadoc() : null; + return new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs); } @Override public FieldDefEntry withName(String name) { - return new FieldDefEntry(parent, name, desc, signature, access); + return new FieldDefEntry(parent, name, desc, signature, access, javadocs); } @Override public FieldDefEntry withParent(ClassEntry owner) { - return new FieldDefEntry(owner, this.name, this.desc, signature, access); + return new FieldDefEntry(owner, this.name, this.desc, signature, access, javadocs); } } diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java index 700512e2..bef0edf4 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java @@ -23,7 +23,11 @@ public class FieldEntry extends ParentedEntry implements Comparable< protected final TypeDescriptor desc; public FieldEntry(ClassEntry parent, String name, TypeDescriptor desc) { - super(parent, name); + this(parent, name, desc, null); + } + + public FieldEntry(ClassEntry parent, String name, TypeDescriptor desc, String javadocs) { + super(parent, name, javadocs); Preconditions.checkNotNull(parent, "Owner cannot be null"); Preconditions.checkNotNull(desc, "Field descriptor cannot be null"); @@ -32,7 +36,7 @@ public class FieldEntry extends ParentedEntry implements Comparable< } public static FieldEntry parse(String owner, String name, String desc) { - return new FieldEntry(new ClassEntry(owner), name, new TypeDescriptor(desc)); + return new FieldEntry(new ClassEntry(owner), name, new TypeDescriptor(desc), null); } @Override @@ -46,18 +50,19 @@ public class FieldEntry extends ParentedEntry implements Comparable< @Override public FieldEntry withName(String name) { - return new FieldEntry(parent, name, desc); + return new FieldEntry(parent, name, desc, null); } @Override public FieldEntry withParent(ClassEntry parent) { - return new FieldEntry(parent, this.name, this.desc); + return new FieldEntry(parent, this.name, this.desc, null); } @Override protected FieldEntry translate(Translator translator, @Nullable EntryMapping mapping) { String translatedName = mapping != null ? mapping.getTargetName() : name; - return new FieldEntry(parent, translatedName, translator.translate(desc)); + String docs = mapping != null ? mapping.getJavadoc() : null; + return new FieldEntry(parent, translatedName, translator.translate(desc), docs); } @Override diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java index c6f32b62..aad4236d 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java @@ -15,8 +15,8 @@ import javax.annotation.Nullable; public class LocalVariableDefEntry extends LocalVariableEntry { protected final TypeDescriptor desc; - public LocalVariableDefEntry(MethodEntry ownerEntry, int index, String name, boolean parameter, TypeDescriptor desc) { - super(ownerEntry, index, name, parameter); + public LocalVariableDefEntry(MethodEntry ownerEntry, int index, String name, boolean parameter, TypeDescriptor desc, String javadoc) { + super(ownerEntry, index, name, parameter, javadoc); Preconditions.checkNotNull(desc, "Variable desc cannot be null"); this.desc = desc; @@ -30,17 +30,18 @@ public class LocalVariableDefEntry extends LocalVariableEntry { public LocalVariableDefEntry translate(Translator translator, @Nullable EntryMapping mapping) { TypeDescriptor translatedDesc = translator.translate(desc); String translatedName = mapping != null ? mapping.getTargetName() : name; - return new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc); + String javadoc = mapping != null ? mapping.getJavadoc() : javadocs; + return new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc); } @Override public LocalVariableDefEntry withName(String name) { - return new LocalVariableDefEntry(parent, index, name, parameter, desc); + return new LocalVariableDefEntry(parent, index, name, parameter, desc, javadocs); } @Override public LocalVariableDefEntry withParent(MethodEntry entry) { - return new LocalVariableDefEntry(entry, index, name, parameter, desc); + return new LocalVariableDefEntry(entry, index, name, parameter, desc, javadocs); } @Override diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java index 6fdb79fe..3ccb1fa1 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java @@ -17,8 +17,8 @@ public class LocalVariableEntry extends ParentedEntry implements Co protected final int index; protected final boolean parameter; - public LocalVariableEntry(MethodEntry parent, int index, String name, boolean parameter) { - super(parent, name); + public LocalVariableEntry(MethodEntry parent, int index, String name, boolean parameter, String javadoc) { + super(parent, name, javadoc); Preconditions.checkNotNull(parent, "Variable owner cannot be null"); Preconditions.checkArgument(index >= 0, "Index must be positive"); @@ -48,17 +48,18 @@ public class LocalVariableEntry extends ParentedEntry implements Co @Override public LocalVariableEntry translate(Translator translator, @Nullable EntryMapping mapping) { String translatedName = mapping != null ? mapping.getTargetName() : name; - return new LocalVariableEntry(parent, index, translatedName, parameter); + String javadoc = mapping != null ? mapping.getJavadoc() : null; + return new LocalVariableEntry(parent, index, translatedName, parameter, javadoc); } @Override public LocalVariableEntry withName(String name) { - return new LocalVariableEntry(parent, index, name, parameter); + return new LocalVariableEntry(parent, index, name, parameter, javadocs); } @Override public LocalVariableEntry withParent(MethodEntry parent) { - return new LocalVariableEntry(parent, index, name, parameter); + return new LocalVariableEntry(parent, index, name, parameter, javadocs); } @Override diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java index 7e89f6a6..280b605d 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java @@ -26,7 +26,11 @@ public class MethodDefEntry extends MethodEntry implements DefEntry private final Signature signature; public MethodDefEntry(ClassEntry owner, String name, MethodDescriptor descriptor, Signature signature, AccessFlags access) { - super(owner, name, descriptor); + this(owner, name, descriptor, signature, access, null); + } + + public MethodDefEntry(ClassEntry owner, String name, MethodDescriptor descriptor, Signature signature, AccessFlags access, String docs) { + super(owner, name, descriptor, docs); Preconditions.checkNotNull(access, "Method access cannot be null"); Preconditions.checkNotNull(signature, "Method signature cannot be null"); this.access = access; @@ -34,7 +38,7 @@ public class MethodDefEntry extends MethodEntry implements DefEntry } public static MethodDefEntry parse(ClassEntry owner, int access, String name, String desc, String signature) { - return new MethodDefEntry(owner, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access)); + return new MethodDefEntry(owner, name, new MethodDescriptor(desc), Signature.createSignature(signature), new AccessFlags(access), null); } public static MethodDefEntry parse(MethodDefinition definition) { @@ -42,7 +46,7 @@ public class MethodDefEntry extends MethodEntry implements DefEntry MethodDescriptor descriptor = new MethodDescriptor(definition.getErasedSignature()); Signature signature = Signature.createSignature(definition.getSignature()); AccessFlags access = new AccessFlags(definition.getModifiers()); - return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access); + return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access, null); } @Override @@ -60,16 +64,17 @@ public class MethodDefEntry extends MethodEntry implements DefEntry Signature translatedSignature = translator.translate(signature); String translatedName = mapping != null ? mapping.getTargetName() : name; AccessFlags translatedAccess = mapping != null ? mapping.getAccessModifier().transform(access) : access; - return new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess); + String docs = mapping != null ? mapping.getJavadoc() : null; + return new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs); } @Override public MethodDefEntry withName(String name) { - return new MethodDefEntry(parent, name, descriptor, signature, access); + return new MethodDefEntry(parent, name, descriptor, signature, access, javadocs); } @Override public MethodDefEntry withParent(ClassEntry parent) { - return new MethodDefEntry(new ClassEntry(parent.getFullName()), name, descriptor, signature, access); + return new MethodDefEntry(new ClassEntry(parent.getFullName()), name, descriptor, signature, access, javadocs); } } diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java index f5d5c744..e1ffad37 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java @@ -24,7 +24,11 @@ public class MethodEntry extends ParentedEntry implements Comparable protected final MethodDescriptor descriptor; public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor) { - super(parent, name); + this(parent, name, descriptor, null); + } + + public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor, String javadocs) { + super(parent, name, javadocs); Preconditions.checkNotNull(parent, "Parent cannot be null"); Preconditions.checkNotNull(descriptor, "Method descriptor cannot be null"); @@ -33,7 +37,7 @@ public class MethodEntry extends ParentedEntry implements Comparable } public static MethodEntry parse(String owner, String name, String desc) { - return new MethodEntry(new ClassEntry(owner), name, new MethodDescriptor(desc)); + return new MethodEntry(new ClassEntry(owner), name, new MethodDescriptor(desc), null); } @Override @@ -52,17 +56,18 @@ public class MethodEntry extends ParentedEntry implements Comparable @Override public MethodEntry translate(Translator translator, @Nullable EntryMapping mapping) { String translatedName = mapping != null ? mapping.getTargetName() : name; - return new MethodEntry(parent, translatedName, translator.translate(descriptor)); + String docs = mapping != null ? mapping.getJavadoc() : null; + return new MethodEntry(parent, translatedName, translator.translate(descriptor), docs); } @Override public MethodEntry withName(String name) { - return new MethodEntry(parent, name, descriptor); + return new MethodEntry(parent, name, descriptor, javadocs); } @Override public MethodEntry withParent(ClassEntry parent) { - return new MethodEntry(new ClassEntry(parent.getFullName()), name, descriptor); + return new MethodEntry(new ClassEntry(parent.getFullName()), name, descriptor, javadocs); } @Override diff --git a/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java b/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java index b753d3a3..cbc5faf5 100644 --- a/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java +++ b/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java @@ -24,10 +24,12 @@ import javax.annotation.Nullable; public abstract class ParentedEntry

> implements Entry

{ protected final P parent; protected final String name; + protected final @Nullable String javadocs; - protected ParentedEntry(P parent, String name) { + protected ParentedEntry(P parent, String name, String javadocs) { this.parent = parent; this.name = name; + this.javadocs = javadocs; Preconditions.checkNotNull(name, "Name cannot be null"); } @@ -51,6 +53,12 @@ public abstract class ParentedEntry

> implements Entry

{ return parent; } + @Nullable + @Override + public String getJavadocs() { + return javadocs; + } + @Override public ParentedEntry

translate(Translator translator, EntryResolver resolver, EntryMap mappings) { P parent = getParent(); -- cgit v1.2.3