summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2014-08-10 01:03:40 -0400
committerGravatar jeff2014-08-10 01:03:40 -0400
commitd24d2b9ad9b5c895020b56f700a72906346482e5 (patch)
treeda360c07209e6e327325db53dbb4df05e77cb7e9 /src
parentadded sorting for deobfuscated classes (diff)
downloadenigma-d24d2b9ad9b5c895020b56f700a72906346482e5.tar.gz
enigma-d24d2b9ad9b5c895020b56f700a72906346482e5.tar.xz
enigma-d24d2b9ad9b5c895020b56f700a72906346482e5.zip
completely re-wrote token recognizer to bootstrap from Procyon's AST
changed imports to guava instead of whatever collections library happened to be on my classpath
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java114
-rw-r--r--src/cuchaz/enigma/analysis/Analyzer.java263
-rw-r--r--src/cuchaz/enigma/analysis/ClassNameIndex.java19
-rw-r--r--src/cuchaz/enigma/analysis/Lexer.java79
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndex.java99
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexVisitor.java618
-rw-r--r--src/cuchaz/enigma/analysis/SourcedAst.java140
-rw-r--r--src/cuchaz/enigma/analysis/Token.java (renamed from src/cuchaz/enigma/analysis/JavaSourceFromString.java)40
-rw-r--r--src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java2
-rw-r--r--src/cuchaz/enigma/gui/Gui.java29
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java56
-rw-r--r--src/cuchaz/enigma/mapping/Ancestries.java2
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java24
-rw-r--r--src/cuchaz/enigma/mapping/EntryPair.java5
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java2
15 files changed, 845 insertions, 647 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index e6e647e9..8eda889f 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -10,12 +10,10 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import java.io.BufferedReader;
14import java.io.File; 13import java.io.File;
15import java.io.FileInputStream; 14import java.io.FileInputStream;
16import java.io.IOException; 15import java.io.IOException;
17import java.io.InputStream; 16import java.io.InputStream;
18import java.io.StringReader;
19import java.io.StringWriter; 17import java.io.StringWriter;
20import java.util.Enumeration; 18import java.util.Enumeration;
21import java.util.List; 19import java.util.List;
@@ -23,11 +21,26 @@ import java.util.Map;
23import java.util.jar.JarEntry; 21import java.util.jar.JarEntry;
24import java.util.jar.JarFile; 22import java.util.jar.JarFile;
25 23
26import com.beust.jcommander.internal.Lists; 24import com.google.common.collect.Lists;
27import com.strobel.decompiler.Decompiler; 25import com.strobel.assembler.metadata.MemberReference;
26import com.strobel.assembler.metadata.MetadataSystem;
27import com.strobel.assembler.metadata.TypeDefinition;
28import com.strobel.componentmodel.Key;
29import com.strobel.decompiler.DecompilerContext;
28import com.strobel.decompiler.DecompilerSettings; 30import com.strobel.decompiler.DecompilerSettings;
29import com.strobel.decompiler.PlainTextOutput; 31import com.strobel.decompiler.PlainTextOutput;
32import com.strobel.decompiler.languages.java.JavaOutputVisitor;
33import com.strobel.decompiler.languages.java.ast.AstBuilder;
34import com.strobel.decompiler.languages.java.ast.AstNode;
35import com.strobel.decompiler.languages.java.ast.CompilationUnit;
36import com.strobel.decompiler.languages.java.ast.Identifier;
37import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor;
38import com.strobel.decompiler.languages.java.ast.InvocationExpression;
39import com.strobel.decompiler.languages.java.ast.Keys;
40import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression;
30 41
42import cuchaz.enigma.analysis.SourceIndex;
43import cuchaz.enigma.analysis.SourceIndexVisitor;
31import cuchaz.enigma.mapping.Ancestries; 44import cuchaz.enigma.mapping.Ancestries;
32import cuchaz.enigma.mapping.ArgumentEntry; 45import cuchaz.enigma.mapping.ArgumentEntry;
33import cuchaz.enigma.mapping.ClassEntry; 46import cuchaz.enigma.mapping.ClassEntry;
@@ -91,7 +104,6 @@ public class Deobfuscator
91 104
92 // config the decompiler 105 // config the decompiler
93 m_settings = DecompilerSettings.javaDefaults(); 106 m_settings = DecompilerSettings.javaDefaults();
94 m_settings.setForceExplicitImports( true );
95 m_settings.setShowSyntheticMembers( true ); 107 m_settings.setShowSyntheticMembers( true );
96 108
97 // init mappings 109 // init mappings
@@ -157,7 +169,7 @@ public class Deobfuscator
157 } 169 }
158 } 170 }
159 171
160 public String getSource( final ClassFile classFile ) 172 public SourceIndex getSource( final ClassFile classFile )
161 { 173 {
162 // is this class deobfuscated? 174 // is this class deobfuscated?
163 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out 175 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
@@ -170,45 +182,79 @@ public class Deobfuscator
170 } 182 }
171 183
172 // decompile it! 184 // decompile it!
185 TypeDefinition resolvedType = new MetadataSystem( m_settings.getTypeLoader() ).lookupType( deobfName ).resolve();
186 DecompilerContext context = new DecompilerContext();
187 context.setCurrentType( resolvedType );
188 context.setSettings( m_settings );
189 AstBuilder builder = new AstBuilder( context );
190 builder.addType( resolvedType );
191 builder.runTransformations( null );
192 CompilationUnit root = builder.getCompilationUnit();
193
194 // render the AST into source
173 StringWriter buf = new StringWriter(); 195 StringWriter buf = new StringWriter();
174 Decompiler.decompile( deobfName, new PlainTextOutput( buf ), m_settings ); 196 root.acceptVisitor( new InsertParenthesesVisitor(), null );
175 return fixSource( buf.toString() ); 197 root.acceptVisitor( new JavaOutputVisitor( new PlainTextOutput( buf ), m_settings ), null );
198
199 // build the source index
200 SourceIndex index = new SourceIndex( buf.toString() );
201 root.acceptVisitor( new SourceIndexVisitor(), index );
202
203 return index;
176 } 204 }
177 205
178 private String fixSource( String source ) 206 private void dump( AstNode node, int depth )
179 { 207 {
180 // fix the imports from the default package in the source 208 StringBuilder buf = new StringBuilder();
181 try 209 for( int i=0; i<depth; i++ )
210 {
211 buf.append( "\t" );
212 }
213 buf.append( node.getClass().getSimpleName() );
214
215 MemberReference memberRef = node.getUserData( Keys.MEMBER_REFERENCE );
216 if( memberRef != null )
182 { 217 {
183 StringBuilder buf = new StringBuilder(); 218 buf.append( String.format( " (MemberReference: %s.%s -> %s)", memberRef.getDeclaringType(), memberRef.getName(), memberRef.getSignature() ) );
184 BufferedReader reader = new BufferedReader( new StringReader( source ) ); 219 }
185 String line = null; 220
186 while( ( line = reader.readLine() ) != null ) 221 for( Key<?> key : Keys.ALL_KEYS )
222 {
223 if( key == Keys.MEMBER_REFERENCE )
187 { 224 {
188 String[] parts = line.trim().split( " " ); 225 continue;
189 if( parts.length == 2 && parts[0].equals( "import" ) ) 226 }
190 { 227 Object val = node.getUserData( key );
191 // is this an (illegal) import from the default package? 228 if( val != null )
192 String className = parts[1]; 229 {
193 if( className.indexOf( '.' ) < 0 ) 230 buf.append( String.format( " (%s=%s)", key, val ) );
194 {
195 // this is an illegal import, replace it
196 line = "import __DEFAULT__." + parts[1];
197 }
198 }
199
200 buf.append( line );
201 buf.append( "\n" );
202 } 231 }
203 return buf.toString();
204 } 232 }
205 catch( IOException ex ) 233
234
235 if( node instanceof Identifier )
236 {
237 Identifier n = (Identifier)node;
238 buf.append( ": " + n.getName() );
239 }
240 else if( node instanceof MemberReferenceExpression )
241 {
242 MemberReferenceExpression n = (MemberReferenceExpression)node;
243 buf.append( ": " + n.getTarget() + "." + n.getMemberName() );
244 }
245 else if( node instanceof InvocationExpression )
206 { 246 {
207 // dealing with IOExceptions on StringReaders is silly... 247
208 throw new Error( ex ); 248 }
249
250 System.out.println( buf );
251
252 for( AstNode child : node.getChildren() )
253 {
254 dump( child, depth + 1 );
209 } 255 }
210 } 256 }
211 257
212 // NOTE: these methods are a bit messy... oh well 258 // NOTE: these methods are a bit messy... oh well
213 259
214 public void rename( Entry obfEntry, String newName ) 260 public void rename( Entry obfEntry, String newName )
diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java
deleted file mode 100644
index 2b7e0b0b..00000000
--- a/src/cuchaz/enigma/analysis/Analyzer.java
+++ /dev/null
@@ -1,263 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import java.io.IOException;
14import java.util.Arrays;
15
16import javax.tools.JavaCompiler;
17import javax.tools.StandardJavaFileManager;
18import javax.tools.ToolProvider;
19
20import jsyntaxpane.Token;
21import jsyntaxpane.TokenType;
22
23import com.sun.source.tree.ArrayTypeTree;
24import com.sun.source.tree.ClassTree;
25import com.sun.source.tree.CompilationUnitTree;
26import com.sun.source.tree.IdentifierTree;
27import com.sun.source.tree.MethodTree;
28import com.sun.source.tree.PrimitiveTypeTree;
29import com.sun.source.tree.Tree;
30import com.sun.source.tree.Tree.Kind;
31import com.sun.source.tree.VariableTree;
32import com.sun.source.util.JavacTask;
33import com.sun.source.util.TreeScanner;
34import com.sun.source.util.Trees;
35
36import cuchaz.enigma.mapping.ArgumentEntry;
37import cuchaz.enigma.mapping.ClassEntry;
38import cuchaz.enigma.mapping.Entry;
39import cuchaz.enigma.mapping.FieldEntry;
40import cuchaz.enigma.mapping.MethodEntry;
41
42class TreeVisitor extends TreeScanner<CompilationUnitTree, SourcedAst>
43{
44 private SourceIndex m_index;
45
46 public TreeVisitor( SourceIndex index )
47 {
48 m_index = index;
49 }
50
51 @Override
52 public CompilationUnitTree visitClass( ClassTree classTree, SourcedAst ast )
53 {
54 ClassEntry classEntry = indexClass( classTree, ast );
55
56 // look at the class members
57 for( Tree memberTree : classTree.getMembers() )
58 {
59 if( memberTree.getKind() == Kind.VARIABLE )
60 {
61 indexField( (VariableTree)memberTree, ast, classEntry );
62 }
63 else if( memberTree.getKind() == Kind.METHOD )
64 {
65 MethodTree methodTree = (MethodTree)memberTree;
66 MethodEntry methodEntry = indexMethod( methodTree, ast, classEntry );
67
68 // look at method arguments
69 int argNum = 0;
70 for( VariableTree variableTree : methodTree.getParameters() )
71 {
72 indexArgument( variableTree, ast, methodEntry, argNum++ );
73 }
74 }
75 }
76
77 return super.visitClass( classTree, ast );
78 }
79
80 private ClassEntry indexClass( ClassTree classTree, SourcedAst ast )
81 {
82 // index the class name
83 ClassEntry classEntry = indexClassIdentifier( classTree, ast );
84 assert( classEntry != null );
85
86 // index the extends clause
87 indexClassIdentifier( classTree.getExtendsClause(), ast );
88
89 // index the implements clauses
90 for( Tree implementsTree : classTree.getImplementsClause() )
91 {
92 indexClassIdentifier( implementsTree, ast );
93 }
94
95 return classEntry;
96 }
97
98 private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry )
99 {
100 // index the field name
101 FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() );
102 Token nameToken = new Lexer( ast.getSource( variableTree ) ).getFirstIdentifierMatching( variableTree.getName() );
103 addToken( entry, nameToken, variableTree, ast );
104
105 // index the field type
106 indexClassIdentifier( variableTree.getType(), ast );
107
108 return entry;
109 }
110
111 private MethodEntry indexMethod( MethodTree methodTree, SourcedAst ast, ClassEntry classEntry )
112 {
113 // build the entry
114 StringBuilder signature = new StringBuilder();
115 signature.append( "(" );
116 for( VariableTree variableTree : methodTree.getParameters() )
117 {
118 signature.append( toJvmType( variableTree.getType(), ast ) );
119 }
120 signature.append( ")" );
121 if( methodTree.getReturnType() != null )
122 {
123 signature.append( toJvmType( methodTree.getReturnType(), ast ) );
124 }
125 else
126 {
127 signature.append( "V" );
128 }
129 MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() );
130
131 // lex the source at this tree node
132 Lexer lexer = new Lexer( ast.getSource( methodTree ) );
133 for( Token token : lexer )
134 {
135 // scan until we find an identifier that matches the method name
136 if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) )
137 {
138 addToken( entry, token, methodTree, ast );
139 break;
140 }
141 }
142
143 return entry;
144 }
145
146 private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index )
147 {
148 // index argument name
149 ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() );
150 Token token = new Lexer( ast.getSource( variableTree ) ).getLastIdentifier();
151 addToken( entry, token, variableTree, ast );
152
153 // index argument type
154 indexClassIdentifier( variableTree.getType(), ast );
155 }
156
157 private ClassEntry indexClassIdentifier( Tree tree, SourcedAst ast )
158 {
159 if( tree == null )
160 {
161 return null;
162 }
163
164 Lexer lexer = new Lexer( ast.getSource( tree ) );
165 Token token = lexer.getFirstIdentifier();
166 if( token == null )
167 {
168 return null;
169 }
170
171 ClassEntry classEntry = new ClassEntry( ast.getFullClassName( lexer.getText( token ) ) );
172 addToken( classEntry, token, tree, ast );
173 return classEntry;
174 }
175
176 private void addToken( Entry entry, Token token, Tree tree, SourcedAst ast )
177 {
178 if( token == null )
179 {
180 throw new IllegalArgumentException( "token cannot be null!" );
181 }
182
183 // offset the token by the tree
184 Token offsetToken = new Token( token.type, token.start + ast.getStart( tree ), token.length );
185
186 m_index.add( entry, offsetToken );
187 }
188
189 private String toJvmType( Tree tree, SourcedAst ast )
190 {
191 switch( tree.getKind() )
192 {
193 case PRIMITIVE_TYPE:
194 {
195 PrimitiveTypeTree primitiveTypeTree = (PrimitiveTypeTree)tree;
196 switch( primitiveTypeTree.getPrimitiveTypeKind() )
197 {
198 case BOOLEAN: return "Z";
199 case BYTE: return "B";
200 case CHAR: return "C";
201 case DOUBLE: return "D";
202 case FLOAT: return "F";
203 case INT: return "I";
204 case LONG: return "J";
205 case SHORT: return "S";
206 case VOID: return "V";
207
208 default:
209 throw new Error( "Unsupported primitive type: " + primitiveTypeTree.getPrimitiveTypeKind() );
210 }
211 }
212
213 case IDENTIFIER:
214 {
215 IdentifierTree identifierTree = (IdentifierTree)tree;
216 String className = identifierTree.getName().toString();
217 className = ast.getFullClassName( className );
218 return "L" + className.replace( ".", "/" ) + ";";
219 }
220
221 case ARRAY_TYPE:
222 {
223 ArrayTypeTree arrayTree = (ArrayTypeTree)tree;
224 return "[" + toJvmType( arrayTree.getType(), ast );
225 }
226
227
228 default:
229 throw new Error( "Unsupported type kind: " + tree.getKind() );
230 }
231 }
232}
233
234public class Analyzer
235{
236 public static SourceIndex analyze( String className, String source )
237 {
238 SourceIndex index = new SourceIndex();
239 SourcedAst ast = getAst( className, source );
240 ast.visit( new TreeVisitor( index ) );
241 return index;
242 }
243
244 private static SourcedAst getAst( String className, String source )
245 {
246 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
247 StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
248 JavaSourceFromString unit = new JavaSourceFromString( className, source );
249 JavacTask task = (JavacTask)compiler.getTask( null, fileManager, null, null, null, Arrays.asList( unit ) );
250
251 try
252 {
253 return new SourcedAst(
254 task.parse().iterator().next(),
255 Trees.instance( task )
256 );
257 }
258 catch( IOException ex )
259 {
260 throw new Error( ex );
261 }
262 }
263}
diff --git a/src/cuchaz/enigma/analysis/ClassNameIndex.java b/src/cuchaz/enigma/analysis/ClassNameIndex.java
deleted file mode 100644
index ea3e2cae..00000000
--- a/src/cuchaz/enigma/analysis/ClassNameIndex.java
+++ /dev/null
@@ -1,19 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import com.sun.source.tree.CompilationUnitTree;
14import com.sun.source.util.TreeScanner;
15
16public class ClassNameIndex extends TreeScanner<CompilationUnitTree, SourcedAst>
17{
18
19}
diff --git a/src/cuchaz/enigma/analysis/Lexer.java b/src/cuchaz/enigma/analysis/Lexer.java
deleted file mode 100644
index 602e3a9b..00000000
--- a/src/cuchaz/enigma/analysis/Lexer.java
+++ /dev/null
@@ -1,79 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import java.util.Iterator;
14
15import jsyntaxpane.SyntaxDocument;
16import jsyntaxpane.Token;
17import jsyntaxpane.TokenType;
18import jsyntaxpane.lexers.JavaLexer;
19
20public class Lexer implements Iterable<Token>
21{
22 private SyntaxDocument m_doc;
23 private Iterator<Token> m_iter;
24
25 public Lexer( CharSequence source )
26 {
27 m_doc = new SyntaxDocument( new JavaLexer() );
28 m_doc.append( source.toString() );
29 m_iter = m_doc.getTokens( 0, m_doc.getLength() );
30 }
31
32 @Override
33 public Iterator<Token> iterator( )
34 {
35 return m_iter;
36 }
37
38 public String getText( Token token )
39 {
40 return token.getString( m_doc );
41 }
42
43 public Token getFirstIdentifier( )
44 {
45 for( Token token : this )
46 {
47 if( token.type == TokenType.IDENTIFIER )
48 {
49 return token;
50 }
51 }
52 return null;
53 }
54
55 public Token getFirstIdentifierMatching( CharSequence val )
56 {
57 for( Token token : this )
58 {
59 if( token.type == TokenType.IDENTIFIER && getText( token ).equals( val.toString() ) )
60 {
61 return token;
62 }
63 }
64 return null;
65 }
66
67 public Token getLastIdentifier( )
68 {
69 Token lastToken = null;
70 for( Token token : this )
71 {
72 if( token.type == TokenType.IDENTIFIER )
73 {
74 lastToken = token;
75 }
76 }
77 return lastToken;
78 }
79}
diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java
index de163087..398a50d1 100644
--- a/src/cuchaz/enigma/analysis/SourceIndex.java
+++ b/src/cuchaz/enigma/analysis/SourceIndex.java
@@ -10,70 +10,101 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13import java.util.Collection; 13import java.util.List;
14import java.util.Iterator;
15import java.util.Map; 14import java.util.Map;
15import java.util.TreeMap;
16 16
17import jsyntaxpane.Token; 17import com.google.common.collect.Lists;
18 18import com.google.common.collect.Maps;
19import com.google.common.collect.HashMultimap; 19import com.strobel.decompiler.languages.Region;
20import com.google.common.collect.Multimap; 20import com.strobel.decompiler.languages.java.ast.AstNode;
21 21
22import cuchaz.enigma.mapping.Entry; 22import cuchaz.enigma.mapping.Entry;
23 23
24public class SourceIndex implements Iterable<Map.Entry<Entry,Token>> 24public class SourceIndex
25{ 25{
26 private Multimap<Entry,Token> m_entryToTokens; 26 private String m_source;
27 private TreeMap<Token,Entry> m_tokens;
28 private List<Integer> m_lineOffsets;
27 29
28 public SourceIndex( ) 30 public SourceIndex( String source )
29 { 31 {
30 m_entryToTokens = HashMultimap.create(); 32 m_source = source;
33 m_tokens = Maps.newTreeMap();
34 m_lineOffsets = Lists.newArrayList();
35
36 // count the lines
37 m_lineOffsets.add( 0 );
38 for( int i=0; i<source.length(); i++ )
39 {
40 if( source.charAt( i ) == '\n' )
41 {
42 m_lineOffsets.add( i + 1 );
43 }
44 }
31 } 45 }
32 46
33 public void add( Entry entry, Token token ) 47 public String getSource( )
34 { 48 {
35 m_entryToTokens.put( entry, token ); 49 return m_source;
36 } 50 }
37 51
38 public Iterator<Map.Entry<Entry,Token>> iterator( ) 52 public Token getToken( AstNode node )
39 { 53 {
40 return m_entryToTokens.entries().iterator(); 54 // get a token for this node's region
55 Region region = node.getRegion();
56 if( region.getBeginLine() == 0 || region.getEndLine() == 0 )
57 {
58 throw new IllegalArgumentException( "Invalid region: " + region );
59 }
60 return new Token(
61 toPos( region.getBeginLine(), region.getBeginColumn() ),
62 toPos( region.getEndLine(), region.getEndColumn() )
63 );
41 } 64 }
42 65
43 public Collection<Token> tokens( ) 66 public void add( AstNode node, Entry entry )
44 { 67 {
45 return m_entryToTokens.values(); 68 m_tokens.put( getToken( node ), entry );
46 } 69 }
47 70
48 public Entry getEntry( Token token ) 71 public void add( Token token, Entry entry )
72 {
73 m_tokens.put( token, entry );
74 }
75
76 public Token getToken( int pos )
49 { 77 {
50 // linear search is fast enough for now 78 Map.Entry<Token,Entry> mapEntry = m_tokens.floorEntry( new Token( pos, pos ) );
51 for( Map.Entry<Entry,Token> entry : this ) 79 if( mapEntry == null )
52 { 80 {
53 if( entry.getValue().equals( token ) ) 81 return null;
54 { 82 }
55 return entry.getKey(); 83 Token token = mapEntry.getKey();
56 } 84 if( token.contains( pos ) )
85 {
86 return token;
57 } 87 }
58 return null; 88 return null;
59 } 89 }
60 90
61 public Map.Entry<Entry,Token> getEntry( int pos ) 91 public Entry getEntry( Token token )
62 { 92 {
63 // linear search is fast enough for now 93 if( token == null )
64 for( Map.Entry<Entry,Token> entry : this )
65 { 94 {
66 Token token = entry.getValue(); 95 return null;
67 if( pos >= token.start && pos <= token.end() )
68 {
69 return entry;
70 }
71 } 96 }
72 return null; 97 return m_tokens.get( token );
98 }
99
100 public Iterable<Token> tokens( )
101 {
102 return m_tokens.keySet();
73 } 103 }
74 104
75 public Collection<Token> getTokens( Entry entry ) 105 private int toPos( int line, int col )
76 { 106 {
77 return m_entryToTokens.get( entry ); 107 // line and col are 1-based
108 return m_lineOffsets.get( line - 1 ) + col - 1;
78 } 109 }
79} 110}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
new file mode 100644
index 00000000..2a26c85f
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
@@ -0,0 +1,618 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import com.strobel.assembler.metadata.FieldDefinition;
14import com.strobel.assembler.metadata.MemberReference;
15import com.strobel.assembler.metadata.MethodDefinition;
16import com.strobel.assembler.metadata.ParameterDefinition;
17import com.strobel.assembler.metadata.TypeDefinition;
18import com.strobel.assembler.metadata.TypeReference;
19import com.strobel.componentmodel.Key;
20import com.strobel.decompiler.languages.TextLocation;
21import com.strobel.decompiler.languages.java.ast.Annotation;
22import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression;
23import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression;
24import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression;
25import com.strobel.decompiler.languages.java.ast.ArraySpecifier;
26import com.strobel.decompiler.languages.java.ast.AssertStatement;
27import com.strobel.decompiler.languages.java.ast.AssignmentExpression;
28import com.strobel.decompiler.languages.java.ast.AstNode;
29import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression;
30import com.strobel.decompiler.languages.java.ast.BlockStatement;
31import com.strobel.decompiler.languages.java.ast.BreakStatement;
32import com.strobel.decompiler.languages.java.ast.CaseLabel;
33import com.strobel.decompiler.languages.java.ast.CastExpression;
34import com.strobel.decompiler.languages.java.ast.CatchClause;
35import com.strobel.decompiler.languages.java.ast.ClassOfExpression;
36import com.strobel.decompiler.languages.java.ast.Comment;
37import com.strobel.decompiler.languages.java.ast.CompilationUnit;
38import com.strobel.decompiler.languages.java.ast.ComposedType;
39import com.strobel.decompiler.languages.java.ast.ConditionalExpression;
40import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration;
41import com.strobel.decompiler.languages.java.ast.ContinueStatement;
42import com.strobel.decompiler.languages.java.ast.DoWhileStatement;
43import com.strobel.decompiler.languages.java.ast.EmptyStatement;
44import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration;
45import com.strobel.decompiler.languages.java.ast.Expression;
46import com.strobel.decompiler.languages.java.ast.ExpressionStatement;
47import com.strobel.decompiler.languages.java.ast.FieldDeclaration;
48import com.strobel.decompiler.languages.java.ast.ForEachStatement;
49import com.strobel.decompiler.languages.java.ast.ForStatement;
50import com.strobel.decompiler.languages.java.ast.GotoStatement;
51import com.strobel.decompiler.languages.java.ast.IAstVisitor;
52import com.strobel.decompiler.languages.java.ast.Identifier;
53import com.strobel.decompiler.languages.java.ast.IdentifierExpression;
54import com.strobel.decompiler.languages.java.ast.IfElseStatement;
55import com.strobel.decompiler.languages.java.ast.ImportDeclaration;
56import com.strobel.decompiler.languages.java.ast.IndexerExpression;
57import com.strobel.decompiler.languages.java.ast.InstanceInitializer;
58import com.strobel.decompiler.languages.java.ast.InstanceOfExpression;
59import com.strobel.decompiler.languages.java.ast.InvocationExpression;
60import com.strobel.decompiler.languages.java.ast.JavaTokenNode;
61import com.strobel.decompiler.languages.java.ast.Keys;
62import com.strobel.decompiler.languages.java.ast.LabelStatement;
63import com.strobel.decompiler.languages.java.ast.LabeledStatement;
64import com.strobel.decompiler.languages.java.ast.LambdaExpression;
65import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement;
66import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression;
67import com.strobel.decompiler.languages.java.ast.MethodDeclaration;
68import com.strobel.decompiler.languages.java.ast.MethodGroupExpression;
69import com.strobel.decompiler.languages.java.ast.NewLineNode;
70import com.strobel.decompiler.languages.java.ast.NullReferenceExpression;
71import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression;
72import com.strobel.decompiler.languages.java.ast.PackageDeclaration;
73import com.strobel.decompiler.languages.java.ast.ParameterDeclaration;
74import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression;
75import com.strobel.decompiler.languages.java.ast.PrimitiveExpression;
76import com.strobel.decompiler.languages.java.ast.ReturnStatement;
77import com.strobel.decompiler.languages.java.ast.SimpleType;
78import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression;
79import com.strobel.decompiler.languages.java.ast.SwitchSection;
80import com.strobel.decompiler.languages.java.ast.SwitchStatement;
81import com.strobel.decompiler.languages.java.ast.SynchronizedStatement;
82import com.strobel.decompiler.languages.java.ast.TextNode;
83import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression;
84import com.strobel.decompiler.languages.java.ast.ThrowStatement;
85import com.strobel.decompiler.languages.java.ast.TryCatchStatement;
86import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
87import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration;
88import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression;
89import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression;
90import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement;
91import com.strobel.decompiler.languages.java.ast.VariableInitializer;
92import com.strobel.decompiler.languages.java.ast.WhileStatement;
93import com.strobel.decompiler.languages.java.ast.WildcardType;
94import com.strobel.decompiler.patterns.Pattern;
95
96import cuchaz.enigma.mapping.ArgumentEntry;
97import cuchaz.enigma.mapping.ClassEntry;
98import cuchaz.enigma.mapping.FieldEntry;
99import cuchaz.enigma.mapping.MethodEntry;
100
101public class SourceIndexVisitor implements IAstVisitor<SourceIndex, Void>
102{
103 @Override
104 public Void visitComment( Comment node, SourceIndex index )
105 {
106 return recurse( node, index );
107 }
108
109 @Override
110 public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index )
111 {
112 return recurse( node, index );
113 }
114
115 @Override
116 public Void visitInvocationExpression( InvocationExpression node, SourceIndex index )
117 {
118 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE );
119 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() );
120 MethodEntry methodEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() );
121 if( node.getTarget() instanceof MemberReferenceExpression )
122 {
123 index.add( ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(), methodEntry );
124 }
125
126 return recurse( node, index );
127 }
128
129 @Override
130 public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index )
131 {
132 return recurse( node, index );
133 }
134
135 @Override
136 public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index )
137 {
138 return recurse( node, index );
139 }
140
141 @Override
142 public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index )
143 {
144 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE );
145 if( ref != null )
146 {
147 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() );
148 FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() );
149 index.add( node.getMemberNameToken(), fieldEntry );
150 }
151
152 return recurse( node, index );
153 }
154
155 @Override
156 public Void visitIdentifier( Identifier node, SourceIndex index )
157 {
158 return recurse( node, index );
159 }
160
161 @Override
162 public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index )
163 {
164 return recurse( node, index );
165 }
166
167 @Override
168 public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index )
169 {
170 return recurse( node, index );
171 }
172
173 @Override
174 public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index )
175 {
176 return recurse( node, index );
177 }
178
179 @Override
180 public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index )
181 {
182 return recurse( node, index );
183 }
184
185 @Override
186 public Void visitBlockStatement( BlockStatement node, SourceIndex index )
187 {
188 return recurse( node, index );
189 }
190
191 @Override
192 public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index )
193 {
194 return recurse( node, index );
195 }
196
197 @Override
198 public Void visitBreakStatement( BreakStatement node, SourceIndex index )
199 {
200 return recurse( node, index );
201 }
202
203 @Override
204 public Void visitContinueStatement( ContinueStatement node, SourceIndex index )
205 {
206 return recurse( node, index );
207 }
208
209 @Override
210 public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index )
211 {
212 return recurse( node, index );
213 }
214
215 @Override
216 public Void visitEmptyStatement( EmptyStatement node, SourceIndex index )
217 {
218 return recurse( node, index );
219 }
220
221 @Override
222 public Void visitIfElseStatement( IfElseStatement node, SourceIndex index )
223 {
224 return recurse( node, index );
225 }
226
227 @Override
228 public Void visitLabelStatement( LabelStatement node, SourceIndex index )
229 {
230 return recurse( node, index );
231 }
232
233 @Override
234 public Void visitLabeledStatement( LabeledStatement node, SourceIndex index )
235 {
236 return recurse( node, index );
237 }
238
239 @Override
240 public Void visitReturnStatement( ReturnStatement node, SourceIndex index )
241 {
242 return recurse( node, index );
243 }
244
245 @Override
246 public Void visitSwitchStatement( SwitchStatement node, SourceIndex index )
247 {
248 return recurse( node, index );
249 }
250
251 @Override
252 public Void visitSwitchSection( SwitchSection node, SourceIndex index )
253 {
254 return recurse( node, index );
255 }
256
257 @Override
258 public Void visitCaseLabel( CaseLabel node, SourceIndex index )
259 {
260 return recurse( node, index );
261 }
262
263 @Override
264 public Void visitThrowStatement( ThrowStatement node, SourceIndex index )
265 {
266 return recurse( node, index );
267 }
268
269 @Override
270 public Void visitCatchClause( CatchClause node, SourceIndex index )
271 {
272 return recurse( node, index );
273 }
274
275 @Override
276 public Void visitAnnotation( Annotation node, SourceIndex index )
277 {
278 return recurse( node, index );
279 }
280
281 @Override
282 public Void visitNewLine( NewLineNode node, SourceIndex index )
283 {
284 return recurse( node, index );
285 }
286
287 @Override
288 public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index )
289 {
290 return recurse( node, index );
291 }
292
293 @Override
294 public Void visitVariableInitializer( VariableInitializer node, SourceIndex index )
295 {
296 return recurse( node, index );
297 }
298
299 @Override
300 public Void visitText( TextNode node, SourceIndex index )
301 {
302 return recurse( node, index );
303 }
304
305 @Override
306 public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index )
307 {
308 return recurse( node, index );
309 }
310
311 @Override
312 public Void visitSimpleType( SimpleType node, SourceIndex index )
313 {
314 TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE );
315 if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY )
316 {
317 index.add( node.getIdentifierToken(), new ClassEntry( ref.getInternalName() ) );
318 }
319
320 return recurse( node, index );
321 }
322
323 @Override
324 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index )
325 {
326 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION );
327 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() );
328 MethodEntry methodEntry = new MethodEntry( classEntry, def.getName(), def.getSignature() );
329 index.add( node.getNameToken(), methodEntry );
330
331 return recurse( node, index );
332 }
333
334 @Override
335 public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index )
336 {
337 return recurse( node, index );
338 }
339
340 @Override
341 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index )
342 {
343 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION );
344 index.add( node.getNameToken(), new ClassEntry( def.getDeclaringType().getInternalName() ) );
345
346 return recurse( node, index );
347 }
348
349 @Override
350 public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index )
351 {
352 return recurse( node, index );
353 }
354
355 @Override
356 public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index )
357 {
358 ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION );
359 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() );
360 MethodDefinition methodDef = (MethodDefinition)def.getMethod();
361 MethodEntry methodEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() );
362 ArgumentEntry argumentEntry = new ArgumentEntry( methodEntry, def.getPosition(), def.getName() );
363 index.add( node.getNameToken(), argumentEntry );
364
365 return recurse( node, index );
366 }
367
368 @Override
369 public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index )
370 {
371 FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION );
372 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() );
373 FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() );
374 assert( node.getVariables().size() == 1 );
375 VariableInitializer variable = node.getVariables().firstOrNullObject();
376 index.add( variable.getNameToken(), fieldEntry );
377
378 return recurse( node, index );
379 }
380
381 @Override
382 public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index )
383 {
384 TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION );
385 index.add( node.getNameToken(), new ClassEntry( def.getInternalName() ) );
386
387 return recurse( node, index );
388 }
389
390 @Override
391 public Void visitCompilationUnit( CompilationUnit node, SourceIndex index )
392 {
393 return recurse( node, index );
394 }
395
396 @Override
397 public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index )
398 {
399 return recurse( node, index );
400 }
401
402 @Override
403 public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index )
404 {
405 return recurse( node, index );
406 }
407
408 @Override
409 public Void visitComposedType( ComposedType node, SourceIndex index )
410 {
411 return recurse( node, index );
412 }
413
414 @Override
415 public Void visitWhileStatement( WhileStatement node, SourceIndex index )
416 {
417 return recurse( node, index );
418 }
419
420 @Override
421 public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index )
422 {
423 return recurse( node, index );
424 }
425
426 @Override
427 public Void visitCastExpression( CastExpression node, SourceIndex index )
428 {
429 return recurse( node, index );
430 }
431
432 @Override
433 public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index )
434 {
435 return recurse( node, index );
436 }
437
438 @Override
439 public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index )
440 {
441 return recurse( node, index );
442 }
443
444 @Override
445 public Void visitIndexerExpression( IndexerExpression node, SourceIndex index )
446 {
447 return recurse( node, index );
448 }
449
450 @Override
451 public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index )
452 {
453 // TODO
454 return recurse( node, index );
455 }
456
457 @Override
458 public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index )
459 {
460 return recurse( node, index );
461 }
462
463 @Override
464 public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index )
465 {
466 return recurse( node, index );
467 }
468
469 @Override
470 public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index )
471 {
472 return recurse( node, index );
473 }
474
475 @Override
476 public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index )
477 {
478 return recurse( node, index );
479 }
480
481 @Override
482 public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index )
483 {
484 return recurse( node, index );
485 }
486
487 @Override
488 public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index )
489 {
490 return recurse( node, index );
491 }
492
493 @Override
494 public Void visitForStatement( ForStatement node, SourceIndex index )
495 {
496 return recurse( node, index );
497 }
498
499 @Override
500 public Void visitForEachStatement( ForEachStatement node, SourceIndex index )
501 {
502 return recurse( node, index );
503 }
504
505 @Override
506 public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index )
507 {
508 return recurse( node, index );
509 }
510
511 @Override
512 public Void visitGotoStatement( GotoStatement node, SourceIndex index )
513 {
514 return recurse( node, index );
515 }
516
517 @Override
518 public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index )
519 {
520 return recurse( node, index );
521 }
522
523 @Override
524 public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index )
525 {
526 return recurse( node, index );
527 }
528
529 @Override
530 public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index )
531 {
532 return recurse( node, index );
533 }
534
535 @Override
536 public Void visitWildcardType( WildcardType node, SourceIndex index )
537 {
538 return recurse( node, index );
539 }
540
541 @Override
542 public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index )
543 {
544 return recurse( node, index );
545 }
546
547 @Override
548 public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index )
549 {
550 return recurse( node, index );
551 }
552
553 @Override
554 public Void visitAssertStatement( AssertStatement node, SourceIndex index )
555 {
556 return recurse( node, index );
557 }
558
559 @Override
560 public Void visitLambdaExpression( LambdaExpression node, SourceIndex index )
561 {
562 return recurse( node, index );
563 }
564
565 @Override
566 public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index )
567 {
568 return recurse( node, index );
569 }
570
571 private Void recurse( AstNode node, SourceIndex index )
572 {
573 // TEMP: show the tree
574 System.out.println( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() );
575
576 for( final AstNode child : node.getChildren() )
577 {
578 child.acceptVisitor( this, index );
579 }
580 return null;
581 }
582
583 private String dumpUserData( AstNode node )
584 {
585 StringBuilder buf = new StringBuilder();
586 for( Key<?> key : Keys.ALL_KEYS )
587 {
588 Object val = node.getUserData( key );
589 if( val != null )
590 {
591 buf.append( String.format( " [%s=%s]", key, val ) );
592 }
593 }
594 return buf.toString();
595 }
596
597 private String getIndent( AstNode node )
598 {
599 StringBuilder buf = new StringBuilder();
600 int depth = getDepth( node );
601 for( int i = 0; i < depth; i++ )
602 {
603 buf.append( "\t" );
604 }
605 return buf.toString();
606 }
607
608 private int getDepth( AstNode node )
609 {
610 int depth = -1;
611 while( node != null )
612 {
613 depth++;
614 node = node.getParent();
615 }
616 return depth;
617 }
618}
diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java
deleted file mode 100644
index a88cc754..00000000
--- a/src/cuchaz/enigma/analysis/SourcedAst.java
+++ /dev/null
@@ -1,140 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import java.io.IOException;
14import java.util.HashMap;
15
16import javassist.bytecode.Descriptor;
17
18import com.google.common.collect.Maps;
19import com.sun.source.tree.CompilationUnitTree;
20import com.sun.source.tree.ImportTree;
21import com.sun.source.tree.Tree;
22import com.sun.source.util.SourcePositions;
23import com.sun.source.util.Trees;
24
25public class SourcedAst
26{
27 private CompilationUnitTree m_tree;
28 private Trees m_trees;
29 private SourcePositions m_positions;
30 private HashMap<String,String> m_classNameIndex;
31 private String m_packageName;
32
33 public SourcedAst( CompilationUnitTree tree, Trees trees )
34 {
35 m_tree = tree;
36 m_trees = trees;
37 m_positions = m_trees.getSourcePositions();
38 m_classNameIndex = Maps.newHashMap();
39
40 // index all the class names from package imports
41 for( ImportTree importTree : m_tree.getImports() )
42 {
43 // ignore static imports for now
44 if( importTree.isStatic() )
45 {
46 continue;
47 }
48
49 // get the full and simple class names
50 String fullName = Descriptor.toJvmName( importTree.getQualifiedIdentifier().toString() );
51 String simpleName = fullName;
52
53 if( fullName.startsWith( "__DEFAULT__/" ) )
54 {
55 // remove the default package flag
56 fullName = fullName.substring( 12 );
57 }
58
59 String[] parts = fullName.split( "/" );
60 if( parts.length > 0 )
61 {
62 simpleName = parts[parts.length - 1];
63 }
64
65 m_classNameIndex.put( simpleName, fullName );
66 }
67
68 // get the package name
69 m_packageName = null;
70 if( m_tree.getPackageName() != null )
71 {
72 m_packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() );
73 }
74 }
75
76 public int getStart( Tree node )
77 {
78 int pos = (int)m_positions.getStartPosition( m_tree, node );
79 assert( pos >= 0 );
80 return pos;
81 }
82
83 public int getEnd( Tree node )
84 {
85 int pos = (int)m_positions.getEndPosition( m_tree, node );
86 assert( pos >= 0 );
87 return pos;
88 }
89
90 public int getLine( Tree node )
91 {
92 return getLine( getStart( node ) );
93 }
94
95 public int getLine( int pos )
96 {
97 return (int)m_tree.getLineMap().getLineNumber( pos );
98 }
99
100 public CharSequence getSource( )
101 {
102 try
103 {
104 return m_tree.getSourceFile().getCharContent( true );
105 }
106 catch( IOException ex )
107 {
108 throw new Error( ex );
109 }
110 }
111
112 public CharSequence getSource( Tree node )
113 {
114 return getSource().subSequence( getStart( node ), getEnd( node ) );
115 }
116
117 public void visit( TreeVisitor visitor )
118 {
119 m_tree.accept( visitor, this );
120 }
121
122 public String getFullClassName( String simpleClassName )
123 {
124 String fullClassName = m_classNameIndex.get( simpleClassName );
125 if( fullClassName == null )
126 {
127 if( m_packageName != null )
128 {
129 // no mapping was found, assume it's in the package
130 fullClassName = m_packageName + "/" + simpleClassName;
131 }
132 else
133 {
134 // this must be in the default package
135 fullClassName = simpleClassName;
136 }
137 }
138 return fullClassName;
139 }
140}
diff --git a/src/cuchaz/enigma/analysis/JavaSourceFromString.java b/src/cuchaz/enigma/analysis/Token.java
index cf5c4c27..74023e32 100644
--- a/src/cuchaz/enigma/analysis/JavaSourceFromString.java
+++ b/src/cuchaz/enigma/analysis/Token.java
@@ -10,22 +10,40 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13import java.net.URI; 13public class Token implements Comparable<Token>
14
15import javax.tools.SimpleJavaFileObject;
16
17public class JavaSourceFromString extends SimpleJavaFileObject
18{ 14{
19 private final String m_source; 15 public int start;
16 public int end;
17
18 public Token( int start, int end )
19 {
20 this.start = start;
21 this.end = end;
22 }
23
24 public boolean contains( int pos )
25 {
26 return pos >= start && pos <= end;
27 }
28
29 @Override
30 public int compareTo( Token other )
31 {
32 return start - other.start;
33 }
20 34
21 JavaSourceFromString( String name, String source ) 35 @Override
36 public boolean equals( Object other )
22 { 37 {
23 super( URI.create( "string:///" + name.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE ); 38 if( other instanceof Token )
24 m_source = source; 39 {
40 return equals( (Token)other );
41 }
42 return false;
25 } 43 }
26 44
27 public CharSequence getCharContent( boolean ignoreEncodingErrors ) 45 public boolean equals( Token other )
28 { 46 {
29 return m_source; 47 return start == other.start && end == other.end;
30 } 48 }
31} 49}
diff --git a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java
index d8e67554..61e582df 100644
--- a/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java
+++ b/src/cuchaz/enigma/gui/ClassInheritanceTreeNode.java
@@ -14,7 +14,7 @@ import java.util.List;
14 14
15import javax.swing.tree.DefaultMutableTreeNode; 15import javax.swing.tree.DefaultMutableTreeNode;
16 16
17import com.beust.jcommander.internal.Lists; 17import com.google.common.collect.Lists;
18 18
19import cuchaz.enigma.mapping.Ancestries; 19import cuchaz.enigma.mapping.Ancestries;
20import cuchaz.enigma.mapping.Translator; 20import cuchaz.enigma.mapping.Translator;
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 61e66e04..187852a2 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -62,12 +62,12 @@ import javax.swing.tree.TreePath;
62 62
63import jsyntaxpane.DefaultSyntaxKit; 63import jsyntaxpane.DefaultSyntaxKit;
64import jsyntaxpane.SyntaxDocument; 64import jsyntaxpane.SyntaxDocument;
65import jsyntaxpane.Token;
66 65
67import com.beust.jcommander.internal.Lists; 66import com.google.common.collect.Lists;
68 67
69import cuchaz.enigma.ClassFile; 68import cuchaz.enigma.ClassFile;
70import cuchaz.enigma.Constants; 69import cuchaz.enigma.Constants;
70import cuchaz.enigma.analysis.Token;
71import cuchaz.enigma.mapping.ArgumentEntry; 71import cuchaz.enigma.mapping.ArgumentEntry;
72import cuchaz.enigma.mapping.ClassEntry; 72import cuchaz.enigma.mapping.ClassEntry;
73import cuchaz.enigma.mapping.Entry; 73import cuchaz.enigma.mapping.Entry;
@@ -643,7 +643,7 @@ public class Gui
643 { 643 {
644 try 644 try
645 { 645 {
646 m_editor.getHighlighter().addHighlight( token.start, token.end(), painter ); 646 m_editor.getHighlighter().addHighlight( token.start, token.end, painter );
647 } 647 }
648 catch( BadLocationException ex ) 648 catch( BadLocationException ex )
649 { 649 {
@@ -740,22 +740,20 @@ public class Gui
740 740
741 private void onCaretMove( int pos ) 741 private void onCaretMove( int pos )
742 { 742 {
743 m_selectedEntryPair = m_controller.getEntryPair( pos ); 743 Token token = m_controller.getToken( pos );
744 744 m_renameMenu.setEnabled( token != null );
745 boolean isEntry = m_selectedEntryPair != null; 745 if( token == null )
746 boolean isClassEntry = isEntry && m_selectedEntryPair.obf instanceof ClassEntry;
747 boolean isMethodEntry = isEntry && m_selectedEntryPair.obf instanceof MethodEntry;
748
749 if( isEntry )
750 {
751 showEntryPair( m_selectedEntryPair );
752 }
753 else
754 { 746 {
755 clearEntryPair(); 747 clearEntryPair();
748 return;
756 } 749 }
757 750
758 m_renameMenu.setEnabled( isEntry ); 751 m_selectedEntryPair = m_controller.getEntryPair( token );
752 boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry;
753 boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry;
754
755 showEntryPair( m_selectedEntryPair );
756
759 m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); 757 m_inheritanceMenu.setEnabled( isClassEntry || isMethodEntry );
760 m_openEntryMenu.setEnabled( isClassEntry ); 758 m_openEntryMenu.setEnabled( isClassEntry );
761 } 759 }
@@ -803,6 +801,7 @@ public class Gui
803 int lineNum = doc.getLineNumberAt( m_editor.getCaretPosition() ); 801 int lineNum = doc.getLineNumberAt( m_editor.getCaretPosition() );
804 try 802 try
805 { 803 {
804 // TODO: give token to the controller so we can put the caret back there
806 m_controller.rename( m_selectedEntryPair.obf, newName, lineNum ); 805 m_controller.rename( m_selectedEntryPair.obf, newName, lineNum );
807 } 806 }
808 catch( IllegalNameException ex ) 807 catch( IllegalNameException ex )
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 2219e05b..e0aad860 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -17,15 +17,13 @@ import java.io.IOException;
17import java.util.List; 17import java.util.List;
18import java.util.Map; 18import java.util.Map;
19 19
20import jsyntaxpane.Token; 20import com.google.common.collect.Lists;
21 21import com.google.common.collect.Maps;
22import com.beust.jcommander.internal.Lists;
23import com.beust.jcommander.internal.Maps;
24 22
25import cuchaz.enigma.ClassFile; 23import cuchaz.enigma.ClassFile;
26import cuchaz.enigma.Deobfuscator; 24import cuchaz.enigma.Deobfuscator;
27import cuchaz.enigma.analysis.Analyzer;
28import cuchaz.enigma.analysis.SourceIndex; 25import cuchaz.enigma.analysis.SourceIndex;
26import cuchaz.enigma.analysis.Token;
29import cuchaz.enigma.mapping.ClassEntry; 27import cuchaz.enigma.mapping.ClassEntry;
30import cuchaz.enigma.mapping.Entry; 28import cuchaz.enigma.mapping.Entry;
31import cuchaz.enigma.mapping.EntryPair; 29import cuchaz.enigma.mapping.EntryPair;
@@ -105,41 +103,35 @@ public class GuiController
105 deobfuscate( m_currentFile ); 103 deobfuscate( m_currentFile );
106 } 104 }
107 105
108 public EntryPair<Entry> getEntryPair( int pos ) 106 public Token getToken( int pos )
109 { 107 {
110 if( m_index == null ) 108 if( m_index == null )
111 { 109 {
112 return null; 110 return null;
113 } 111 }
114 112
115 Map.Entry<Entry,Token> deobfEntryAndToken = m_index.getEntry( pos ); 113 return m_index.getToken( pos );
116 if( deobfEntryAndToken == null ) 114 }
115
116 public EntryPair<Entry> getEntryPair( Token token )
117 {
118 if( m_index == null )
117 { 119 {
118 return null; 120 return null;
119 } 121 }
120 Entry deobfEntry = deobfEntryAndToken.getKey(); 122
121 Token token = deobfEntryAndToken.getValue(); 123 Entry deobfEntry = m_index.getEntry( token );
122 return new EntryPair<Entry>( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry, token ); 124 return new EntryPair<Entry>( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry );
123 } 125 }
124 126
125 public boolean entryHasMapping( int pos ) 127 public boolean entryHasMapping( Entry deobfEntry )
126 { 128 {
127 EntryPair<Entry> pair = getEntryPair( pos ); 129 return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) );
128 if( pair == null || pair.obf == null )
129 {
130 return false;
131 }
132 return m_deobfuscator.hasMapping( pair.obf );
133 } 130 }
134 131
135 public boolean entryIsObfuscatedIdenfitier( int pos ) 132 public boolean entryIsObfuscatedIdenfitier( Entry deobfEntry )
136 { 133 {
137 EntryPair<Entry> pair = getEntryPair( pos ); 134 return m_deobfuscator.entryIsObfuscatedIdenfitier( m_deobfuscator.obfuscateEntry( deobfEntry ) );
138 if( pair == null || pair.obf == null )
139 {
140 return false;
141 }
142 return m_deobfuscator.entryIsObfuscatedIdenfitier( pair.obf );
143 } 135 }
144 136
145 public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) 137 public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry )
@@ -210,23 +202,21 @@ public class GuiController
210 @Override 202 @Override
211 public void run( ) 203 public void run( )
212 { 204 {
213 // deobfuscate,decompile the bytecode 205 // decopmile,deobfuscate the bytecode
214 String source = m_deobfuscator.getSource( classFile ); 206 m_index = m_deobfuscator.getSource( classFile );
215 m_gui.setSource( source, lineNum ); 207 m_gui.setSource( m_index.getSource(), lineNum );
216
217 // index the source file
218 m_index = Analyzer.analyze( classFile.getName(), source );
219 208
220 // set the highlighted tokens 209 // set the highlighted tokens
221 List<Token> obfuscatedTokens = Lists.newArrayList(); 210 List<Token> obfuscatedTokens = Lists.newArrayList();
222 List<Token> deobfuscatedTokens = Lists.newArrayList(); 211 List<Token> deobfuscatedTokens = Lists.newArrayList();
223 for( Token token : m_index.tokens() ) 212 for( Token token : m_index.tokens() )
224 { 213 {
225 if( entryHasMapping( token.start ) ) 214 Entry entry = m_index.getEntry( token );
215 if( entryHasMapping( entry ) )
226 { 216 {
227 deobfuscatedTokens.add( token ); 217 deobfuscatedTokens.add( token );
228 } 218 }
229 else if( entryIsObfuscatedIdenfitier( token.start ) ) 219 else if( entryIsObfuscatedIdenfitier( entry ) )
230 { 220 {
231 obfuscatedTokens.add( token ); 221 obfuscatedTokens.add( token );
232 } 222 }
diff --git a/src/cuchaz/enigma/mapping/Ancestries.java b/src/cuchaz/enigma/mapping/Ancestries.java
index f77a00eb..894cf802 100644
--- a/src/cuchaz/enigma/mapping/Ancestries.java
+++ b/src/cuchaz/enigma/mapping/Ancestries.java
@@ -26,7 +26,7 @@ import javassist.CtClass;
26import javassist.NotFoundException; 26import javassist.NotFoundException;
27import javassist.bytecode.Descriptor; 27import javassist.bytecode.Descriptor;
28 28
29import com.beust.jcommander.internal.Lists; 29import com.google.common.collect.Lists;
30import com.google.common.collect.Maps; 30import com.google.common.collect.Maps;
31 31
32import cuchaz.enigma.Constants; 32import cuchaz.enigma.Constants;
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index a1cc775f..c6826f31 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -13,7 +13,7 @@ package cuchaz.enigma.mapping;
13import java.io.Serializable; 13import java.io.Serializable;
14import java.util.Map; 14import java.util.Map;
15 15
16import com.beust.jcommander.internal.Maps; 16import com.google.common.collect.Maps;
17 17
18public class ClassMapping implements Serializable, Comparable<ClassMapping> 18public class ClassMapping implements Serializable, Comparable<ClassMapping>
19{ 19{
@@ -135,16 +135,16 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
135 135
136 public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature ) 136 public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature )
137 { 137 {
138 MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); 138 MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) );
139 if( methodIndex == null ) 139 if( methodMapping == null )
140 { 140 {
141 methodIndex = createMethodIndex( obfName, obfSignature ); 141 methodMapping = createMethodIndex( obfName, obfSignature );
142 } 142 }
143 143
144 m_methodsByDeobf.remove( getMethodKey( methodIndex.getDeobfName(), methodIndex.getDeobfSignature() ) ); 144 m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) );
145 methodIndex.setDeobfName( deobfName ); 145 methodMapping.setDeobfName( deobfName );
146 methodIndex.setDeobfSignature( deobfSignature ); 146 methodMapping.setDeobfSignature( deobfSignature );
147 m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodIndex ); 147 m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping );
148 } 148 }
149 149
150 public void updateDeobfMethodSignatures( Translator translator ) 150 public void updateDeobfMethodSignatures( Translator translator )
@@ -167,11 +167,11 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
167 167
168 private MethodMapping createMethodIndex( String obfName, String obfSignature ) 168 private MethodMapping createMethodIndex( String obfName, String obfSignature )
169 { 169 {
170 MethodMapping methodIndex = new MethodMapping( obfName, obfName, obfSignature, obfSignature ); 170 MethodMapping methodMapping = new MethodMapping( obfName, obfName, obfSignature, obfSignature );
171 String key = getMethodKey( obfName, obfSignature ); 171 String key = getMethodKey( obfName, obfSignature );
172 m_methodsByObf.put( key, methodIndex ); 172 m_methodsByObf.put( key, methodMapping );
173 m_methodsByDeobf.put( key, methodIndex ); 173 m_methodsByDeobf.put( key, methodMapping );
174 return methodIndex; 174 return methodMapping;
175 } 175 }
176 176
177 @Override 177 @Override
diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java
index 1bf9be09..f94d77ea 100644
--- a/src/cuchaz/enigma/mapping/EntryPair.java
+++ b/src/cuchaz/enigma/mapping/EntryPair.java
@@ -10,19 +10,16 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13import jsyntaxpane.Token;
14 13
15 14
16public class EntryPair<T extends Entry> 15public class EntryPair<T extends Entry>
17{ 16{
18 public T obf; 17 public T obf;
19 public T deobf; 18 public T deobf;
20 public Token token;
21 19
22 public EntryPair( T obf, T deobf, Token token ) 20 public EntryPair( T obf, T deobf )
23 { 21 {
24 this.obf = obf; 22 this.obf = obf;
25 this.deobf = deobf; 23 this.deobf = deobf;
26 this.token = token;
27 } 24 }
28} 25}
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
index 2a39057a..4dff6935 100644
--- a/src/cuchaz/enigma/mapping/Mappings.java
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -17,7 +17,7 @@ import java.io.Serializable;
17import java.util.Map; 17import java.util.Map;
18import java.util.zip.GZIPInputStream; 18import java.util.zip.GZIPInputStream;
19 19
20import com.beust.jcommander.internal.Maps; 20import com.google.common.collect.Maps;
21 21
22import cuchaz.enigma.Util; 22import cuchaz.enigma.Util;
23 23