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