• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import java.util.*;
27 
28 /**
29  * This ClassVisitor links all corresponding non-private methods in the class
30  * hierarchies of all visited classes. Visited classes are typically all class
31  * files that are not being subclassed. Chains of links that have been created
32  * in previous invocations are merged with new chains of links, in order to
33  * create a consistent set of chains.
34  * <p>
35  * As a MemberVisitor, it links all corresponding class members that it visits,
36  * including fields and private class members.
37  * <p>
38  * Class initialization methods and constructors are always ignored.
39  *
40  * @author Eric Lafortune
41  */
42 public class MethodLinker
43 extends      SimplifiedVisitor
44 implements   ClassVisitor,
45              MemberVisitor
46 {
47     // An object that is reset and reused every time.
48     // The map: [class member name+' '+descriptor - class member info]
49     private final Map memberMap = new HashMap();
50 
51 
52     // Implementations for ClassVisitor.
53 
visitAnyClass(Clazz clazz)54     public void visitAnyClass(Clazz clazz)
55     {
56         // Collect all non-private members in this class hierarchy.
57         clazz.hierarchyAccept(true, true, true, false,
58             new AllMethodVisitor(
59             new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
60             this)));
61 
62         // Clean up for the next class hierarchy.
63         memberMap.clear();
64     }
65 
66 
67     // Implementations for MemberVisitor.
68 
visitAnyMember(Clazz clazz, Member member)69     public void visitAnyMember(Clazz clazz, Member member)
70     {
71         // Get the class member's name and descriptor.
72         String name       = member.getName(clazz);
73         String descriptor = member.getDescriptor(clazz);
74 
75         // Special cases: <clinit> and <init> are always kept unchanged.
76         // We can ignore them here.
77         if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
78             name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
79         {
80             return;
81         }
82 
83         // See if we've already come across a method with the same name and
84         // descriptor.
85         String key = name + ' ' + descriptor;
86         Member otherMember = (Member)memberMap.get(key);
87 
88         if (otherMember == null)
89         {
90             // Get the last method in the chain.
91             Member thisLastMember = lastMember(member);
92 
93             // Store the new class method in the map.
94             memberMap.put(key, thisLastMember);
95         }
96         else
97         {
98             // Link both members.
99             link(member, otherMember);
100         }
101     }
102 
103 
104     // Small utility methods.
105 
106     /**
107      * Links the two given class members.
108      */
link(Member member1, Member member2)109     private static void link(Member member1, Member member2)
110     {
111         // Get the last methods in the both chains.
112         Member lastMember1 = lastMember(member1);
113         Member lastMember2 = lastMember(member2);
114 
115         // Check if both link chains aren't already ending in the same element.
116         if (!lastMember1.equals(lastMember2))
117         {
118             // Merge the two chains, with the library members last.
119             if (lastMember2 instanceof LibraryMember)
120             {
121                 lastMember1.setVisitorInfo(lastMember2);
122             }
123             else
124             {
125                 lastMember2.setVisitorInfo(lastMember1);
126             }
127         }
128     }
129 
130 
131     /**
132      * Finds the last class member in the linked list of related class members.
133      * @param member the given class member.
134      * @return the last class member in the linked list.
135      */
lastMember(Member member)136     public static Member lastMember(Member member)
137     {
138         Member lastMember = member;
139         while (lastMember.getVisitorInfo() != null &&
140                lastMember.getVisitorInfo() instanceof Member)
141         {
142             lastMember = (Member)lastMember.getVisitorInfo();
143         }
144 
145         return lastMember;
146     }
147 
148 
149     /**
150      * Finds the last visitor accepter in the linked list of visitors.
151      * @param visitorAccepter the given method.
152      * @return the last method in the linked list.
153      */
lastVisitorAccepter(VisitorAccepter visitorAccepter)154     public static VisitorAccepter lastVisitorAccepter(VisitorAccepter visitorAccepter)
155     {
156         VisitorAccepter lastVisitorAccepter = visitorAccepter;
157         while (lastVisitorAccepter.getVisitorInfo() != null &&
158                lastVisitorAccepter.getVisitorInfo() instanceof VisitorAccepter)
159         {
160             lastVisitorAccepter = (VisitorAccepter)lastVisitorAccepter.getVisitorInfo();
161         }
162 
163         return lastVisitorAccepter;
164     }
165 }
166