1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 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 */
21package proguard.classfile.util;
22
23import proguard.classfile.*;
24import 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 */
32public class MemberFinder
33extends      SimplifiedVisitor
34implements   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     */
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     */
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     */
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     */
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     */
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     */
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
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