summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/ClassIdentity.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/convert/ClassIdentity.java')
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java436
1 files changed, 178 insertions, 258 deletions
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index 1de345f..7340403 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -57,8 +57,8 @@ import cuchaz.enigma.mapping.MethodEntry;
57import cuchaz.enigma.mapping.SignatureUpdater; 57import cuchaz.enigma.mapping.SignatureUpdater;
58import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 58import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
59 59
60public class ClassIdentity 60public class ClassIdentity {
61{ 61
62 private ClassEntry m_classEntry; 62 private ClassEntry m_classEntry;
63 private SidedClassNamer m_namer; 63 private SidedClassNamer m_namer;
64 private Multiset<String> m_fields; 64 private Multiset<String> m_fields;
@@ -70,419 +70,339 @@ public class ClassIdentity
70 private Multiset<String> m_implementations; 70 private Multiset<String> m_implementations;
71 private Multiset<String> m_references; 71 private Multiset<String> m_references;
72 72
73 public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences ) 73 public ClassIdentity(CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences) {
74 {
75 m_namer = namer; 74 m_namer = namer;
76 75
77 // stuff from the bytecode 76 // stuff from the bytecode
78 77
79 m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 78 m_classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
80 m_fields = HashMultiset.create(); 79 m_fields = HashMultiset.create();
81 for( CtField field : c.getDeclaredFields() ) 80 for (CtField field : c.getDeclaredFields()) {
82 { 81 m_fields.add(scrubSignature(field.getSignature()));
83 m_fields.add( scrubSignature( field.getSignature() ) );
84 } 82 }
85 m_methods = HashMultiset.create(); 83 m_methods = HashMultiset.create();
86 for( CtMethod method : c.getDeclaredMethods() ) 84 for (CtMethod method : c.getDeclaredMethods()) {
87 { 85 m_methods.add(scrubSignature(method.getSignature()) + "0x" + getBehaviorSignature(method));
88 m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) );
89 } 86 }
90 m_constructors = HashMultiset.create(); 87 m_constructors = HashMultiset.create();
91 for( CtConstructor constructor : c.getDeclaredConstructors() ) 88 for (CtConstructor constructor : c.getDeclaredConstructors()) {
92 { 89 m_constructors.add(scrubSignature(constructor.getSignature()) + "0x" + getBehaviorSignature(constructor));
93 m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) );
94 } 90 }
95 m_staticInitializer = ""; 91 m_staticInitializer = "";
96 if( c.getClassInitializer() != null ) 92 if (c.getClassInitializer() != null) {
97 { 93 m_staticInitializer = getBehaviorSignature(c.getClassInitializer());
98 m_staticInitializer = getBehaviorSignature( c.getClassInitializer() );
99 } 94 }
100 m_extends = ""; 95 m_extends = "";
101 if( c.getClassFile().getSuperclass() != null ) 96 if (c.getClassFile().getSuperclass() != null) {
102 { 97 m_extends = scrubClassName(c.getClassFile().getSuperclass());
103 m_extends = scrubClassName( c.getClassFile().getSuperclass() );
104 } 98 }
105 m_implements = HashMultiset.create(); 99 m_implements = HashMultiset.create();
106 for( String interfaceName : c.getClassFile().getInterfaces() ) 100 for (String interfaceName : c.getClassFile().getInterfaces()) {
107 { 101 m_implements.add(scrubClassName(interfaceName));
108 m_implements.add( scrubClassName( interfaceName ) );
109 } 102 }
110 103
111 // stuff from the jar index 104 // stuff from the jar index
112 105
113 m_implementations = HashMultiset.create(); 106 m_implementations = HashMultiset.create();
114 ClassImplementationsTreeNode implementationsNode = index.getClassImplementations( null, m_classEntry ); 107 ClassImplementationsTreeNode implementationsNode = index.getClassImplementations(null, m_classEntry);
115 if( implementationsNode != null ) 108 if (implementationsNode != null) {
116 { 109 @SuppressWarnings("unchecked")
117 @SuppressWarnings( "unchecked" )
118 Enumeration<ClassImplementationsTreeNode> implementations = implementationsNode.children(); 110 Enumeration<ClassImplementationsTreeNode> implementations = implementationsNode.children();
119 while( implementations.hasMoreElements() ) 111 while (implementations.hasMoreElements()) {
120 {
121 ClassImplementationsTreeNode node = implementations.nextElement(); 112 ClassImplementationsTreeNode node = implementations.nextElement();
122 m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); 113 m_implementations.add(scrubClassName(node.getClassEntry().getName()));
123 } 114 }
124 } 115 }
125 116
126 m_references = HashMultiset.create(); 117 m_references = HashMultiset.create();
127 if( useReferences ) 118 if (useReferences) {
128 { 119 for (CtField field : c.getDeclaredFields()) {
129 for( CtField field : c.getDeclaredFields() ) 120 FieldEntry fieldEntry = new FieldEntry(m_classEntry, field.getName());
130 { 121 for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(fieldEntry)) {
131 FieldEntry fieldEntry = new FieldEntry( m_classEntry, field.getName() ); 122 addReference(reference);
132 for( EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences( fieldEntry ) )
133 {
134 addReference( reference );
135 } 123 }
136 } 124 }
137 for( CtMethod method : c.getDeclaredMethods() ) 125 for (CtMethod method : c.getDeclaredMethods()) {
138 { 126 MethodEntry methodEntry = new MethodEntry(m_classEntry, method.getName(), method.getSignature());
139 MethodEntry methodEntry = new MethodEntry( m_classEntry, method.getName(), method.getSignature() ); 127 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(methodEntry)) {
140 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( methodEntry ) ) 128 addReference(reference);
141 {
142 addReference( reference );
143 } 129 }
144 } 130 }
145 for( CtConstructor constructor : c.getDeclaredConstructors() ) 131 for (CtConstructor constructor : c.getDeclaredConstructors()) {
146 { 132 ConstructorEntry constructorEntry = new ConstructorEntry(m_classEntry, constructor.getSignature());
147 ConstructorEntry constructorEntry = new ConstructorEntry( m_classEntry, constructor.getSignature() ); 133 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(constructorEntry)) {
148 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( constructorEntry ) ) 134 addReference(reference);
149 {
150 addReference( reference );
151 } 135 }
152 } 136 }
153 } 137 }
154 } 138 }
155 139
156 private void addReference( EntryReference<? extends Entry,BehaviorEntry> reference ) 140 private void addReference(EntryReference<? extends Entry,BehaviorEntry> reference) {
157 { 141 if (reference.context.getSignature() != null) {
158 if( reference.context.getSignature() != null ) 142 m_references.add(String.format("%s_%s", scrubClassName(reference.context.getClassName()), scrubSignature(reference.context.getSignature())));
159 { 143 } else {
160 m_references.add( String.format( "%s_%s", 144 m_references.add(String.format("%s_<clinit>", scrubClassName(reference.context.getClassName())));
161 scrubClassName( reference.context.getClassName() ),
162 scrubSignature( reference.context.getSignature() )
163 ) );
164 }
165 else
166 {
167 m_references.add( String.format( "%s_<clinit>",
168 scrubClassName( reference.context.getClassName() )
169 ) );
170 } 145 }
171 } 146 }
172 147
173 public ClassEntry getClassEntry( ) 148 public ClassEntry getClassEntry() {
174 {
175 return m_classEntry; 149 return m_classEntry;
176 } 150 }
177 151
178 @Override 152 @Override
179 public String toString( ) 153 public String toString() {
180 {
181 StringBuilder buf = new StringBuilder(); 154 StringBuilder buf = new StringBuilder();
182 buf.append( "class: " ); 155 buf.append("class: ");
183 buf.append( m_classEntry.getName() ); 156 buf.append(m_classEntry.getName());
184 buf.append( " " ); 157 buf.append(" ");
185 buf.append( hashCode() ); 158 buf.append(hashCode());
186 buf.append( "\n" ); 159 buf.append("\n");
187 for( String field : m_fields ) 160 for (String field : m_fields) {
188 { 161 buf.append("\tfield ");
189 buf.append( "\tfield " ); 162 buf.append(field);
190 buf.append( field ); 163 buf.append("\n");
191 buf.append( "\n" );
192 } 164 }
193 for( String method : m_methods ) 165 for (String method : m_methods) {
194 { 166 buf.append("\tmethod ");
195 buf.append( "\tmethod " ); 167 buf.append(method);
196 buf.append( method ); 168 buf.append("\n");
197 buf.append( "\n" );
198 } 169 }
199 for( String constructor : m_constructors ) 170 for (String constructor : m_constructors) {
200 { 171 buf.append("\tconstructor ");
201 buf.append( "\tconstructor " ); 172 buf.append(constructor);
202 buf.append( constructor ); 173 buf.append("\n");
203 buf.append( "\n" );
204 } 174 }
205 if( m_staticInitializer.length() > 0 ) 175 if (m_staticInitializer.length() > 0) {
206 { 176 buf.append("\tinitializer ");
207 buf.append( "\tinitializer " ); 177 buf.append(m_staticInitializer);
208 buf.append( m_staticInitializer ); 178 buf.append("\n");
209 buf.append( "\n" );
210 } 179 }
211 if( m_extends.length() > 0 ) 180 if (m_extends.length() > 0) {
212 { 181 buf.append("\textends ");
213 buf.append( "\textends " ); 182 buf.append(m_extends);
214 buf.append( m_extends ); 183 buf.append("\n");
215 buf.append( "\n" );
216 } 184 }
217 for( String interfaceName : m_implements ) 185 for (String interfaceName : m_implements) {
218 { 186 buf.append("\timplements ");
219 buf.append( "\timplements " ); 187 buf.append(interfaceName);
220 buf.append( interfaceName ); 188 buf.append("\n");
221 buf.append( "\n" );
222 } 189 }
223 for( String implementation : m_implementations ) 190 for (String implementation : m_implementations) {
224 { 191 buf.append("\timplemented by ");
225 buf.append( "\timplemented by " ); 192 buf.append(implementation);
226 buf.append( implementation ); 193 buf.append("\n");
227 buf.append( "\n" );
228 } 194 }
229 for( String reference : m_references ) 195 for (String reference : m_references) {
230 { 196 buf.append("\treference ");
231 buf.append( "\treference " ); 197 buf.append(reference);
232 buf.append( reference ); 198 buf.append("\n");
233 buf.append( "\n" );
234 } 199 }
235 return buf.toString(); 200 return buf.toString();
236 } 201 }
237 202
238 private String scrubClassName( String className ) 203 private String scrubClassName(String className) {
239 { 204 return scrubSignature("L" + Descriptor.toJvmName(className) + ";");
240 return scrubSignature( "L" + Descriptor.toJvmName( className ) + ";" );
241 } 205 }
242 206
243 private String scrubSignature( String signature ) 207 private String scrubSignature(String signature) {
244 { 208 return SignatureUpdater.update(signature, new ClassNameUpdater() {
245 return SignatureUpdater.update( signature, new ClassNameUpdater( )
246 {
247 private Map<String,String> m_classNames = Maps.newHashMap(); 209 private Map<String,String> m_classNames = Maps.newHashMap();
248 210
249 @Override 211 @Override
250 public String update( String className ) 212 public String update(String className) {
251 {
252 // classes not in the none package can be passed through 213 // classes not in the none package can be passed through
253 ClassEntry classEntry = new ClassEntry( className ); 214 ClassEntry classEntry = new ClassEntry(className);
254 if( !classEntry.getPackageName().equals( Constants.NonePackage ) ) 215 if (!classEntry.getPackageName().equals(Constants.NonePackage)) {
255 {
256 return className; 216 return className;
257 } 217 }
258 218
259 // is this class ourself? 219 // is this class ourself?
260 if( className.equals( m_classEntry.getName() ) ) 220 if (className.equals(m_classEntry.getName())) {
261 {
262 return "CSelf"; 221 return "CSelf";
263 } 222 }
264 223
265 // try the namer 224 // try the namer
266 if( m_namer != null ) 225 if (m_namer != null) {
267 { 226 String newName = m_namer.getName(className);
268 String newName = m_namer.getName( className ); 227 if (newName != null) {
269 if( newName != null )
270 {
271 return newName; 228 return newName;
272 } 229 }
273 } 230 }
274 231
275 // otherwise, use local naming 232 // otherwise, use local naming
276 if( !m_classNames.containsKey( className ) ) 233 if (!m_classNames.containsKey(className)) {
277 { 234 m_classNames.put(className, getNewClassName());
278 m_classNames.put( className, getNewClassName() );
279 } 235 }
280 return m_classNames.get( className ); 236 return m_classNames.get(className);
281 } 237 }
282 238
283 private String getNewClassName( ) 239 private String getNewClassName() {
284 { 240 return String.format("C%03d", m_classNames.size());
285 return String.format( "C%03d", m_classNames.size() );
286 } 241 }
287 } ); 242 });
288 } 243 }
289 244
290 private boolean isClassMatchedUniquely( String className ) 245 private boolean isClassMatchedUniquely(String className) {
291 { 246 return m_namer != null && m_namer.getName(Descriptor.toJvmName(className)) != null;
292 return m_namer != null && m_namer.getName( Descriptor.toJvmName( className ) ) != null;
293 } 247 }
294 248
295 private String getBehaviorSignature( CtBehavior behavior ) 249 private String getBehaviorSignature(CtBehavior behavior) {
296 { 250 try {
297 try
298 {
299 // does this method have an implementation? 251 // does this method have an implementation?
300 if( behavior.getMethodInfo().getCodeAttribute() == null ) 252 if (behavior.getMethodInfo().getCodeAttribute() == null) {
301 {
302 return "(none)"; 253 return "(none)";
303 } 254 }
304 255
305 // compute the hash from the opcodes 256 // compute the hash from the opcodes
306 ConstPool constants = behavior.getMethodInfo().getConstPool(); 257 ConstPool constants = behavior.getMethodInfo().getConstPool();
307 final MessageDigest digest = MessageDigest.getInstance( "MD5" ); 258 final MessageDigest digest = MessageDigest.getInstance("MD5");
308 CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); 259 CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator();
309 while( iter.hasNext() ) 260 while (iter.hasNext()) {
310 {
311 int pos = iter.next(); 261 int pos = iter.next();
312 262
313 // update the hash with the opcode 263 // update the hash with the opcode
314 int opcode = iter.byteAt( pos ); 264 int opcode = iter.byteAt(pos);
315 digest.update( (byte)opcode ); 265 digest.update((byte)opcode);
316 266
317 switch( opcode ) 267 switch (opcode) {
318 { 268 case Opcode.LDC: {
319 case Opcode.LDC: 269 int constIndex = iter.byteAt(pos + 1);
320 { 270 updateHashWithConstant(digest, constants, constIndex);
321 int constIndex = iter.byteAt( pos + 1 );
322 updateHashWithConstant( digest, constants, constIndex );
323 } 271 }
324 break; 272 break;
325 273
326 case Opcode.LDC_W: 274 case Opcode.LDC_W:
327 case Opcode.LDC2_W: 275 case Opcode.LDC2_W: {
328 { 276 int constIndex = (iter.byteAt(pos + 1) << 8) | iter.byteAt(pos + 2);
329 int constIndex = ( iter.byteAt( pos + 1 ) << 8 ) | iter.byteAt( pos + 2 ); 277 updateHashWithConstant(digest, constants, constIndex);
330 updateHashWithConstant( digest, constants, constIndex );
331 } 278 }
332 break; 279 break;
333 } 280 }
334 } 281 }
335 282
336 // update hash with method and field accesses 283 // update hash with method and field accesses
337 behavior.instrument( new ExprEditor( ) 284 behavior.instrument(new ExprEditor() {
338 {
339 @Override 285 @Override
340 public void edit( MethodCall call ) 286 public void edit(MethodCall call) {
341 { 287 updateHashWithString(digest, scrubClassName(call.getClassName()));
342 updateHashWithString( digest, scrubClassName( call.getClassName() ) ); 288 updateHashWithString(digest, scrubSignature(call.getSignature()));
343 updateHashWithString( digest, scrubSignature( call.getSignature() ) ); 289 if (isClassMatchedUniquely(call.getClassName())) {
344 if( isClassMatchedUniquely( call.getClassName() ) ) 290 updateHashWithString(digest, call.getMethodName());
345 {
346 updateHashWithString( digest, call.getMethodName() );
347 } 291 }
348 } 292 }
349 293
350 @Override 294 @Override
351 public void edit( FieldAccess access ) 295 public void edit(FieldAccess access) {
352 { 296 updateHashWithString(digest, scrubClassName(access.getClassName()));
353 updateHashWithString( digest, scrubClassName( access.getClassName() ) ); 297 updateHashWithString(digest, scrubSignature(access.getSignature()));
354 updateHashWithString( digest, scrubSignature( access.getSignature() ) ); 298 if (isClassMatchedUniquely(access.getClassName())) {
355 if( isClassMatchedUniquely( access.getClassName() ) ) 299 updateHashWithString(digest, access.getFieldName());
356 {
357 updateHashWithString( digest, access.getFieldName() );
358 } 300 }
359 } 301 }
360 302
361 @Override 303 @Override
362 public void edit( ConstructorCall call ) 304 public void edit(ConstructorCall call) {
363 { 305 updateHashWithString(digest, scrubClassName(call.getClassName()));
364 updateHashWithString( digest, scrubClassName( call.getClassName() ) ); 306 updateHashWithString(digest, scrubSignature(call.getSignature()));
365 updateHashWithString( digest, scrubSignature( call.getSignature() ) );
366 } 307 }
367 308
368 @Override 309 @Override
369 public void edit( NewExpr expr ) 310 public void edit(NewExpr expr) {
370 { 311 updateHashWithString(digest, scrubClassName(expr.getClassName()));
371 updateHashWithString( digest, scrubClassName( expr.getClassName() ) );
372 } 312 }
373 } ); 313 });
374 314
375 // convert the hash to a hex string 315 // convert the hash to a hex string
376 return toHex( digest.digest() ); 316 return toHex(digest.digest());
377 } 317 } catch (BadBytecode | NoSuchAlgorithmException | CannotCompileException ex) {
378 catch( BadBytecode | NoSuchAlgorithmException | CannotCompileException ex ) 318 throw new Error(ex);
379 {
380 throw new Error( ex );
381 } 319 }
382 } 320 }
383 321
384 private void updateHashWithConstant( MessageDigest digest, ConstPool constants, int index ) 322 private void updateHashWithConstant(MessageDigest digest, ConstPool constants, int index) {
385 { 323 ConstPoolEditor editor = new ConstPoolEditor(constants);
386 ConstPoolEditor editor = new ConstPoolEditor( constants ); 324 ConstInfoAccessor item = editor.getItem(index);
387 ConstInfoAccessor item = editor.getItem( index ); 325 if (item.getType() == InfoType.StringInfo) {
388 if( item.getType() == InfoType.StringInfo ) 326 updateHashWithString(digest, constants.getStringInfo(index));
389 {
390 updateHashWithString( digest, constants.getStringInfo( index ) );
391 } 327 }
392 // TODO: other constants 328 // TODO: other constants
393 } 329 }
394 330
395 private void updateHashWithString( MessageDigest digest, String val ) 331 private void updateHashWithString(MessageDigest digest, String val) {
396 { 332 try {
397 try 333 digest.update(val.getBytes("UTF8"));
398 { 334 } catch (UnsupportedEncodingException ex) {
399 digest.update( val.getBytes( "UTF8" ) ); 335 throw new Error(ex);
400 }
401 catch( UnsupportedEncodingException ex )
402 {
403 throw new Error( ex );
404 } 336 }
405 } 337 }
406 338
407 private String toHex( byte[] bytes ) 339 private String toHex(byte[] bytes) {
408 {
409 // function taken from: 340 // function taken from:
410 // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java 341 // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java
411 final char[] hexArray = "0123456789ABCDEF".toCharArray(); 342 final char[] hexArray = "0123456789ABCDEF".toCharArray();
412 char[] hexChars = new char[bytes.length * 2]; 343 char[] hexChars = new char[bytes.length * 2];
413 for( int j = 0; j < bytes.length; j++ ) 344 for (int j = 0; j < bytes.length; j++) {
414 {
415 int v = bytes[j] & 0xFF; 345 int v = bytes[j] & 0xFF;
416 hexChars[j * 2] = hexArray[v >>> 4]; 346 hexChars[j * 2] = hexArray[v >>> 4];
417 hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 347 hexChars[j * 2 + 1] = hexArray[v & 0x0F];
418 } 348 }
419 return new String( hexChars ); 349 return new String(hexChars);
420 } 350 }
421 351
422 @Override 352 @Override
423 public boolean equals( Object other ) 353 public boolean equals(Object other) {
424 { 354 if (other instanceof ClassIdentity) {
425 if( other instanceof ClassIdentity ) 355 return equals((ClassIdentity)other);
426 {
427 return equals( (ClassIdentity)other );
428 } 356 }
429 return false; 357 return false;
430 } 358 }
431 359
432 public boolean equals( ClassIdentity other ) 360 public boolean equals(ClassIdentity other) {
433 { 361 return m_fields.equals(other.m_fields)
434 return m_fields.equals( other.m_fields ) 362 && m_methods.equals(other.m_methods)
435 && m_methods.equals( other.m_methods ) 363 && m_constructors.equals(other.m_constructors)
436 && m_constructors.equals( other.m_constructors ) 364 && m_staticInitializer.equals(other.m_staticInitializer)
437 && m_staticInitializer.equals( other.m_staticInitializer ) 365 && m_extends.equals(other.m_extends)
438 && m_extends.equals( other.m_extends ) 366 && m_implements.equals(other.m_implements)
439 && m_implements.equals( other.m_implements ) 367 && m_implementations.equals(other.m_implementations)
440 && m_implementations.equals( other.m_implementations ) 368 && m_references.equals(other.m_references);
441 && m_references.equals( other.m_references );
442 } 369 }
443 370
444 @Override 371 @Override
445 public int hashCode( ) 372 public int hashCode() {
446 {
447 List<Object> objs = Lists.newArrayList(); 373 List<Object> objs = Lists.newArrayList();
448 objs.addAll( m_fields ); 374 objs.addAll(m_fields);
449 objs.addAll( m_methods ); 375 objs.addAll(m_methods);
450 objs.addAll( m_constructors ); 376 objs.addAll(m_constructors);
451 objs.add( m_staticInitializer ); 377 objs.add(m_staticInitializer);
452 objs.add( m_extends ); 378 objs.add(m_extends);
453 objs.addAll( m_implements ); 379 objs.addAll(m_implements);
454 objs.addAll( m_implementations ); 380 objs.addAll(m_implementations);
455 objs.addAll( m_references ); 381 objs.addAll(m_references);
456 return Util.combineHashesOrdered( objs ); 382 return Util.combineHashesOrdered(objs);
457 } 383 }
458 384
459 public int getMatchScore( ClassIdentity other ) 385 public int getMatchScore(ClassIdentity other) {
460 { 386 return getNumMatches(m_fields, other.m_fields)
461 return getNumMatches( m_fields, other.m_fields ) 387 + getNumMatches(m_methods, other.m_methods)
462 + getNumMatches( m_methods, other.m_methods ) 388 + getNumMatches(m_constructors, other.m_constructors);
463 + getNumMatches( m_constructors, other.m_constructors );
464 } 389 }
465 390
466 public int getMaxMatchScore( ) 391 public int getMaxMatchScore() {
467 {
468 return m_fields.size() + m_methods.size() + m_constructors.size(); 392 return m_fields.size() + m_methods.size() + m_constructors.size();
469 } 393 }
470 394
471 public boolean matches( CtClass c ) 395 public boolean matches(CtClass c) {
472 {
473 // just compare declaration counts 396 // just compare declaration counts
474 return m_fields.size() == c.getDeclaredFields().length 397 return m_fields.size() == c.getDeclaredFields().length
475 && m_methods.size() == c.getDeclaredMethods().length 398 && m_methods.size() == c.getDeclaredMethods().length
476 && m_constructors.size() == c.getDeclaredConstructors().length; 399 && m_constructors.size() == c.getDeclaredConstructors().length;
477 } 400 }
478 401
479 private int getNumMatches( Multiset<String> a, Multiset<String> b ) 402 private int getNumMatches(Multiset<String> a, Multiset<String> b) {
480 {
481 int numMatches = 0; 403 int numMatches = 0;
482 for( String val : a ) 404 for (String val : a) {
483 { 405 if (b.contains(val)) {
484 if( b.contains( val ) )
485 {
486 numMatches++; 406 numMatches++;
487 } 407 }
488 } 408 }