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.*;
26import proguard.optimize.KeepMarker;
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. Returns the number of notes printed.
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.
89        programClassPool.classesAccept(new AllMemberVisitor(this));
90    }
91
92
93    // Implementations for MemberVisitor.
94
95    public void visitProgramField(ProgramClass programClass, ProgramField programField)
96    {
97        if (KeepMarker.isKept(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
108
109    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
110    {
111        if (KeepMarker.isKept(programMethod))
112        {
113            referencingClass  = programClass;
114            referencingMember = programMethod;
115            isField           = false;
116
117            // Don't check the return type, because it is not required for
118            // introspection (e.g. the return type of the special Enum methods).
119            //programMethod.referencedClassesAccept(this);
120
121            Clazz[] referencedClasses = programMethod.referencedClasses;
122            if (referencedClasses != null)
123            {
124                for (int index = 0; index < referencedClasses.length-1; index++)
125                {
126                    if (referencedClasses[index] != null)
127                    {
128                        referencedClasses[index].accept(this);
129                    }
130                }
131            }
132        }
133    }
134
135
136    // Implementations for ClassVisitor.
137
138    public void visitProgramClass(ProgramClass programClass)
139    {
140        if (!KeepMarker.isKept(programClass))
141        {
142            notePrinter.print(referencingClass.getName(),
143                              programClass.getName(),
144                              "Note: the configuration keeps the entry point '" +
145                              ClassUtil.externalClassName(referencingClass.getName()) +
146                              " { " +
147                              (isField ?
148                                   ClassUtil.externalFullFieldDescription(0,
149                                                                          referencingMember.getName(referencingClass),
150                                                                          referencingMember.getDescriptor(referencingClass)) :
151                                   ClassUtil.externalFullMethodDescription(referencingClass.getName(),
152                                                                           0,
153                                                                           referencingMember.getName(referencingClass),
154                                                                           referencingMember.getDescriptor(referencingClass))) +
155                              "; }', but not the descriptor class '" +
156                              ClassUtil.externalClassName(programClass.getName()) +
157                              "'");
158        }
159    }
160
161
162    public void visitLibraryClass(LibraryClass libraryClass) {}
163}
164