DescriptorKeepChecker.java revision b9cc48a43ed984587c939d02fba5316bf5c0df6e
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 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.*;
26import proguard.optimize.*;
27
28import java.util.List;
29
30
31/**
32 * This class checks whether classes referenced by class members that are
33 * marked to be kept are marked to be kept too.
34 *
35 * @author Eric Lafortune
36 */
37public class DescriptorKeepChecker
38extends      SimplifiedVisitor
39implements   MemberVisitor,
40             ClassVisitor
41{
42    private final ClassPool      programClassPool;
43    private final ClassPool      libraryClassPool;
44    private final WarningPrinter notePrinter;
45
46    // Some fields acting as parameters for the class visitor.
47    private Clazz   referencingClass;
48    private Member  referencingMember;
49    private boolean isField;
50
51
52    /**
53     * Creates a new DescriptorKeepChecker.
54     */
55    public DescriptorKeepChecker(ClassPool      programClassPool,
56                                 ClassPool      libraryClassPool,
57                                 WarningPrinter notePrinter)
58    {
59        this.programClassPool = programClassPool;
60        this.libraryClassPool = libraryClassPool;
61        this.notePrinter      = notePrinter;
62    }
63
64
65    /**
66     * Checks the classes mentioned in the given keep specifications, printing
67     * notes if necessary.
68     */
69    public void checkClassSpecifications(List keepSpecifications)
70    {
71        // Clean up any old visitor info.
72        programClassPool.classesAccept(new ClassCleaner());
73        libraryClassPool.classesAccept(new ClassCleaner());
74
75        // Create a visitor for marking the seeds.
76        KeepMarker keepMarker = new KeepMarker();
77        ClassPoolVisitor classPoolvisitor =
78            ClassSpecificationVisitorFactory.createClassPoolVisitor(keepSpecifications,
79                                                                    keepMarker,
80                                                                    keepMarker,
81                                                                    false,
82                                                                    true,
83                                                                    true);
84        // Mark the seeds.
85        programClassPool.accept(classPoolvisitor);
86        libraryClassPool.accept(classPoolvisitor);
87
88        // Print out notes about argument types that are not being kept in
89        // class members that are being kept.
90        programClassPool.classesAccept(
91            new AllMemberVisitor(
92            new KeptMemberFilter(this)));
93    }
94
95
96    // Implementations for MemberVisitor.
97
98    public void visitProgramField(ProgramClass programClass, ProgramField programField)
99    {
100        //referencingClass  = programClass;
101        //referencingMember = programField;
102        //isField           = true;
103        //
104        // Don't check the type, because it is not required for introspection.
105        //programField.referencedClassesAccept(this);
106    }
107
108
109    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
110    {
111        referencingClass  = programClass;
112        referencingMember = programMethod;
113        isField           = false;
114
115        // Don't check the return type, because it is not required for
116        // introspection (e.g. the return type of the special Enum methods).
117        //programMethod.referencedClassesAccept(this);
118
119        Clazz[] referencedClasses = programMethod.referencedClasses;
120        if (referencedClasses != null)
121        {
122            int count = referencedClasses.length;
123
124            // Adapt the count if the return type is a class type (not so
125            // pretty; assuming test just checks for final ';').
126            if (ClassUtil.isInternalClassType(programMethod.getDescriptor(programClass)))
127            {
128                count--;
129            }
130
131            for (int index = 0; index < count; index++)
132            {
133                if (referencedClasses[index] != null)
134                {
135                    referencedClasses[index].accept(this);
136                }
137            }
138        }
139    }
140
141
142    // Implementations for ClassVisitor.
143
144    public void visitProgramClass(ProgramClass programClass)
145    {
146        if (!KeepMarker.isKept(programClass))
147        {
148            notePrinter.print(referencingClass.getName(),
149                              programClass.getName(),
150                              "Note: the configuration keeps the entry point '" +
151                              ClassUtil.externalClassName(referencingClass.getName()) +
152                              " { " +
153                              (isField ?
154                                   ClassUtil.externalFullFieldDescription(0,
155                                                                          referencingMember.getName(referencingClass),
156                                                                          referencingMember.getDescriptor(referencingClass)) :
157                                   ClassUtil.externalFullMethodDescription(referencingClass.getName(),
158                                                                           0,
159                                                                           referencingMember.getName(referencingClass),
160                                                                           referencingMember.getDescriptor(referencingClass))) +
161                              "; }', but not the descriptor class '" +
162                              ClassUtil.externalClassName(programClass.getName()) +
163                              "'");
164        }
165    }
166
167
168    public void visitLibraryClass(LibraryClass libraryClass) {}
169}
170