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