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 */ 21package proguard; 22 23import proguard.classfile.*; 24import proguard.classfile.util.*; 25import proguard.classfile.visitor.*; 26 27import java.util.List; 28 29/** 30 * This class checks if the user has forgotten to fully qualify any classes 31 * in the configuration. 32 * 33 * @author Eric Lafortune 34 */ 35public class FullyQualifiedClassNameChecker 36extends SimplifiedVisitor 37implements ClassVisitor 38{ 39 private final ClassPool programClassPool; 40 private final ClassPool libraryClassPool; 41 private final WarningPrinter notePrinter; 42 43 44 /** 45 * Creates a new DescriptorKeepChecker. 46 */ 47 public FullyQualifiedClassNameChecker(ClassPool programClassPool, 48 ClassPool libraryClassPool, 49 WarningPrinter notePrinter) 50 { 51 this.programClassPool = programClassPool; 52 this.libraryClassPool = libraryClassPool; 53 this.notePrinter = notePrinter; 54 } 55 56 57 /** 58 * Checks the classes mentioned in the given class specifications, printing 59 * notes if necessary. Returns the number of notes printed. 60 */ 61 public void checkClassSpecifications(List classSpecifications) 62 { 63 if (classSpecifications != null) 64 { 65 for (int index = 0; index < classSpecifications.size(); index++) 66 { 67 ClassSpecification classSpecification = 68 (ClassSpecification)classSpecifications.get(index); 69 70 checkType(classSpecification.annotationType); 71 checkClassName(classSpecification.className); 72 checkType(classSpecification.extendsAnnotationType); 73 checkClassName(classSpecification.extendsClassName); 74 75 checkMemberSpecifications(classSpecification.fieldSpecifications, true); 76 checkMemberSpecifications(classSpecification.methodSpecifications, false); 77 } 78 } 79 } 80 81 82 /** 83 * Checks the classes mentioned in the given class member specifications, 84 * printing notes if necessary. 85 */ 86 private void checkMemberSpecifications(List memberSpecifications, boolean isField) 87 { 88 if (memberSpecifications != null) 89 { 90 for (int index = 0; index < memberSpecifications.size(); index++) 91 { 92 MemberSpecification memberSpecification = 93 (MemberSpecification)memberSpecifications.get(index); 94 95 checkType(memberSpecification.annotationType); 96 97 if (isField) 98 { 99 checkType(memberSpecification.descriptor); 100 } 101 else 102 { 103 checkDescriptor(memberSpecification.descriptor); 104 } 105 } 106 } 107 } 108 109 110 /** 111 * Checks the classes mentioned in the given class member descriptor, 112 * printing notes if necessary. 113 */ 114 private void checkDescriptor(String descriptor) 115 { 116 if (descriptor != null) 117 { 118 InternalTypeEnumeration internalTypeEnumeration = 119 new InternalTypeEnumeration(descriptor); 120 121 checkType(internalTypeEnumeration.returnType()); 122 123 while (internalTypeEnumeration.hasMoreTypes()) 124 { 125 checkType(internalTypeEnumeration.nextType()); 126 } 127 } 128 } 129 130 131 /** 132 * Checks the class mentioned in the given type (if any), 133 * printing notes if necessary. 134 */ 135 private void checkType(String type) 136 { 137 if (type != null) 138 { 139 checkClassName(ClassUtil.internalClassNameFromType(type)); 140 } 141 } 142 143 144 /** 145 * Checks the specified class (if any), 146 * printing notes if necessary. 147 */ 148 private void checkClassName(String className) 149 { 150 if (className != null && 151 !containsWildCards(className) && 152 programClassPool.getClass(className) == null && 153 libraryClassPool.getClass(className) == null && 154 notePrinter.accepts(className)) 155 { 156 notePrinter.print(className, 157 "Note: the configuration refers to the unknown class '" + 158 ClassUtil.externalClassName(className) + "'"); 159 160 String fullyQualifiedClassName = 161 "**" + ClassConstants.INTERNAL_PACKAGE_SEPARATOR + 162 className.substring(className.lastIndexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR)+1); 163 164 ClassNameFilter classNameFilter = 165 new ClassNameFilter(fullyQualifiedClassName, this); 166 167 programClassPool.classesAccept(classNameFilter); 168 libraryClassPool.classesAccept(classNameFilter); 169 } 170 } 171 172 173 private static boolean containsWildCards(String string) 174 { 175 return string != null && 176 (string.indexOf('*') >= 0 || 177 string.indexOf('?') >= 0 || 178 string.indexOf(',') >= 0 || 179 string.indexOf("///") >= 0); 180 } 181 182 183 // Implementations for ClassVisitor. 184 185 public void visitAnyClass(Clazz clazz) 186 { 187 System.out.println(" Maybe you meant the fully qualified name '" + 188 ClassUtil.externalClassName(clazz.getName()) + "'?"); 189 } 190} 191