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