From a85529d1ce6ec533809575ec84572de855464b36 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 20 Aug 2014 01:21:52 -0400 Subject: finished reference navigation system. Still need to debug and polish it, but the basic idea seems to work. =) --- .../enigma/analysis/BehaviorReferenceTreeNode.java | 12 +- src/cuchaz/enigma/analysis/EntryReference.java | 89 ++- .../enigma/analysis/FieldReferenceTreeNode.java | 14 +- src/cuchaz/enigma/analysis/JarIndex.java | 43 +- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 6 +- src/cuchaz/enigma/analysis/SourceIndex.java | 51 +- .../analysis/SourceIndexBehaviorVisitor.java | 142 +++++ .../enigma/analysis/SourceIndexClassVisitor.java | 114 ++++ src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 600 --------------------- src/cuchaz/enigma/analysis/Token.java | 6 + 10 files changed, 408 insertions(+), 669 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java create mode 100644 src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java delete mode 100644 src/cuchaz/enigma/analysis/SourceIndexVisitor.java (limited to 'src/cuchaz/enigma/analysis') diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 158aad7..0f7e7f7 100644 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -21,13 +21,13 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.Translator; -public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { private static final long serialVersionUID = -3658163700783307520L; private Translator m_deobfuscatingTranslator; private BehaviorEntry m_entry; - private EntryReference m_reference; + private EntryReference m_reference; public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) { @@ -36,7 +36,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements m_reference = null; } - public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; @@ -50,7 +50,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements } @Override - public EntryReference getReference( ) + public EntryReference getReference( ) { return m_reference; } @@ -60,7 +60,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements { if( m_reference != null ) { - return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + return m_deobfuscatingTranslator.translateEntry( m_reference.context ).toString(); } return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); } @@ -68,7 +68,7 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements public void load( JarIndex index, boolean recurse ) { // get all the child nodes - for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) + for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) { add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); } diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java index f462210..869e08c 100644 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -10,19 +10,96 @@ ******************************************************************************/ package cuchaz.enigma.analysis; -import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.Util; +import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; -public class EntryReference +public class EntryReference { - public T entry; - public BehaviorEntry caller; + public E entry; + public C context; public int pos; - public EntryReference( T entry, BehaviorEntry caller, int pos ) + public EntryReference( E entry ) { + this( entry, null, -1 ); + } + + public EntryReference( E entry, C context, int pos ) + { + if( entry == null ) + { + throw new IllegalArgumentException( "Entry cannot be null!" ); + } + this.entry = entry; - this.caller = caller; + this.context = context; this.pos = pos; } + + public ClassEntry getClassEntry( ) + { + if( context != null ) + { + return context.getClassEntry(); + } + return entry.getClassEntry(); + } + + @Override + public int hashCode( ) + { + if( context != null ) + { + return Util.combineHashesOrdered( entry.hashCode(), context.hashCode(), Integer.valueOf( pos ).hashCode() ); + } + return entry.hashCode(); + } + + @Override + public boolean equals( Object other ) + { + if( other instanceof EntryReference ) + { + return equals( (EntryReference)other ); + } + return false; + } + + public boolean equals( EntryReference other ) + { + // check entry first + boolean isEntrySame = entry.equals( other.entry ); + if( !isEntrySame ) + { + return false; + } + + // check caller + if( context == null && other.context == null ) + { + return true; + } + else if( context != null && other.context != null ) + { + return context.equals( other.context ) && pos == other.pos; + } + return false; + } + + @Override + public String toString( ) + { + StringBuilder buf = new StringBuilder(); + buf.append( entry ); + if( context != null ) + { + buf.append( " called from " ); + buf.append( context ); + buf.append( " (" ); + buf.append( pos ); + buf.append( ")" ); + } + return buf.toString(); + } } diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index dd552d6..645e682 100644 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -16,13 +16,13 @@ import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.Translator; -public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { private static final long serialVersionUID = -7934108091928699835L; private Translator m_deobfuscatingTranslator; private FieldEntry m_entry; - private EntryReference m_reference; + private EntryReference m_reference; public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) { @@ -31,7 +31,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re m_reference = null; } - private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) { m_deobfuscatingTranslator = deobfuscatingTranslator; m_entry = reference.entry; @@ -45,7 +45,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re } @Override - public EntryReference getReference( ) + public EntryReference getReference( ) { return m_reference; } @@ -55,7 +55,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re { if( m_reference != null ) { - return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + return m_deobfuscatingTranslator.translateEntry( m_reference.context ).toString(); } return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); } @@ -65,14 +65,14 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re // get all the child nodes if( m_reference == null ) { - for( EntryReference reference : index.getFieldReferences( m_entry ) ) + for( EntryReference reference : index.getFieldReferences( m_entry ) ) { add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); } } else { - for( EntryReference reference : index.getBehaviorReferences( m_reference.caller ) ) + for( EntryReference reference : index.getBehaviorReferences( m_reference.context ) ) { add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); } diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index f1c29c5..f408d93 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -56,8 +56,8 @@ public class JarIndex private Set m_obfClassNames; private Ancestries m_ancestries; private Multimap m_methodImplementations; - private Multimap> m_behaviorReferences; - private Multimap> m_fieldReferences; + private Multimap> m_behaviorReferences; + private Multimap> m_fieldReferences; private Multimap m_innerClasses; private Map m_outerClasses; private Set m_anonymousClasses; @@ -108,12 +108,12 @@ public class JarIndex m_anonymousClasses.add( innerClassName ); // DEBUG - System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); + //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); } else { // DEBUG - System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); + //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); } } } @@ -172,7 +172,7 @@ public class JarIndex call.getSignature() ); callNumbers.add( calledMethodEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledMethodEntry, thisEntry, callNumbers.count( calledMethodEntry ) - 1 @@ -189,7 +189,7 @@ public class JarIndex call.getFieldName() ); callNumbers.add( calledFieldEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledFieldEntry, thisEntry, callNumbers.count( calledFieldEntry ) - 1 @@ -209,7 +209,7 @@ public class JarIndex call.getSignature() ); callNumbers.add( calledConstructorEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledConstructorEntry, thisEntry, callNumbers.count( calledConstructorEntry ) - 1 @@ -226,7 +226,7 @@ public class JarIndex call.getSignature() ); callNumbers.add( calledConstructorEntry ); - EntryReference reference = new EntryReference( + EntryReference reference = new EntryReference( calledConstructorEntry, thisEntry, callNumbers.count( calledConstructorEntry ) - 1 @@ -261,9 +261,9 @@ public class JarIndex new ClassEntry( Descriptor.toJvmName( c.getName() ) ), constructor.getMethodInfo().getDescriptor() ); - for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) + for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { - callerClasses.add( reference.caller.getClassEntry() ); + callerClasses.add( reference.context.getClassEntry() ); } // is this called by exactly one class? @@ -496,26 +496,14 @@ public class JarIndex return rootNode; } - @SuppressWarnings( "unchecked" ) - public Collection> getFieldReferences( FieldEntry fieldEntry ) + public Collection> getFieldReferences( FieldEntry fieldEntry ) { - List> references = Lists.newArrayList(); - for( EntryReference reference : m_fieldReferences.get( fieldEntry ) ) - { - references.add( (EntryReference)reference ); - } - return references; + return m_fieldReferences.get( fieldEntry ); } - @SuppressWarnings( "unchecked" ) - public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) + public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) { - List> references = Lists.newArrayList(); - for( EntryReference reference : m_behaviorReferences.get( behaviorEntry ) ) - { - references.add( (EntryReference)reference ); - } - return references; + return m_behaviorReferences.get( behaviorEntry ); } public Collection getInnerClasses( String obfOuterClassName ) @@ -613,8 +601,9 @@ public class JarIndex } else if( thing instanceof EntryReference ) { - EntryReference reference = (EntryReference)thing; + EntryReference reference = (EntryReference)thing; reference.entry = renameThing( renames, reference.entry ); + reference.context = renameThing( renames, reference.context ); return thing; } else diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java index 08ae39d..e0a0a74 100644 --- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java @@ -12,8 +12,8 @@ package cuchaz.enigma.analysis; import cuchaz.enigma.mapping.Entry; -public interface ReferenceTreeNode +public interface ReferenceTreeNode { - T getEntry(); - EntryReference getReference(); + E getEntry(); + EntryReference getReference(); } diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 645a71d..bf890e3 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -10,6 +10,7 @@ ******************************************************************************/ package cuchaz.enigma.analysis; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -24,15 +25,17 @@ import cuchaz.enigma.mapping.Entry; public class SourceIndex { private String m_source; - private TreeMap m_tokens; - private Map m_declarations; + private TreeMap> m_tokenToReference; + private HashMap,Token> m_referenceToToken; + private Map m_declarationToToken; private List m_lineOffsets; public SourceIndex( String source ) { m_source = source; - m_tokens = Maps.newTreeMap(); - m_declarations = Maps.newHashMap(); + m_tokenToReference = Maps.newTreeMap(); + m_referenceToToken = Maps.newHashMap(); + m_declarationToToken = Maps.newHashMap(); m_lineOffsets = Lists.newArrayList(); // count the lines @@ -87,12 +90,13 @@ public class SourceIndex return token; } - public void add( Identifier node, Entry deobfEntry ) + public void addReference( Identifier node, EntryReference deobfReference ) { Token token = getToken( node ); if( token != null ) { - m_tokens.put( token, deobfEntry ); + m_tokenToReference.put( token, deobfReference ); + m_referenceToToken.put( deobfReference, token ); } } @@ -101,19 +105,16 @@ public class SourceIndex Token token = getToken( node ); if( token != null ) { - m_tokens.put( token, deobfEntry ); - m_declarations.put( deobfEntry, token ); + EntryReference reference = new EntryReference( deobfEntry ); + m_tokenToReference.put( token, reference ); + m_referenceToToken.put( reference, token ); + m_declarationToToken.put( deobfEntry, token ); } } - public Token getToken( int pos ) + public Token getReferenceToken( int pos ) { - Map.Entry mapEntry = m_tokens.floorEntry( new Token( pos, pos ) ); - if( mapEntry == null ) - { - return null; - } - Token token = mapEntry.getKey(); + Token token = m_tokenToReference.floorKey( new Token( pos, pos ) ); if( token.contains( pos ) ) { return token; @@ -121,23 +122,33 @@ public class SourceIndex return null; } - public Entry getEntry( Token token ) + public Token getReferenceToken( EntryReference deobfReference ) + { + return m_referenceToToken.get( deobfReference ); + } + + public EntryReference getDeobfReference( Token token ) { if( token == null ) { return null; } - return m_tokens.get( token ); + return m_tokenToReference.get( token ); + } + + public Iterable referenceTokens( ) + { + return m_tokenToReference.keySet(); } - public Iterable tokens( ) + public Iterable declarationTokens( ) { - return m_tokens.keySet(); + return m_declarationToToken.values(); } public Token getDeclarationToken( Entry deobfEntry ) { - return m_declarations.get( deobfEntry ); + return m_declarationToToken.get( deobfEntry ); } private int toPos( int line, int col ) diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java new file mode 100644 index 0000000..d3386c5 --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.analysis; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.strobel.assembler.metadata.MemberReference; +import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.ParameterDefinition; +import com.strobel.assembler.metadata.TypeReference; +import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.IdentifierExpression; +import com.strobel.decompiler.languages.java.ast.InvocationExpression; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; +import com.strobel.decompiler.languages.java.ast.SimpleType; + +import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class SourceIndexBehaviorVisitor extends SourceIndexVisitor +{ + private BehaviorEntry m_behaviorEntry; + private Multiset m_indices; + + public SourceIndexBehaviorVisitor( BehaviorEntry behaviorEntry ) + { + m_behaviorEntry = behaviorEntry; + m_indices = HashMultiset.create(); + } + + @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 visitInvocationExpression( InvocationExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); + if( node.getTarget() instanceof MemberReferenceExpression ) + { + m_indices.add( methodEntry ); + index.addReference( + ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), + new EntryReference( methodEntry, m_behaviorEntry, m_indices.count( methodEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitMemberReferenceExpression( MemberReferenceExpression 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() ); + m_indices.add( fieldEntry ); + index.addReference( + node.getMemberNameToken(), + new EntryReference( fieldEntry, m_behaviorEntry, m_indices.count( fieldEntry ) ) + ); + } + + return recurse( 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() ); + m_indices.add( classEntry ); + index.addReference( + node.getIdentifierToken(), + new EntryReference( classEntry, m_behaviorEntry, m_indices.count( classEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) + { + ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodDefinition methodDef = (MethodDefinition)def.getMethod(); + MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); + ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); + index.addDeclaration( node.getNameToken(), argumentEntry ); + + return recurse( 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() ); + m_indices.add( fieldEntry ); + index.addReference( + node.getIdentifierToken(), + new EntryReference( fieldEntry, m_behaviorEntry, m_indices.count( fieldEntry ) ) + ); + } + + return recurse( node, index ); + } +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java new file mode 100644 index 0000000..2d4c0f5 --- /dev/null +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.analysis; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.strobel.assembler.metadata.FieldDefinition; +import com.strobel.assembler.metadata.MethodDefinition; +import com.strobel.assembler.metadata.TypeReference; +import com.strobel.decompiler.languages.TextLocation; +import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; +import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; +import com.strobel.decompiler.languages.java.ast.FieldDeclaration; +import com.strobel.decompiler.languages.java.ast.Keys; +import com.strobel.decompiler.languages.java.ast.MethodDeclaration; +import com.strobel.decompiler.languages.java.ast.SimpleType; +import com.strobel.decompiler.languages.java.ast.TypeDeclaration; +import com.strobel.decompiler.languages.java.ast.VariableInitializer; + +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.ConstructorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.MethodEntry; + +public class SourceIndexClassVisitor extends SourceIndexVisitor +{ + private ClassEntry m_classEntry; + private Multiset m_indices; + + public SourceIndexClassVisitor( ClassEntry classEntry ) + { + m_classEntry = classEntry; + m_indices = HashMultiset.create(); + } + + @Override + public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) + { + return recurse( 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(), + new EntryReference( classEntry, m_classEntry, m_indices.count( classEntry ) ) + ); + } + + return recurse( node, index ); + } + + @Override + public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) + { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); + index.addDeclaration( node.getNameToken(), methodEntry ); + //if( !def.getName().equals( "" ) ) + + return node.acceptVisitor( new SourceIndexBehaviorVisitor( methodEntry ), index ); + } + + @Override + public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) + { + MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); + index.addDeclaration( node.getNameToken(), constructorEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) + { + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + assert( node.getVariables().size() == 1 ); + VariableInitializer variable = node.getVariables().firstOrNullObject(); + index.addDeclaration( variable.getNameToken(), fieldEntry ); + + return recurse( node, index ); + } + + @Override + public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) + { + // treat enum declarations as field declarations + FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); + ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); + index.addDeclaration( node.getNameToken(), fieldEntry ); + + return recurse( node, index ); + } +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java deleted file mode 100644 index 841d176..0000000 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ /dev/null @@ -1,600 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import com.strobel.assembler.metadata.FieldDefinition; -import com.strobel.assembler.metadata.MemberReference; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.ParameterDefinition; -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.Annotation; -import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; -import com.strobel.decompiler.languages.java.ast.ArraySpecifier; -import com.strobel.decompiler.languages.java.ast.AssertStatement; -import com.strobel.decompiler.languages.java.ast.AssignmentExpression; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.BlockStatement; -import com.strobel.decompiler.languages.java.ast.BreakStatement; -import com.strobel.decompiler.languages.java.ast.CaseLabel; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.CatchClause; -import com.strobel.decompiler.languages.java.ast.ClassOfExpression; -import com.strobel.decompiler.languages.java.ast.Comment; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.ComposedType; -import com.strobel.decompiler.languages.java.ast.ConditionalExpression; -import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; -import com.strobel.decompiler.languages.java.ast.ContinueStatement; -import com.strobel.decompiler.languages.java.ast.DoWhileStatement; -import com.strobel.decompiler.languages.java.ast.EmptyStatement; -import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; -import com.strobel.decompiler.languages.java.ast.ExpressionStatement; -import com.strobel.decompiler.languages.java.ast.FieldDeclaration; -import com.strobel.decompiler.languages.java.ast.ForEachStatement; -import com.strobel.decompiler.languages.java.ast.ForStatement; -import com.strobel.decompiler.languages.java.ast.GotoStatement; -import com.strobel.decompiler.languages.java.ast.IAstVisitor; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.IdentifierExpression; -import com.strobel.decompiler.languages.java.ast.IfElseStatement; -import com.strobel.decompiler.languages.java.ast.ImportDeclaration; -import com.strobel.decompiler.languages.java.ast.IndexerExpression; -import com.strobel.decompiler.languages.java.ast.InstanceInitializer; -import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.JavaTokenNode; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.LabelStatement; -import com.strobel.decompiler.languages.java.ast.LabeledStatement; -import com.strobel.decompiler.languages.java.ast.LambdaExpression; -import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.MethodDeclaration; -import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; -import com.strobel.decompiler.languages.java.ast.NewLineNode; -import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.PackageDeclaration; -import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; -import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; -import com.strobel.decompiler.languages.java.ast.ReturnStatement; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; -import com.strobel.decompiler.languages.java.ast.SwitchSection; -import com.strobel.decompiler.languages.java.ast.SwitchStatement; -import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; -import com.strobel.decompiler.languages.java.ast.TextNode; -import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ThrowStatement; -import com.strobel.decompiler.languages.java.ast.TryCatchStatement; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; -import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.VariableInitializer; -import com.strobel.decompiler.languages.java.ast.WhileStatement; -import com.strobel.decompiler.languages.java.ast.WildcardType; -import com.strobel.decompiler.patterns.Pattern; - -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; - -public class SourceIndexVisitor implements IAstVisitor -{ - @Override - public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) - { - MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); - ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() ); - if( node.getTarget() instanceof MemberReferenceExpression ) - { - index.add( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), methodEntry ); - } - - return recurse( node, index ); - } - - @Override - public Void visitMemberReferenceExpression( MemberReferenceExpression 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() ); - index.add( node.getMemberNameToken(), fieldEntry ); - } - - return recurse( node, index ); - } - - @Override - public Void visitSimpleType( SimpleType node, SourceIndex index ) - { - TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); - if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) - { - index.add( node.getIdentifierToken(), new ClassEntry( ref.getInternalName() ) ); - } - - return recurse( node, index ); - } - - @Override - public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) - { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - - // static initializers don't have identifier tokens - if( !def.getName().equals( "" ) ) - { - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() ); - index.addDeclaration( node.getNameToken(), methodEntry ); - } - - return recurse( node, index ); - } - - @Override - public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) - { - MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); - index.addDeclaration( node.getNameToken(), constructorEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) - { - ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - MethodDefinition methodDef = (MethodDefinition)def.getMethod(); - MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() ); - ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() ); - index.addDeclaration( node.getNameToken(), argumentEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) - { - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - assert( node.getVariables().size() == 1 ); - VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.addDeclaration( variable.getNameToken(), fieldEntry ); - - return recurse( node, index ); - } - - @Override - public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) - { - TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); - index.addDeclaration( node.getNameToken(), new ClassEntry( def.getInternalName() ) ); - - return recurse( node, index ); - } - - @Override - public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) - { - // treat enum declarations as field declarations - FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); - ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); - FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); - index.addDeclaration( node.getNameToken(), fieldEntry ); - - return recurse( 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() ); - index.add( node.getIdentifierToken(), fieldEntry ); - } - - return recurse( node, index ); - } - - private Void recurse( AstNode node, SourceIndex index ) - { - for( final AstNode child : node.getChildren() ) - { - child.acceptVisitor( this, index ); - } - return null; - } - - // OVERRIDES WE DON'T CARE ABOUT - - @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/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java index 74023e3..d0f2b70 100644 --- a/src/cuchaz/enigma/analysis/Token.java +++ b/src/cuchaz/enigma/analysis/Token.java @@ -46,4 +46,10 @@ public class Token implements Comparable { return start == other.start && end == other.end; } + + @Override + public String toString( ) + { + return String.format( "[%d,%d]", start, end ); + } } -- cgit v1.2.3