From 58c0aeb15a65324de08a914dfa62cc68a516a4e3 Mon Sep 17 00:00:00 2001 From: Runemoro Date: Mon, 9 Mar 2020 06:04:08 -0400 Subject: CFR support (#192) * Add decompiler API * Add CFR support--- .../enigma/analysis/AddJavadocsAstTransform.java | 135 ------------ .../java/cuchaz/enigma/analysis/BuiltinPlugin.java | 14 +- .../java/cuchaz/enigma/analysis/ClassCache.java | 4 +- .../enigma/analysis/DropImportAstTransform.java | 33 --- .../analysis/DropVarModifiersAstTransform.java | 37 ---- .../java/cuchaz/enigma/analysis/SourceIndex.java | 240 --------------------- .../enigma/analysis/SourceIndexClassVisitor.java | 96 --------- .../enigma/analysis/SourceIndexMethodVisitor.java | 216 ------------------- .../cuchaz/enigma/analysis/SourceIndexVisitor.java | 38 ---- src/main/java/cuchaz/enigma/analysis/Token.java | 6 +- .../cuchaz/enigma/analysis/TreeDumpVisitor.java | 93 -------- 11 files changed, 14 insertions(+), 898 deletions(-) delete mode 100644 src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/DropImportAstTransform.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/DropVarModifiersAstTransform.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/SourceIndex.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java delete mode 100644 src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java (limited to 'src/main/java/cuchaz/enigma/analysis') diff --git a/src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java b/src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java deleted file mode 100644 index 17ae63d..0000000 --- a/src/main/java/cuchaz/enigma/analysis/AddJavadocsAstTransform.java +++ /dev/null @@ -1,135 +0,0 @@ -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/BuiltinPlugin.java b/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java index 12ef709..fddd9a8 100644 --- a/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java +++ b/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java @@ -1,16 +1,17 @@ package cuchaz.enigma.analysis; -import com.strobel.core.Pair; import cuchaz.enigma.api.EnigmaPlugin; import cuchaz.enigma.api.EnigmaPluginContext; import cuchaz.enigma.api.service.JarIndexerService; import cuchaz.enigma.api.service.NameProposalService; -import cuchaz.enigma.translation.mapping.ResolutionStrategy; +import cuchaz.enigma.source.DecompilerService; +import cuchaz.enigma.source.Decompilers; +import cuchaz.enigma.source.procyon.ProcyonDecompiler; import cuchaz.enigma.translation.representation.TypeDescriptor; 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.MethodEntry; +import cuchaz.enigma.utils.Pair; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; @@ -34,7 +35,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.UnaryOperator; public final class BuiltinPlugin implements EnigmaPlugin { @@ -44,6 +44,7 @@ public final class BuiltinPlugin implements EnigmaPlugin { @Override public void init(EnigmaPluginContext ctx) { registerEnumNamingService(ctx); + registerDecompilerServices(ctx); } private void registerEnumNamingService(EnigmaPluginContext ctx) { @@ -54,6 +55,11 @@ public final class BuiltinPlugin implements EnigmaPlugin { ctx.registerService("enigma:enum_name_proposer", NameProposalService.TYPE, ctx1 -> (obfEntry, remapper) -> Optional.ofNullable(names.get(obfEntry))); } + private void registerDecompilerServices(EnigmaPluginContext ctx) { + ctx.registerService("enigma:procyon", DecompilerService.TYPE, ctx1 -> Decompilers.PROCYON); + ctx.registerService("enigma:cfr", DecompilerService.TYPE, ctx1 -> Decompilers.CFR); + } + private static final class EnumFieldNameFindingVisitor extends ClassVisitor { private ClassEntry clazz; diff --git a/src/main/java/cuchaz/enigma/analysis/ClassCache.java b/src/main/java/cuchaz/enigma/analysis/ClassCache.java index 8453df1..d97b204 100644 --- a/src/main/java/cuchaz/enigma/analysis/ClassCache.java +++ b/src/main/java/cuchaz/enigma/analysis/ClassCache.java @@ -3,7 +3,7 @@ package cuchaz.enigma.analysis; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableSet; -import cuchaz.enigma.CompiledSource; +import cuchaz.enigma.ClassProvider; import cuchaz.enigma.ProgressListener; import cuchaz.enigma.analysis.index.JarIndex; import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor; @@ -22,7 +22,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -public final class ClassCache implements AutoCloseable, CompiledSource { +public final class ClassCache implements AutoCloseable, ClassProvider { private final FileSystem fileSystem; private final ImmutableSet classNames; diff --git a/src/main/java/cuchaz/enigma/analysis/DropImportAstTransform.java b/src/main/java/cuchaz/enigma/analysis/DropImportAstTransform.java deleted file mode 100644 index 991e91d..0000000 --- a/src/main/java/cuchaz/enigma/analysis/DropImportAstTransform.java +++ /dev/null @@ -1,33 +0,0 @@ -package cuchaz.enigma.analysis; - -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; -import com.strobel.decompiler.languages.java.ast.ImportDeclaration; -import com.strobel.decompiler.languages.java.ast.PackageDeclaration; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; - -public final class DropImportAstTransform implements IAstTransform { - public static final DropImportAstTransform INSTANCE = new DropImportAstTransform(); - - private DropImportAstTransform() { - } - - @Override - public void run(AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(), null); - } - - static class Visitor extends DepthFirstAstVisitor { - @Override - public Void visitPackageDeclaration(PackageDeclaration node, Void data) { - node.remove(); - return null; - } - - @Override - public Void visitImportDeclaration(ImportDeclaration node, Void data) { - node.remove(); - return null; - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/DropVarModifiersAstTransform.java b/src/main/java/cuchaz/enigma/analysis/DropVarModifiersAstTransform.java deleted file mode 100644 index 0be5891..0000000 --- a/src/main/java/cuchaz/enigma/analysis/DropVarModifiersAstTransform.java +++ /dev/null @@ -1,37 +0,0 @@ -package cuchaz.enigma.analysis; - -import com.strobel.decompiler.languages.java.ast.*; -import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; - -import javax.lang.model.element.Modifier; - -public final class DropVarModifiersAstTransform implements IAstTransform { - public static final DropVarModifiersAstTransform INSTANCE = new DropVarModifiersAstTransform(); - - private DropVarModifiersAstTransform() { - } - - @Override - public void run(AstNode compilationUnit) { - compilationUnit.acceptVisitor(new Visitor(), null); - } - - static class Visitor extends DepthFirstAstVisitor { - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, Void data) { - for (JavaModifierToken modifierToken : node.getChildrenByRole(EntityDeclaration.MODIFIER_ROLE)) { - if (modifierToken.getModifier() == Modifier.FINAL) { - modifierToken.remove(); - } - } - - return null; - } - - @Override - public Void visitVariableDeclaration(VariableDeclarationStatement node, Void data) { - node.removeModifier(Modifier.FINAL); - return null; - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java deleted file mode 100644 index a800f43..0000000 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java +++ /dev/null @@ -1,240 +0,0 @@ -/******************************************************************************* - * 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.analysis; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.strobel.decompiler.languages.Region; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import cuchaz.enigma.gui.SourceRemapper; -import cuchaz.enigma.translation.mapping.EntryResolver; -import cuchaz.enigma.translation.mapping.ResolutionStrategy; -import cuchaz.enigma.translation.representation.entry.Entry; - -import javax.annotation.Nullable; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class SourceIndex { - private static Pattern ANONYMOUS_INNER = Pattern.compile("\\$\\d+$"); - - private String source; - private TreeMap, Entry>> tokenToReference; - private Multimap, Entry>, Token> referenceToTokens; - private Map, Token> declarationToToken; - private List lineOffsets; - private boolean ignoreBadTokens; - - public SourceIndex(String source) { - this(source, true); - } - - public SourceIndex(String source, boolean ignoreBadTokens) { - this.source = source; - this.ignoreBadTokens = ignoreBadTokens; - this.tokenToReference = new TreeMap<>(); - this.referenceToTokens = HashMultimap.create(); - this.declarationToToken = Maps.newHashMap(); - calculateLineOffsets(); - } - - public static SourceIndex buildIndex(String sourceString, CompilationUnit sourceTree, boolean ignoreBadTokens) { - SourceIndex index = new SourceIndex(sourceString, ignoreBadTokens); - sourceTree.acceptVisitor(new SourceIndexVisitor(), index); - - return index; - } - - private void calculateLineOffsets() { - // count the lines - this.lineOffsets = Lists.newArrayList(); - this.lineOffsets.add(0); - for (int i = 0; i < source.length(); i++) { - if (source.charAt(i) == '\n') { - this.lineOffsets.add(i + 1); - } - } - } - - public SourceIndex remapTo(SourceRemapper.Result result) { - SourceIndex remapped = new SourceIndex(result.getSource(), ignoreBadTokens); - - for (Map.Entry, Token> entry : declarationToToken.entrySet()) { - remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue())); - } - - for (Map.Entry, Entry>, Collection> entry : referenceToTokens.asMap().entrySet()) { - EntryReference, Entry> reference = entry.getKey(); - Collection oldTokens = entry.getValue(); - - Collection newTokens = oldTokens.stream() - .map(result::getRemappedToken) - .collect(Collectors.toList()); - - remapped.referenceToTokens.putAll(reference, newTokens); - } - - for (Map.Entry, Entry>> entry : tokenToReference.entrySet()) { - remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue()); - } - - return remapped; - } - - public String getSource() { - return this.source; - } - - public Token getToken(AstNode node) { - - // get the text of the node - String name = ""; - if (node instanceof Identifier) { - name = ((Identifier) node).getName(); - } - - // get a token for this node's region - Region region = node.getRegion(); - if (region.getBeginLine() == 0 || region.getEndLine() == 0) { - // DEBUG - System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region)); - return null; - } - Token token = new Token(toPos(region.getBeginLine(), region.getBeginColumn()), toPos(region.getEndLine(), region.getEndColumn()), this.source); - if (token.start == 0) { - // DEBUG - System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region)); - return null; - } - - if (node instanceof Identifier && name.indexOf('$') >= 0 && node.getParent() instanceof ConstructorDeclaration && name.lastIndexOf('$') >= 0 && !ANONYMOUS_INNER.matcher(name).matches()) { - TypeDeclaration type = node.getParent().getParent() instanceof TypeDeclaration ? (TypeDeclaration) node.getParent().getParent() : null; - if (type != null) { - name = type.getName(); - token.end = token.start + name.length(); - } - } - - // DEBUG - // System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); - - // Tokens can have $ in name, even for top-level classes - //if (name.lastIndexOf('$') >= 0 && this.ignoreBadTokens) { - // // DEBUG - // System.err.println(String.format("WARNING: %s \"%s\" is probably a bad token. It was ignored", node.getNodeType(), name)); - // return null; - //} - - return token; - } - - public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) { - Token token = getToken(node); - if (token != null) { - EntryReference, Entry> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext); - this.tokenToReference.put(token, deobfReference); - this.referenceToTokens.put(deobfReference, token); - } - } - - public void addDeclaration(AstNode node, Entry deobfEntry) { - Token token = getToken(node); - if (token != null) { - EntryReference, Entry> reference = new EntryReference<>(deobfEntry, token.text); - this.tokenToReference.put(token, reference); - this.referenceToTokens.put(reference, token); - this.declarationToToken.put(deobfEntry, token); - } - } - - public Token getReferenceToken(int pos) { - Token token = this.tokenToReference.floorKey(new Token(pos, pos, null)); - if (token != null && token.contains(pos)) { - return token; - } - return null; - } - - public Collection getReferenceTokens(EntryReference, Entry> deobfReference) { - return this.referenceToTokens.get(deobfReference); - } - - @Nullable - public EntryReference, Entry> getReference(Token token) { - if (token == null) { - return null; - } - return this.tokenToReference.get(token); - } - - public Iterable referenceTokens() { - return this.tokenToReference.keySet(); - } - - public Iterable declarationTokens() { - return this.declarationToToken.values(); - } - - public Iterable> declarations() { - return this.declarationToToken.keySet(); - } - - public Token getDeclarationToken(Entry entry) { - return this.declarationToToken.get(entry); - } - - public int getLineNumber(int pos) { - // line number is 1-based - int line = 0; - for (Integer offset : this.lineOffsets) { - if (offset > pos) { - break; - } - line++; - } - return line; - } - - public int getColumnNumber(int pos) { - // column number is 1-based - return pos - this.lineOffsets.get(getLineNumber(pos) - 1) + 1; - } - - private int toPos(int line, int col) { - // line and col are 1-based - return this.lineOffsets.get(line - 1) + col - 1; - } - - public void resolveReferences(EntryResolver resolver) { - // resolve all the classes in the source references - for (Token token : Lists.newArrayList(referenceToTokens.values())) { - EntryReference, Entry> reference = tokenToReference.get(token); - EntryReference, Entry> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); - - // replace the reference - tokenToReference.replace(token, resolvedReference); - - Collection tokens = referenceToTokens.removeAll(reference); - referenceToTokens.putAll(resolvedReference, tokens); - } - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java deleted file mode 100644 index 2a72cb1..0000000 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************* - * 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.analysis; - -import com.strobel.assembler.metadata.FieldDefinition; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.languages.TextLocation; -import com.strobel.decompiler.languages.java.ast.*; -import cuchaz.enigma.translation.representation.entry.ClassDefEntry; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.FieldDefEntry; -import cuchaz.enigma.translation.representation.entry.MethodDefEntry; - -public class SourceIndexClassVisitor extends SourceIndexVisitor { - private ClassDefEntry classEntry; - - public SourceIndexClassVisitor(ClassDefEntry classEntry) { - this.classEntry = classEntry; - } - - @Override - public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { - // is this this class, or a subtype? - TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); - ClassDefEntry classEntry = ClassDefEntry.parse(def); - if (!classEntry.equals(this.classEntry)) { - // it's a subtype, recurse - index.addDeclaration(node.getNameToken(), classEntry); - return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); - } - - return visitChildren(node, index); - } - - @Override - public Void visitSimpleType(SimpleType node, SourceIndex index) { - TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); - if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { - ClassEntry classEntry = new ClassEntry(ref.getInternalName()); - index.addReference(node.getIdentifierToken(), classEntry, this.classEntry); - } - - return visitChildren(node, index); - } - - @Override - public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { - MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); - MethodDefEntry methodEntry = MethodDefEntry.parse(def); - AstNode tokenNode = node.getNameToken(); - if (methodEntry.isConstructor() && methodEntry.getName().equals("")) { - // for static initializers, check elsewhere for the token node - tokenNode = node.getModifiers().firstOrNullObject(); - } - index.addDeclaration(tokenNode, methodEntry); - return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); - } - - @Override - public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { - MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); - MethodDefEntry methodEntry = MethodDefEntry.parse(def); - index.addDeclaration(node.getNameToken(), methodEntry); - return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); - } - - @Override - public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { - FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); - FieldDefEntry fieldEntry = FieldDefEntry.parse(def); - assert (node.getVariables().size() == 1); - VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.addDeclaration(variable.getNameToken(), fieldEntry); - return visitChildren(node, index); - } - - @Override - public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { - // treat enum declarations as field declarations - FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); - FieldDefEntry fieldEntry = FieldDefEntry.parse(def); - index.addDeclaration(node.getNameToken(), fieldEntry); - return visitChildren(node, index); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java deleted file mode 100644 index dfe58ba..0000000 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexMethodVisitor.java +++ /dev/null @@ -1,216 +0,0 @@ -/******************************************************************************* - * 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.analysis; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.strobel.assembler.metadata.*; -import com.strobel.decompiler.ast.Variable; -import com.strobel.decompiler.languages.TextLocation; -import com.strobel.decompiler.languages.java.ast.*; -import cuchaz.enigma.translation.representation.MethodDescriptor; -import cuchaz.enigma.translation.representation.TypeDescriptor; -import cuchaz.enigma.translation.representation.entry.*; - -import java.lang.Error; -import java.util.HashMap; -import java.util.Map; - -public class SourceIndexMethodVisitor extends SourceIndexVisitor { - private final MethodDefEntry methodEntry; - - private Multimap unmatchedIdentifier = HashMultimap.create(); - private Map> identifierEntryCache = new HashMap<>(); - - public SourceIndexMethodVisitor(MethodDefEntry methodEntry) { - this.methodEntry = methodEntry; - } - - @Override - public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - - // get the behavior entry - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - MethodEntry methodEntry = null; - if (ref instanceof MethodReference) { - methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); - } - if (methodEntry != null) { - // get the node for the token - AstNode tokenNode = null; - if (node.getTarget() instanceof MemberReferenceExpression) { - tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); - } else if (node.getTarget() instanceof SuperReferenceExpression) { - tokenNode = node.getTarget(); - } else if (node.getTarget() instanceof ThisReferenceExpression) { - tokenNode = node.getTarget(); - } - if (tokenNode != null) { - index.addReference(tokenNode, methodEntry, this.methodEntry); - } - } - - // Check for identifier - node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) - .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); - return visitChildren(node, index); - } - - @Override - public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - if (ref instanceof FieldReference) { - // make sure this is actually a field - String erasedSignature = ref.getErasedSignature(); - if (erasedSignature.indexOf('(') >= 0) { - throw new Error("Expected a field here! got " + ref); - } - - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(erasedSignature)); - index.addReference(node.getMemberNameToken(), fieldEntry, this.methodEntry); - } - - return visitChildren(node, index); - } - - @Override - public Void visitSimpleType(SimpleType node, SourceIndex index) { - TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); - if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { - ClassEntry classEntry = new ClassEntry(ref.getInternalName()); - index.addReference(node.getIdentifierToken(), classEntry, this.methodEntry); - } - - return visitChildren(node, index); - } - - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { - ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION); - int parameterIndex = def.getSlot(); - - if (parameterIndex >= 0) { - MethodDefEntry ownerMethod = methodEntry; - if (def.getMethod() instanceof MethodDefinition) { - ownerMethod = MethodDefEntry.parse((MethodDefinition) def.getMethod()); - } - - TypeDescriptor parameterType = TypeDescriptor.parse(def.getParameterType()); - 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 visitChildren(node, index); - } - - @Override - public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - if (ref != null) { - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(ref.getErasedSignature())); - index.addReference(node.getIdentifierToken(), fieldEntry, this.methodEntry); - } else - this.checkIdentifier(node, index); - return visitChildren(node, index); - } - - private void checkIdentifier(IdentifierExpression node, SourceIndex index) { - if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! - index.addDeclaration(node.getIdentifierToken(), identifierEntryCache.get(node.getIdentifier())); - else - unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! - } - - private void addDeclarationToUnmatched(String key, SourceIndex index) { - Entry entry = identifierEntryCache.get(key); - - // This cannot happened in theory - if (entry == null) - return; - for (Identifier identifier : unmatchedIdentifier.get(key)) - index.addDeclaration(identifier, entry); - unmatchedIdentifier.removeAll(key); - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - if (ref != null && node.getType() instanceof SimpleType) { - SimpleType simpleTypeNode = (SimpleType) node.getType(); - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - MethodEntry constructorEntry = new MethodEntry(classEntry, "", new MethodDescriptor(ref.getErasedSignature())); - index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, this.methodEntry); - } - - return visitChildren(node, index); - } - - @Override - public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { - AstNodeCollection variables = node.getVariables(); - - // Single assignation - if (variables.size() == 1) { - VariableInitializer initializer = variables.firstOrNullObject(); - if (initializer != null && node.getType() instanceof SimpleType) { - Identifier identifier = initializer.getNameToken(); - Variable variable = initializer.getUserData(Keys.VARIABLE); - if (variable != null) { - VariableDefinition originalVariable = variable.getOriginalVariable(); - if (originalVariable != null) { - int variableIndex = originalVariable.getSlot(); - 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, null); - identifierEntryCache.put(identifier.getName(), localVariableEntry); - addDeclarationToUnmatched(identifier.getName(), index); - index.addDeclaration(identifier, localVariableEntry); - } - } - } - } - } - return visitChildren(node, index); - } - - @Override - public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - - if (ref instanceof MethodReference) { - // get the behavior entry - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - MethodEntry methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); - - // get the node for the token - AstNode methodNameToken = node.getMethodNameToken(); - AstNode targetToken = node.getTarget(); - - if (methodNameToken != null) { - index.addReference(methodNameToken, methodEntry, this.methodEntry); - } - - if (targetToken != null && !(targetToken instanceof ThisReferenceExpression)) { - index.addReference(targetToken, methodEntry.getParent(), this.methodEntry); - } - } - - return visitChildren(node, index); - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java deleted file mode 100644 index 8bd00a8..0000000 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * 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.analysis; - -import com.strobel.assembler.metadata.TypeDefinition; -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 extends DepthFirstAstVisitor { - @Override - public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { - TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); - ClassDefEntry classEntry = ClassDefEntry.parse(def); - index.addDeclaration(node.getNameToken(), classEntry); - - return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); - } - - @Override - protected Void visitChildren(AstNode node, SourceIndex index) { - for (final AstNode child : node.getChildren()) { - child.acceptVisitor(this, index); - } - return null; - } -} diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java index 12e0aa6..f0155e5 100644 --- a/src/main/java/cuchaz/enigma/analysis/Token.java +++ b/src/main/java/cuchaz/enigma/analysis/Token.java @@ -17,12 +17,10 @@ public class Token implements Comparable { public int end; public String text; - public Token(int start, int end, String source) { + public Token(int start, int end, String text) { this.start = start; this.end = end; - if (source != null) { - this.text = source.substring(start, end); - } + this.text = text; } public int getRenameOffset(String to) { diff --git a/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java deleted file mode 100644 index c85d97a..0000000 --- a/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * 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.analysis; - -import com.strobel.componentmodel.Key; -import com.strobel.decompiler.languages.java.ast.*; -import com.strobel.decompiler.patterns.Pattern; - -import java.io.*; -import java.nio.charset.Charset; - -public class TreeDumpVisitor extends DepthFirstAstVisitor { - - private File file; - private Writer out; - - public TreeDumpVisitor(File file) { - this.file = file; - } - - @Override - public Void visitCompilationUnit(CompilationUnit node, Void ignored) { - try { - out = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8")); - visitChildren(node, ignored); - out.close(); - return null; - } catch (IOException ex) { - throw new Error(ex); - } - } - - @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"); - } catch (IOException ex) { - throw new Error(ex); - } - - // recurse - for (final AstNode child : node.getChildren()) { - child.acceptVisitor(this, ignored); - } - return null; - } - - private String getText(AstNode node) { - if (node instanceof Identifier) { - return "\"" + ((Identifier) node).getName() + "\""; - } - return ""; - } - - private String dumpUserData(AstNode node) { - StringBuilder buf = new StringBuilder(); - for (Key key : Keys.ALL_KEYS) { - Object val = node.getUserData(key); - if (val != null) { - buf.append(String.format(" [%s=%s]", key, val)); - } - } - return buf.toString(); - } - - private String getIndent(AstNode node) { - StringBuilder buf = new StringBuilder(); - int depth = getDepth(node); - for (int i = 0; i < depth; i++) { - buf.append("\t"); - } - return buf.toString(); - } - - private int getDepth(AstNode node) { - int depth = -1; - while (node != null) { - depth++; - node = node.getParent(); - } - return depth; - } -} -- cgit v1.2.3