DynamicMemberReferenceInitializer.java revision b72c5c2e5482cf10117b2b25f642f7616b2326c3
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.classfile.util;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.CodeAttribute;
25import proguard.classfile.attribute.visitor.AttributeVisitor;
26import proguard.classfile.constant.*;
27import proguard.classfile.constant.visitor.ConstantVisitor;
28import proguard.classfile.instruction.*;
29import proguard.classfile.instruction.visitor.InstructionVisitor;
30import proguard.classfile.visitor.*;
31import proguard.util.StringMatcher;
32
33/**
34 * This InstructionVisitor initializes any constant
35 * <code>Class.get[Declared]{Field,Method}</code> references of all instructions
36 * it visits. More specifically, it fills out the references of string constant
37 * pool entries that refer to a class member in the program class pool or in the
38 * library class pool.
39 * <p>
40 * It optionally prints notes if on usage of
41 * <code>(SomeClass)Class.forName(variable).newInstance()</code>.
42 * <p>
43 * The class hierarchy and references must be initialized before using this
44 * visitor.
45 *
46 * @see ClassSuperHierarchyInitializer
47 * @see ClassReferenceInitializer
48 *
49 * @author Eric Lafortune
50 */
51public class DynamicMemberReferenceInitializer
52extends      SimplifiedVisitor
53implements   InstructionVisitor,
54             ConstantVisitor,
55             AttributeVisitor,
56             MemberVisitor
57{
58    public static final int X = InstructionSequenceMatcher.X;
59    public static final int Y = InstructionSequenceMatcher.Y;
60    public static final int Z = InstructionSequenceMatcher.Z;
61
62    public static final int A = InstructionSequenceMatcher.A;
63    public static final int B = InstructionSequenceMatcher.B;
64    public static final int C = InstructionSequenceMatcher.C;
65    public static final int D = InstructionSequenceMatcher.D;
66
67
68    private final Constant[] GET_FIELD_CONSTANTS = new Constant[]
69    {
70        new MethodrefConstant(1, 2, null, null),
71        new ClassConstant(3, null),
72        new NameAndTypeConstant(4, 5),
73        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
74        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_FIELD),
75        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_FIELD),
76    };
77
78    private final Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[]
79    {
80        new MethodrefConstant(1, 2, null, null),
81        new ClassConstant(3, null),
82        new NameAndTypeConstant(4, 5),
83        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
84        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD),
85        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD),
86    };
87
88    private final Constant[] GET_METHOD_CONSTANTS = new Constant[]
89    {
90        new MethodrefConstant(1, 2, null, null),
91        new ClassConstant(3, null),
92        new NameAndTypeConstant(4, 5),
93        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
94        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_METHOD),
95        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_METHOD),
96    };
97
98    private final Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[]
99    {
100        new MethodrefConstant(1, 2, null, null),
101        new ClassConstant(3, null),
102        new NameAndTypeConstant(4, 5),
103        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
104        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD),
105        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD),
106    };
107
108    // SomeClass.class.get[Declared]Field("someField").
109    private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[]
110    {
111        new ConstantInstruction(InstructionConstants.OP_LDC, X),
112        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
113        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
114    };
115
116    // SomeClass.class.get[Declared]Method("someMethod", new Class[] {}).
117    private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[]
118    {
119        new ConstantInstruction(InstructionConstants.OP_LDC, X),
120        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
121        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
122        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
123        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
124    };
125
126    // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }).
127    private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[]
128    {
129        new ConstantInstruction(InstructionConstants.OP_LDC, X),
130        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
131        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
132        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
133        new SimpleInstruction(InstructionConstants.OP_DUP),
134        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
135        new ConstantInstruction(InstructionConstants.OP_LDC, A),
136        new SimpleInstruction(InstructionConstants.OP_AASTORE),
137        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
138    };
139
140    // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
141    private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[]
142    {
143        new ConstantInstruction(InstructionConstants.OP_LDC, X),
144        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
145        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
146        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
147        new SimpleInstruction(InstructionConstants.OP_DUP),
148        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
149        new ConstantInstruction(InstructionConstants.OP_LDC, A),
150        new SimpleInstruction(InstructionConstants.OP_AASTORE),
151        new SimpleInstruction(InstructionConstants.OP_DUP),
152        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
153        new ConstantInstruction(InstructionConstants.OP_LDC, B),
154        new SimpleInstruction(InstructionConstants.OP_AASTORE),
155        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
156    };
157
158    // get[Declared]Field("someField").
159    private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[]
160    {
161        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
162        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
163    };
164
165    // get[Declared]Method("someMethod", new Class[] {}).
166    private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[]
167    {
168        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
169        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
170        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
171        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
172    };
173
174    // get[Declared]Method("someMethod", new Class[] { A.class }).
175    private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[]
176    {
177        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
178        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
179        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
180        new SimpleInstruction(InstructionConstants.OP_DUP),
181        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
182        new ConstantInstruction(InstructionConstants.OP_LDC, A),
183        new SimpleInstruction(InstructionConstants.OP_AASTORE),
184        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
185    };
186
187    // get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
188    private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[]
189    {
190        new ConstantInstruction(InstructionConstants.OP_LDC, Y),
191        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
192        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
193        new SimpleInstruction(InstructionConstants.OP_DUP),
194        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
195        new ConstantInstruction(InstructionConstants.OP_LDC, A),
196        new SimpleInstruction(InstructionConstants.OP_AASTORE),
197        new SimpleInstruction(InstructionConstants.OP_DUP),
198        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
199        new ConstantInstruction(InstructionConstants.OP_LDC, B),
200        new SimpleInstruction(InstructionConstants.OP_AASTORE),
201        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
202    };
203
204
205    private final ClassPool      programClassPool;
206    private final ClassPool      libraryClassPool;
207    private final WarningPrinter notePrinter;
208    private final StringMatcher  noteFieldExceptionMatcher;
209    private final StringMatcher  noteMethodExceptionMatcher;
210
211
212    private final InstructionSequenceMatcher constantGetFieldMatcher =
213        new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
214                                       CONSTANT_GET_FIELD_INSTRUCTIONS);
215
216    private final InstructionSequenceMatcher constantGetDeclaredFieldMatcher =
217        new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
218                                       CONSTANT_GET_FIELD_INSTRUCTIONS);
219
220    private final InstructionSequenceMatcher constantGetMethodMatcher0 =
221        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
222                                       CONSTANT_GET_METHOD_INSTRUCTIONS0);
223
224    private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 =
225        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
226                                       CONSTANT_GET_METHOD_INSTRUCTIONS0);
227
228    private final InstructionSequenceMatcher constantGetMethodMatcher1 =
229        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
230                                       CONSTANT_GET_METHOD_INSTRUCTIONS1);
231
232    private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 =
233        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
234                                       CONSTANT_GET_METHOD_INSTRUCTIONS1);
235
236    private final InstructionSequenceMatcher constantGetMethodMatcher2 =
237        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
238                                       CONSTANT_GET_METHOD_INSTRUCTIONS2);
239
240    private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 =
241        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
242                                       CONSTANT_GET_METHOD_INSTRUCTIONS2);
243
244    private final InstructionSequenceMatcher getFieldMatcher =
245        new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
246                                       GET_FIELD_INSTRUCTIONS);
247
248    private final InstructionSequenceMatcher getDeclaredFieldMatcher =
249        new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
250                                       GET_FIELD_INSTRUCTIONS);
251
252    private final InstructionSequenceMatcher getMethodMatcher0 =
253        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
254                                       GET_METHOD_INSTRUCTIONS0);
255
256    private final InstructionSequenceMatcher getDeclaredMethodMatcher0 =
257        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
258                                       GET_METHOD_INSTRUCTIONS0);
259
260    private final InstructionSequenceMatcher getMethodMatcher1 =
261        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
262                                       GET_METHOD_INSTRUCTIONS1);
263
264    private final InstructionSequenceMatcher getDeclaredMethodMatcher1 =
265        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
266                                       GET_METHOD_INSTRUCTIONS1);
267
268    private final InstructionSequenceMatcher getMethodMatcher2 =
269        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
270                                       GET_METHOD_INSTRUCTIONS2);
271
272    private final InstructionSequenceMatcher getDeclaredMethodMatcher2 =
273        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
274                                       GET_METHOD_INSTRUCTIONS2);
275
276    private final MemberFinder memberFinder = new MemberFinder();
277
278
279    // Fields acting as parameters for the visitors.
280    private Clazz   referencedClass;
281    private boolean isDeclared;
282    private boolean isField;
283
284
285
286    /**
287     * Creates a new DynamicMemberReferenceInitializer.
288     */
289    public DynamicMemberReferenceInitializer(ClassPool      programClassPool,
290                                             ClassPool      libraryClassPool,
291                                             WarningPrinter notePrinter,
292                                             StringMatcher  noteFieldExceptionMatcher,
293                                             StringMatcher  noteMethodExceptionMatcher)
294    {
295        this.programClassPool           = programClassPool;
296        this.libraryClassPool           = libraryClassPool;
297        this.notePrinter                = notePrinter;
298        this.noteFieldExceptionMatcher  = noteFieldExceptionMatcher;
299        this.noteMethodExceptionMatcher = noteMethodExceptionMatcher;
300    }
301
302
303    // Implementations for InstructionVisitor.
304
305    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
306    {
307        // Try to match the SomeClass.class.getField("someField") construct.
308        matchGetMember(clazz, method, codeAttribute, offset, instruction,
309                       constantGetFieldMatcher,
310                       getFieldMatcher, true, false);
311
312        // Try to match the SomeClass.class.getDeclaredField("someField") construct.
313        matchGetMember(clazz, method, codeAttribute, offset, instruction,
314                       constantGetDeclaredFieldMatcher,
315                       getDeclaredFieldMatcher, true, true);
316
317        // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
318        // {}) construct.
319        matchGetMember(clazz, method, codeAttribute, offset, instruction,
320                       constantGetMethodMatcher0,
321                       getMethodMatcher0, false, false);
322
323        // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
324        //  new Class[] {}) construct.
325        matchGetMember(clazz, method, codeAttribute, offset, instruction,
326                       constantGetDeclaredMethodMatcher0,
327                       getDeclaredMethodMatcher0, false, true);
328
329        // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
330        // { A.class }) construct.
331        matchGetMember(clazz, method, codeAttribute, offset, instruction,
332                       constantGetMethodMatcher1,
333                       getMethodMatcher1, false, false);
334
335        // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
336        //  new Class[] { A.class }) construct.
337        matchGetMember(clazz, method, codeAttribute, offset, instruction,
338                       constantGetDeclaredMethodMatcher1,
339                       getDeclaredMethodMatcher1, false, true);
340
341        // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
342        // { A.class, B.class }) construct.
343        matchGetMember(clazz, method, codeAttribute, offset, instruction,
344                       constantGetMethodMatcher2,
345                       getMethodMatcher2, false, false);
346
347        // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
348        //  new Class[] { A.class, B.class }) construct.
349        matchGetMember(clazz, method, codeAttribute, offset, instruction,
350                       constantGetDeclaredMethodMatcher2,
351                       getDeclaredMethodMatcher2, false, true);
352    }
353
354
355    /**
356     * Tries to match the next instruction and fills out the string constant
357     * or prints out a note accordingly.
358     */
359    private void matchGetMember(Clazz                      clazz,
360                                Method                     method,
361                                CodeAttribute              codeAttribute,
362                                int                        offset,
363                                Instruction                instruction,
364                                InstructionSequenceMatcher constantSequenceMatcher,
365                                InstructionSequenceMatcher variableSequenceMatcher,
366                                boolean                    isField,
367                                boolean                    isDeclared)
368    {
369        // Try to match the next instruction in the constant sequence.
370        instruction.accept(clazz, method, codeAttribute, offset,
371                           constantSequenceMatcher);
372
373        // Did we find a match to fill out the string constant?
374        if (constantSequenceMatcher.isMatching())
375        {
376            this.isField    = isField;
377            this.isDeclared = isDeclared;
378
379            // Get the member's class.
380            clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(X), this);
381
382            // Fill out the matched string constant.
383            clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(Y), this);
384
385            // Don't look for the dynamic construct.
386            variableSequenceMatcher.reset();
387        }
388
389        // Try to match the next instruction in the variable sequence.
390        instruction.accept(clazz, method, codeAttribute, offset,
391                           variableSequenceMatcher);
392
393        // Did we find a match to print out a note?
394        if (variableSequenceMatcher.isMatching())
395        {
396            // Print out a note about the dynamic invocation.
397            printDynamicInvocationNote(clazz,
398                                       variableSequenceMatcher,
399                                       isField,
400                                       isDeclared);
401        }
402    }
403
404
405    // Implementations for ConstantVisitor.
406
407    /**
408     * Remembers the referenced class.
409     */
410    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
411    {
412        // Remember the referenced class.
413        referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
414            null :
415            classConstant.referencedClass;
416    }
417
418
419    /**
420     * Fills out the link to the referenced class member.
421     */
422    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
423    {
424        if (referencedClass != null)
425        {
426            String name = stringConstant.getString(clazz);
427
428            // See if we can find the referenced class member locally, or
429            // somewhere in the hierarchy.
430            Member referencedMember = isDeclared ? isField ?
431                (Member)referencedClass.findField(name, null) :
432                (Member)referencedClass.findMethod(name, null) :
433                (Member)memberFinder.findMember(clazz,
434                                                referencedClass,
435                                                name,
436                                                null,
437                                                isField);
438            if (referencedMember != null)
439            {
440                stringConstant.referencedMember = referencedMember;
441                stringConstant.referencedClass  = isDeclared ?
442                    referencedClass :
443                    memberFinder.correspondingClass();
444            }
445        }
446    }
447
448
449    // Small utility methods.
450
451    /**
452     * Prints out a note on the matched dynamic invocation, if necessary.
453     */
454    private void printDynamicInvocationNote(Clazz                      clazz,
455                                            InstructionSequenceMatcher noteSequenceMatcher,
456                                            boolean                    isField,
457                                            boolean                    isDeclared)
458    {
459        // Print out a note about the dynamic invocation.
460        if (notePrinter != null &&
461            notePrinter.accepts(clazz.getName()))
462        {
463            // Is the class member name in the list of exceptions?
464            StringMatcher noteExceptionMatcher = isField ?
465                noteFieldExceptionMatcher :
466                noteMethodExceptionMatcher;
467
468            int    memberNameIndex = noteSequenceMatcher.matchedConstantIndex(Y);
469            String memberName      = clazz.getStringString(memberNameIndex);
470
471            if (noteExceptionMatcher == null ||
472                !noteExceptionMatcher.matches(memberName))
473            {
474                // Compose the external member name and partial descriptor.
475                String externalMemberDescription = memberName;
476
477                if (!isField)
478                {
479                    externalMemberDescription += '(';
480                    for (int count = 0; count < 2; count++)
481                    {
482                        int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count);
483                        if (memberArgumentIndex > 0)
484                        {
485                            if (count > 0)
486                            {
487                                externalMemberDescription += ',';
488                            }
489                            String className = clazz.getClassName(memberArgumentIndex);
490                            externalMemberDescription += ClassUtil.isInternalArrayType(className) ?
491                                ClassUtil.externalType(className) :
492                                ClassUtil.externalClassName(className);
493                        }
494                    }
495                    externalMemberDescription += ')';
496                }
497
498                // Print out the actual note.
499                notePrinter.print(clazz.getName(),
500                                  "Note: " +
501                                  ClassUtil.externalClassName(clazz.getName()) +
502                                  " accesses a " +
503                                  (isDeclared ? "declared " : "") +
504                                  (isField    ? "field" : "method") +
505                                  " '" +
506                                  externalMemberDescription +
507                                  "' dynamically");
508
509                // Print out notes about potential candidates.
510                ClassVisitor classVisitor;
511
512                if (isField)
513                {
514                    classVisitor =
515                       new AllFieldVisitor(
516                       new MemberNameFilter(memberName, this));
517                }
518                else
519                {
520                    // Compose the partial method descriptor.
521                    String methodDescriptor = "(";
522                    for (int count = 0; count < 2; count++)
523                    {
524                        int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count);
525                        if (memberArgumentIndex > 0)
526                        {
527                            if (count > 0)
528                            {
529                                methodDescriptor += ',';
530                            }
531                            String className = clazz.getClassName(memberArgumentIndex);
532                            methodDescriptor += ClassUtil.isInternalArrayType(className) ?
533                                className :
534                                ClassUtil.internalTypeFromClassName(className);
535                        }
536                    }
537                    methodDescriptor += ")L///;";
538
539                    classVisitor =
540                        new AllMethodVisitor(
541                        new MemberNameFilter(memberName,
542                        new MemberDescriptorFilter(methodDescriptor, this)));
543                }
544
545                programClassPool.classesAcceptAlphabetically(classVisitor);
546                libraryClassPool.classesAcceptAlphabetically(classVisitor);
547            }
548        }
549    }
550
551
552    // Implementations for MemberVisitor.
553
554    public void visitProgramField(ProgramClass programClass, ProgramField programField)
555    {
556        if (notePrinter.accepts(programClass.getName()))
557        {
558            System.out.println("      Maybe this is program field '" +
559                               ClassUtil.externalFullClassDescription(0, programClass.getName()) +
560                               " { " +
561                               ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) +
562                               "; }'");
563        }
564    }
565
566
567    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
568    {
569        if (notePrinter.accepts(programClass.getName()))
570        {
571            System.out.println("      Maybe this is program method '" +
572                               ClassUtil.externalFullClassDescription(0, programClass.getName()) +
573                               " { " +
574                               ClassUtil.externalFullMethodDescription(null, 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
575                               "; }'");
576        }
577    }
578
579
580    public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
581    {
582        if (notePrinter.accepts(libraryClass.getName()))
583        {
584            System.out.println("      Maybe this is library field '" +
585                               ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
586                               " { " +
587                               ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) +
588                               "; }'");
589        }
590    }
591
592
593    public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
594    {
595        if (notePrinter.accepts(libraryClass.getName()))
596        {
597            System.out.println("      Maybe this is library method '" +
598                               ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
599                               " { " +
600                               ClassUtil.externalFullMethodDescription(null, 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
601                               "; }'");
602        }
603    }
604}