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.obfuscate;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.util.*;
025: import proguard.classfile.visitor.MemberVisitor;
026:
027: import java.util.Map;
028:
029: /**
030: * This MemberInfoVisitor solves obfuscation naming conflicts in all class
031: * members that it visits. It avoids names from the given descriptor map,
032: * delegating to the given obfuscator in order to get a new name if necessary.
033: *
034: * @author Eric Lafortune
035: */
036: public class MemberNameConflictFixer implements MemberVisitor {
037: private final boolean allowAggressiveOverloading;
038: private final Map descriptorMap;
039: private final WarningPrinter warningPrinter;
040: private final MemberObfuscator memberObfuscator;
041:
042: /**
043: * Creates a new MemberNameConflictFixer.
044: * @param allowAggressiveOverloading a flag that specifies whether class
045: * members can be overloaded aggressively.
046: * @param descriptorMap the map of descriptors to
047: * [new name - old name] maps.
048: * @param warningPrinter an optional warning printer to which
049: * warnings about conflicting name
050: * mappings can be printed.
051: * @param memberObfuscator the obfuscator that can assign new
052: * names to members with conflicting
053: * names.
054: */
055: public MemberNameConflictFixer(boolean allowAggressiveOverloading,
056: Map descriptorMap, WarningPrinter warningPrinter,
057: MemberObfuscator memberObfuscator) {
058: this .allowAggressiveOverloading = allowAggressiveOverloading;
059: this .descriptorMap = descriptorMap;
060: this .warningPrinter = warningPrinter;
061: this .memberObfuscator = memberObfuscator;
062: }
063:
064: // Implementations for MemberVisitor.
065:
066: public void visitProgramField(ProgramClass programClass,
067: ProgramField programField) {
068: visitMember(programClass, programField, true);
069: }
070:
071: public void visitProgramMethod(ProgramClass programClass,
072: ProgramMethod programMethod) {
073: // Special cases: <clinit> and <init> are always kept unchanged.
074: // We can ignore them here.
075: String name = programMethod.getName(programClass);
076: if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)
077: || name
078: .equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) {
079: return;
080: }
081:
082: visitMember(programClass, programMethod, false);
083: }
084:
085: public void visitLibraryField(LibraryClass libraryClass,
086: LibraryField libraryField) {
087: }
088:
089: public void visitLibraryMethod(LibraryClass libraryClass,
090: LibraryMethod libraryMethod) {
091: }
092:
093: /**
094: * Obfuscates the given class member.
095: * @param clazz the class of the given member.
096: * @param member the class member to be obfuscated.
097: * @param isField specifies whether the class member is a field.
098: */
099: private void visitMember(Clazz clazz, Member member, boolean isField) {
100: // Get the member's name and descriptor.
101: String name = member.getName(clazz);
102: String descriptor = member.getDescriptor(clazz);
103:
104: // Check whether we're allowed to overload aggressively.
105: if (!allowAggressiveOverloading) {
106: // Trim the return argument from the descriptor if not.
107: // Works for fields and methods alike.
108: descriptor = descriptor.substring(0, descriptor
109: .indexOf(')') + 1);
110: }
111:
112: // Get the name map.
113: Map nameMap = MemberObfuscator.retrieveNameMap(descriptorMap,
114: descriptor);
115:
116: // Get the member's new name.
117: String newName = MemberObfuscator.newMemberName(member);
118:
119: // Get the expected old name for this new name.
120: String previousName = (String) nameMap.get(newName);
121: if (previousName != null && !name.equals(previousName)) {
122: // There's a conflict! A member (with a given old name) in a
123: // first namespace has received the same new name as this
124: // member (with a different old name) in a second name space,
125: // and now these two have to live together in this name space.
126: if (MemberObfuscator.hasFixedNewMemberName(member)
127: && warningPrinter != null) {
128: descriptor = member.getDescriptor(clazz);
129: warningPrinter
130: .print("Warning: "
131: + ClassUtil.externalClassName(clazz
132: .getName())
133: + (isField ? ": field '"
134: + ClassUtil
135: .externalFullFieldDescription(
136: 0, name,
137: descriptor)
138: : ": method '"
139: + ClassUtil
140: .externalFullMethodDescription(
141: clazz
142: .getName(),
143: 0,
144: name,
145: descriptor))
146: + "' can't be mapped to '"
147: + newName
148: + "' because it would conflict with "
149: + (isField ? "field '" : "method '")
150: + previousName
151: + "', which is already being mapped to '"
152: + newName + "'");
153: }
154:
155: // Clear the conflicting name.
156: MemberObfuscator.setNewMemberName(member, null);
157:
158: // Assign a new name.
159: member.accept(clazz, memberObfuscator);
160: }
161: }
162: }
|