FullyQualifiedClassNameChecker.java revision cfead78069f3dc32998dc118ee08cab3867acea2
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2011 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 FullyQualifiedClassNameChecker.
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.
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             string.indexOf("///") >= 0);
181    }
182
183
184    // Implementations for ClassVisitor.
185
186    public void visitAnyClass(Clazz clazz)
187    {
188        System.out.println("      Maybe you meant the fully qualified name '" +
189                           ClassUtil.externalClassName(clazz.getName()) + "'?");
190    }
191}
192