1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.classfile.util; 22 23 import proguard.classfile.*; 24 import proguard.classfile.visitor.*; 25 26 /** 27 * This class provides methods to find class members in a given class or in its 28 * hierarchy. 29 * 30 * @author Eric Lafortune 31 */ 32 public class MemberFinder 33 extends SimplifiedVisitor 34 implements MemberVisitor 35 { 36 private static class MemberFoundException extends RuntimeException {} 37 private static final MemberFoundException MEMBER_FOUND = new MemberFoundException(); 38 39 private Clazz clazz; 40 private Member member; 41 42 43 /** 44 * Finds the field with the given name and descriptor in the given 45 * class or its hierarchy. 46 */ findField(Clazz referencingClass, Clazz clazz, String name, String descriptor)47 public Field findField(Clazz referencingClass, 48 Clazz clazz, 49 String name, 50 String descriptor) 51 { 52 return (Field)findMember(referencingClass, clazz, name, descriptor, true); 53 } 54 55 56 /** 57 * Finds the method with the given name and descriptor in the given 58 * class or its hierarchy. 59 */ findMethod(Clazz referencingClass, Clazz clazz, String name, String descriptor)60 public Method findMethod(Clazz referencingClass, 61 Clazz clazz, 62 String name, 63 String descriptor) 64 { 65 return (Method)findMember(referencingClass, clazz, name, descriptor, false); 66 } 67 68 69 /** 70 * Finds the class member with the given name and descriptor in the given 71 * class or its hierarchy. 72 */ findMember(Clazz referencingClass, Clazz clazz, String name, String descriptor, boolean isField)73 public Member findMember(Clazz referencingClass, 74 Clazz clazz, 75 String name, 76 String descriptor, 77 boolean isField) 78 { 79 // Organize a search in the hierarchy of superclasses and interfaces. 80 // The class member may be in a different class, if the code was 81 // compiled with "-target 1.2" or higher (the default in JDK 1.4). 82 try 83 { 84 this.clazz = null; 85 this.member = null; 86 clazz.hierarchyAccept(true, true, true, false, isField ? 87 (ClassVisitor)new NamedFieldVisitor(name, descriptor, 88 new MemberClassAccessFilter(referencingClass, this)) : 89 (ClassVisitor)new NamedMethodVisitor(name, descriptor, 90 new MemberClassAccessFilter(referencingClass, this))); 91 } 92 catch (MemberFoundException ex) 93 { 94 // We've found the member we were looking for. 95 } 96 97 return member; 98 } 99 100 101 /** 102 * Returns the corresponding class of the most recently found class 103 * member. 104 */ correspondingClass()105 public Clazz correspondingClass() 106 { 107 return clazz; 108 } 109 110 111 /** 112 * Returns whether the given method is overridden anywhere down the class 113 * hierarchy. 114 */ isOverriden(Clazz clazz, Method method)115 public boolean isOverriden(Clazz clazz, 116 Method method) 117 { 118 String name = method.getName(clazz); 119 String descriptor = method.getDescriptor(clazz); 120 121 // Go looking for the method down the class hierarchy. 122 try 123 { 124 this.clazz = null; 125 this.member = null; 126 127 clazz.hierarchyAccept(false, false, false, true, 128 new NamedMethodVisitor(name, descriptor, 129 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))); 130 } 131 catch (MemberFoundException ex) 132 { 133 // We've found an overriding method. 134 return true; 135 } 136 137 return false; 138 } 139 140 141 /** 142 * Returns whether the given field is shadowed anywhere down the class 143 * hierarchy. 144 */ isShadowed(Clazz clazz, Field field)145 public boolean isShadowed(Clazz clazz, 146 Field field) 147 { 148 String name = field.getName(clazz); 149 String descriptor = field.getDescriptor(clazz); 150 151 // Go looking for the field down the class hierarchy. 152 try 153 { 154 this.clazz = null; 155 this.member = null; 156 clazz.hierarchyAccept(false, false, false, true, 157 new NamedFieldVisitor(name, descriptor, 158 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))); 159 } 160 catch (MemberFoundException ex) 161 { 162 // We've found a shadowing field. 163 return true; 164 } 165 166 return false; 167 } 168 169 170 // // Implementations for ClassVisitor. 171 // 172 // private void visitAnyClass(Clazz clazz) 173 // { 174 // if (member == null) 175 // { 176 // member = isField ? 177 // (Member)clazz.findField(name, descriptor) : 178 // (Member)clazz.findMethod(name, descriptor); 179 // 180 // if (member != null) 181 // { 182 // this.clazz = clazz; 183 // } 184 // } 185 // } 186 187 188 // Implementations for MemberVisitor. 189 visitAnyMember(Clazz clazz, Member member)190 public void visitAnyMember(Clazz clazz, Member member) 191 { 192 this.clazz = clazz; 193 this.member = member; 194 195 throw MEMBER_FOUND; 196 } 197 } 198