001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.classfile.util;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.visitor.*;
025:
026: import java.util.*;
027:
028: /**
029: * This ClassVisitor links all corresponding non-private methods in the class
030: * hierarchies of all visited classes. Visited classes are typically all class
031: * files that are not being subclassed. Chains of links that have been created
032: * in previous invocations are merged with new chains of links, in order to
033: * create a consistent set of chains.
034: * <p>
035: * As a MemberVisitor, it links all corresponding class members that it visits,
036: * including fields and private class members.
037: * <p>
038: * Class initialization methods and constructors are always ignored.
039: *
040: * @author Eric Lafortune
041: */
042: public class MethodLinker extends SimplifiedVisitor implements
043: ClassVisitor, MemberVisitor {
044: // An object that is reset and reused every time.
045: // The map: [class member name+' '+descriptor - class member info]
046: private final Map memberMap = new HashMap();
047:
048: // Implementations for ClassVisitor.
049:
050: public void visitAnyClass(Clazz clazz) {
051: // Collect all non-private members in this class hierarchy.
052: clazz.hierarchyAccept(true, true, true, false,
053: new AllMethodVisitor(new MemberAccessFilter(0,
054: ClassConstants.INTERNAL_ACC_PRIVATE, this )));
055:
056: // Clean up for the next class hierarchy.
057: memberMap.clear();
058: }
059:
060: // Implementations for MemberVisitor.
061:
062: public void visitAnyMember(Clazz clazz, Member member) {
063: // Get the class member's name and descriptor.
064: String name = member.getName(clazz);
065: String descriptor = member.getDescriptor(clazz);
066:
067: // Special cases: <clinit> and <init> are always kept unchanged.
068: // We can ignore them here.
069: if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)
070: || name
071: .equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) {
072: return;
073: }
074:
075: // Get the last method in the chain.
076: Member this LastMember = lastMember(member);
077:
078: // See if we've already come across a method with the same name and
079: // descriptor.
080: String key = name + ' ' + descriptor;
081: Member otherMember = (Member) memberMap.get(key);
082:
083: if (otherMember == null) {
084: // Store the new class method in the map.
085: memberMap.put(key, this LastMember);
086: } else {
087: // Get the last method in the other chain.
088: Member otherLastMember = lastMember(otherMember);
089:
090: // Check if both link chains aren't already ending in the same element.
091: if (!this LastMember.equals(otherLastMember)) {
092: // Merge the two chains, with the library members last.
093: if (otherLastMember instanceof LibraryMember) {
094: this LastMember.setVisitorInfo(otherLastMember);
095: } else {
096: otherLastMember.setVisitorInfo(this LastMember);
097: }
098: }
099: }
100: }
101:
102: // Small utility methods.
103:
104: /**
105: * Finds the last class member in the linked list of related class members.
106: * @param member the given class member.
107: * @return the last class member in the linked list.
108: */
109: public static Member lastMember(Member member) {
110: Member lastMember = member;
111: while (lastMember.getVisitorInfo() != null
112: && lastMember.getVisitorInfo() instanceof Member) {
113: lastMember = (Member) lastMember.getVisitorInfo();
114: }
115:
116: return lastMember;
117: }
118:
119: /**
120: * Finds the last visitor accepter in the linked list of visitors.
121: * @param visitorAccepter the given method.
122: * @return the last method in the linked list.
123: */
124: public static VisitorAccepter lastVisitorAccepter(
125: VisitorAccepter visitorAccepter) {
126: VisitorAccepter lastVisitorAccepter = visitorAccepter;
127: while (lastVisitorAccepter.getVisitorInfo() != null
128: && lastVisitorAccepter.getVisitorInfo() instanceof VisitorAccepter) {
129: lastVisitorAccepter = (VisitorAccepter) lastVisitorAccepter
130: .getVisitorInfo();
131: }
132:
133: return lastVisitorAccepter;
134: }
135: }
|