• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.classfile.util;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.CodeAttribute;
25 import proguard.classfile.constant.*;
26 import proguard.classfile.constant.visitor.ConstantVisitor;
27 import proguard.classfile.instruction.*;
28 import proguard.classfile.instruction.visitor.InstructionVisitor;
29 import proguard.classfile.visitor.*;
30 import proguard.util.StringMatcher;
31 
32 /**
33  * This InstructionVisitor initializes any constant
34  * <code>Class.get[Declared]{Field,Method}</code> references of all instructions
35  * it visits. More specifically, it fills out the references of string constant
36  * pool entries that refer to a class member in the program class pool or in the
37  * library class pool.
38  * <p>
39  * It optionally prints notes if on usage of
40  * <code>(SomeClass)Class.forName(variable).newInstance()</code>.
41  * <p>
42  * The class hierarchy and references must be initialized before using this
43  * visitor.
44  *
45  * @see ClassSuperHierarchyInitializer
46  * @see ClassReferenceInitializer
47  *
48  * @author Eric Lafortune
49  */
50 public class DynamicMemberReferenceInitializer
51 extends      SimplifiedVisitor
52 implements   InstructionVisitor,
53              ConstantVisitor,
54              MemberVisitor
55 {
56     //*
57     private static final boolean DEBUG = false;
58     /*/
59     private static       boolean DEBUG = true;
60     //*/
61 
62     public static final int CLASS_INDEX       = InstructionSequenceMatcher.X;
63     public static final int MEMBER_NAME_INDEX = InstructionSequenceMatcher.Y;
64     public static final int TYPE_CLASS_INDEX  = InstructionSequenceMatcher.Z;
65 
66     public static final int PARAMETER0_CLASS_INDEX = InstructionSequenceMatcher.A;
67     public static final int PARAMETER1_CLASS_INDEX = InstructionSequenceMatcher.B;
68     public static final int PARAMETER2_CLASS_INDEX = InstructionSequenceMatcher.C;
69     public static final int PARAMETER3_CLASS_INDEX = InstructionSequenceMatcher.D;
70 
71 
72     private final Constant[] GET_FIELD_CONSTANTS = new Constant[]
73     {
74         new MethodrefConstant(1, 2, null, null),
75         new ClassConstant(3, null),
76         new NameAndTypeConstant(4, 5),
77         new Utf8Constant(ClassConstants.NAME_JAVA_LANG_CLASS),
78         new Utf8Constant(ClassConstants.METHOD_NAME_CLASS_GET_FIELD),
79         new Utf8Constant(ClassConstants.METHOD_TYPE_CLASS_GET_FIELD),
80     };
81 
82     private final Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[]
83     {
84         new MethodrefConstant(1, 2, null, null),
85         new ClassConstant(3, null),
86         new NameAndTypeConstant(4, 5),
87         new Utf8Constant(ClassConstants.NAME_JAVA_LANG_CLASS),
88         new Utf8Constant(ClassConstants.METHOD_NAME_CLASS_GET_DECLARED_FIELD),
89         new Utf8Constant(ClassConstants.METHOD_TYPE_CLASS_GET_DECLARED_FIELD),
90     };
91 
92     private final Constant[] GET_CONSTRUCTOR_CONSTANTS = new Constant[]
93     {
94         new MethodrefConstant(1, 2, null, null),
95         new ClassConstant(3, null),
96         new NameAndTypeConstant(4, 5),
97         new Utf8Constant(ClassConstants.NAME_JAVA_LANG_CLASS),
98         new Utf8Constant(ClassConstants.CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR),
99         new Utf8Constant(ClassConstants.CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR),
100     };
101 
102     private final Constant[] GET_DECLARED_CONSTRUCTOR_CONSTANTS = new Constant[]
103     {
104         new MethodrefConstant(1, 2, null, null),
105         new ClassConstant(3, null),
106         new NameAndTypeConstant(4, 5),
107         new Utf8Constant(ClassConstants.NAME_JAVA_LANG_CLASS),
108         new Utf8Constant(ClassConstants.CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR),
109         new Utf8Constant(ClassConstants.CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR),
110     };
111 
112     private final Constant[] GET_METHOD_CONSTANTS = new Constant[]
113     {
114         new MethodrefConstant(1, 2, null, null),
115         new ClassConstant(3, null),
116         new NameAndTypeConstant(4, 5),
117         new Utf8Constant(ClassConstants.NAME_JAVA_LANG_CLASS),
118         new Utf8Constant(ClassConstants.METHOD_NAME_CLASS_GET_METHOD),
119         new Utf8Constant(ClassConstants.METHOD_TYPE_CLASS_GET_METHOD),
120     };
121 
122     private final Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[]
123     {
124         new MethodrefConstant(1, 2, null, null),
125         new ClassConstant(3, null),
126         new NameAndTypeConstant(4, 5),
127         new Utf8Constant(ClassConstants.NAME_JAVA_LANG_CLASS),
128         new Utf8Constant(ClassConstants.METHOD_NAME_CLASS_GET_DECLARED_METHOD),
129         new Utf8Constant(ClassConstants.METHOD_TYPE_CLASS_GET_DECLARED_METHOD),
130     };
131 
132     private final Constant[] NEW_INTEGER_UPDATER_CONSTANTS = new Constant[]
133     {
134         new MethodrefConstant(1, 2, null, null),
135         new ClassConstant(3, null),
136         new NameAndTypeConstant(4, 5),
137         new Utf8Constant(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER),
138         new Utf8Constant(ClassConstants.METHOD_NAME_NEW_UPDATER),
139         new Utf8Constant(ClassConstants.METHOD_TYPE_NEW_INTEGER_UPDATER),
140     };
141 
142     private final Constant[] NEW_LONG_UPDATER_CONSTANTS = new Constant[]
143     {
144         new MethodrefConstant(1, 2, null, null),
145         new ClassConstant(3, null),
146         new NameAndTypeConstant(4, 5),
147         new Utf8Constant(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER),
148         new Utf8Constant(ClassConstants.METHOD_NAME_NEW_UPDATER),
149         new Utf8Constant(ClassConstants.METHOD_TYPE_NEW_LONG_UPDATER),
150     };
151 
152     private final Constant[] NEW_REFERENCE_UPDATER_CONSTANTS = new Constant[]
153     {
154         new MethodrefConstant(1, 2, null, null),
155         new ClassConstant(3, null),
156         new NameAndTypeConstant(4, 5),
157         new Utf8Constant(ClassConstants.NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER),
158         new Utf8Constant(ClassConstants.METHOD_NAME_NEW_UPDATER),
159         new Utf8Constant(ClassConstants.METHOD_TYPE_NEW_REFERENCE_UPDATER),
160     };
161 
162     // SomeClass.class.get[Declared]Field("someField").
163     private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[]
164     {
165         new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
166         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
167         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
168     };
169 
170 //    // SomeClass.class.get[Declared]Constructor(new Class[] {}).
171 //    private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
172 //    {
173 //        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
174 //        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
175 //        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
176 //        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
177 //    };
178 //
179 //    // SomeClass.class.get[Declared]Constructor(new Class[] { A.class }).
180 //    private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
181 //    {
182 //        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
183 //        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
184 //        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
185 //        new SimpleInstruction(InstructionConstants.OP_DUP),
186 //        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
187 //        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
188 //        new SimpleInstruction(InstructionConstants.OP_AASTORE),
189 //        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
190 //    };
191 //
192 //    // SomeClass.class.get[Declared]Constructor(new Class[] { A.class, B.class }).
193 //    private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
194 //    {
195 //        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
196 //        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
197 //        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
198 //        new SimpleInstruction(InstructionConstants.OP_DUP),
199 //        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
200 //        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
201 //        new SimpleInstruction(InstructionConstants.OP_AASTORE),
202 //        new SimpleInstruction(InstructionConstants.OP_DUP),
203 //        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
204 //        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
205 //        new SimpleInstruction(InstructionConstants.OP_AASTORE),
206 //        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
207 //    };
208 
209     // SomeClass.class.get[Declared]Method("someMethod", new Class[] {}).
210     private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[]
211     {
212         new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
213         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
214         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
215         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
216         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
217     };
218 
219     // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }).
220     private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[]
221     {
222         new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
223         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
224         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
225         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
226         new SimpleInstruction(InstructionConstants.OP_DUP),
227         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
228         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
229         new SimpleInstruction(InstructionConstants.OP_AASTORE),
230         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
231     };
232 
233     // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
234     private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[]
235     {
236         new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
237         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
238         new SimpleInstruction(InstructionConstants.OP_ICONST_2),
239         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
240         new SimpleInstruction(InstructionConstants.OP_DUP),
241         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
242         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
243         new SimpleInstruction(InstructionConstants.OP_AASTORE),
244         new SimpleInstruction(InstructionConstants.OP_DUP),
245         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
246         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
247         new SimpleInstruction(InstructionConstants.OP_AASTORE),
248         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
249     };
250 
251     // AtomicIntegerFieldUpdater.newUpdater(A.class, "someField").
252     // AtomicLongFieldUpdater.newUpdater(A.class, "someField").
253     private final Instruction[] CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS = new Instruction[]
254     {
255         new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
256         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
257         new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
258     };
259 
260     // AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "someField").
261     private final Instruction[] CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS = new Instruction[]
262     {
263         new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
264         new ConstantInstruction(InstructionConstants.OP_LDC, TYPE_CLASS_INDEX),
265         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
266         new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
267     };
268 
269     // get[Declared]Field("someField").
270     private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[]
271     {
272         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
273         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
274     };
275 
276 //    // get[Declared]Constructor(new Class[] {}).
277 //    private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
278 //    {
279 //        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
280 //        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
281 //        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
282 //    };
283 
284     // get[Declared]Constructor(new Class[] { A.class }).
285     private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
286     {
287         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
288         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
289         new SimpleInstruction(InstructionConstants.OP_DUP),
290         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
291         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
292         new SimpleInstruction(InstructionConstants.OP_AASTORE),
293         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
294     };
295 
296     // get[Declared]Constructor(new Class[] { A.class, B.class }).
297     private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
298     {
299         new SimpleInstruction(InstructionConstants.OP_ICONST_2),
300         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
301         new SimpleInstruction(InstructionConstants.OP_DUP),
302         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
303         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
304         new SimpleInstruction(InstructionConstants.OP_AASTORE),
305         new SimpleInstruction(InstructionConstants.OP_DUP),
306         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
307         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
308         new SimpleInstruction(InstructionConstants.OP_AASTORE),
309         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
310     };
311 
312     // get[Declared]Method("someMethod", new Class[] {}).
313     private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[]
314     {
315         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
316         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
317         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
318         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
319     };
320 
321     // get[Declared]Method("someMethod", new Class[] { A.class }).
322     private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[]
323     {
324         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
325         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
326         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
327         new SimpleInstruction(InstructionConstants.OP_DUP),
328         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
329         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
330         new SimpleInstruction(InstructionConstants.OP_AASTORE),
331         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
332     };
333 
334     // get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
335     private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[]
336     {
337         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
338         new SimpleInstruction(InstructionConstants.OP_ICONST_2),
339         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
340         new SimpleInstruction(InstructionConstants.OP_DUP),
341         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
342         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
343         new SimpleInstruction(InstructionConstants.OP_AASTORE),
344         new SimpleInstruction(InstructionConstants.OP_DUP),
345         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
346         new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
347         new SimpleInstruction(InstructionConstants.OP_AASTORE),
348         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
349     };
350 
351     // AtomicIntegerFieldUpdater.newUpdater(..., "someField").
352     // AtomicLongFieldUpdater.newUpdater(..., "someField").
353     // AtomicReferenceFieldUpdater.newUpdater(..., "someField").
354     private final Instruction[] NEW_UPDATER_INSTRUCTIONS = new Instruction[]
355     {
356         new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
357         new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
358     };
359 
360 
361     private final ClassPool      programClassPool;
362     private final ClassPool      libraryClassPool;
363     private final WarningPrinter notePrinter;
364     private final StringMatcher  noteFieldExceptionMatcher;
365     private final StringMatcher  noteMethodExceptionMatcher;
366 
367 
368     private final InstructionSequenceMatcher constantGetFieldMatcher =
369         new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
370                                        CONSTANT_GET_FIELD_INSTRUCTIONS);
371 
372     private final InstructionSequenceMatcher constantGetDeclaredFieldMatcher =
373         new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
374                                        CONSTANT_GET_FIELD_INSTRUCTIONS);
375 
376 //    private final InstructionSequenceMatcher constantGetConstructorMatcher0 =
377 //        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
378 //                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
379 //
380 //    private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher0 =
381 //        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
382 //                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
383 //
384 //    private final InstructionSequenceMatcher constantGetConstructorMatcher1 =
385 //        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
386 //                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
387 //
388 //    private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher1 =
389 //        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
390 //                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
391 //
392 //    private final InstructionSequenceMatcher constantGetConstructorMatcher2 =
393 //        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
394 //                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
395 //
396 //    private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher2 =
397 //        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
398 //                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
399 
400     private final InstructionSequenceMatcher constantGetMethodMatcher0 =
401         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
402                                        CONSTANT_GET_METHOD_INSTRUCTIONS0);
403 
404     private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 =
405         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
406                                        CONSTANT_GET_METHOD_INSTRUCTIONS0);
407 
408     private final InstructionSequenceMatcher constantGetMethodMatcher1 =
409         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
410                                        CONSTANT_GET_METHOD_INSTRUCTIONS1);
411 
412     private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 =
413         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
414                                        CONSTANT_GET_METHOD_INSTRUCTIONS1);
415 
416     private final InstructionSequenceMatcher constantGetMethodMatcher2 =
417         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
418                                        CONSTANT_GET_METHOD_INSTRUCTIONS2);
419 
420     private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 =
421         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
422                                        CONSTANT_GET_METHOD_INSTRUCTIONS2);
423 
424     private final InstructionSequenceMatcher constantGetIntegerUpdaterMatcher =
425         new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
426                                        CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
427 
428     private final InstructionSequenceMatcher constantGetLongUpdaterMatcher =
429         new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
430                                        CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
431 
432     private final InstructionSequenceMatcher constantGetReferenceUpdaterMatcher =
433         new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
434                                        CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS);
435 
436     private final InstructionSequenceMatcher getFieldMatcher =
437         new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
438                                        GET_FIELD_INSTRUCTIONS);
439 
440     private final InstructionSequenceMatcher getDeclaredFieldMatcher =
441         new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
442                                        GET_FIELD_INSTRUCTIONS);
443 
444 //    private final InstructionSequenceMatcher getConstructorMatcher0 =
445 //        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
446 //                                       GET_CONSTRUCTOR_INSTRUCTIONS0);
447 //
448 //    private final InstructionSequenceMatcher getDeclaredConstructorMatcher0 =
449 //        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
450 //                                       GET_CONSTRUCTOR_INSTRUCTIONS0);
451 
452     private final InstructionSequenceMatcher getConstructorMatcher1 =
453         new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
454                                        GET_CONSTRUCTOR_INSTRUCTIONS1);
455 
456     private final InstructionSequenceMatcher getDeclaredConstructorMatcher1 =
457         new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
458                                        GET_CONSTRUCTOR_INSTRUCTIONS1);
459 
460     private final InstructionSequenceMatcher getConstructorMatcher2 =
461         new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
462                                        GET_CONSTRUCTOR_INSTRUCTIONS2);
463 
464     private final InstructionSequenceMatcher getDeclaredConstructorMatcher2 =
465         new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
466                                        GET_CONSTRUCTOR_INSTRUCTIONS2);
467 
468     private final InstructionSequenceMatcher getMethodMatcher0 =
469         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
470                                        GET_METHOD_INSTRUCTIONS0);
471 
472     private final InstructionSequenceMatcher getDeclaredMethodMatcher0 =
473         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
474                                        GET_METHOD_INSTRUCTIONS0);
475 
476     private final InstructionSequenceMatcher getMethodMatcher1 =
477         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
478                                        GET_METHOD_INSTRUCTIONS1);
479 
480     private final InstructionSequenceMatcher getDeclaredMethodMatcher1 =
481         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
482                                        GET_METHOD_INSTRUCTIONS1);
483 
484     private final InstructionSequenceMatcher getMethodMatcher2 =
485         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
486                                        GET_METHOD_INSTRUCTIONS2);
487 
488     private final InstructionSequenceMatcher getDeclaredMethodMatcher2 =
489         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
490                                        GET_METHOD_INSTRUCTIONS2);
491 
492     private final InstructionSequenceMatcher getIntegerUpdaterMatcher =
493         new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
494                                        NEW_UPDATER_INSTRUCTIONS);
495 
496     private final InstructionSequenceMatcher getLongUpdaterMatcher =
497         new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
498                                        NEW_UPDATER_INSTRUCTIONS);
499 
500     private final InstructionSequenceMatcher getReferenceUpdaterMatcher =
501         new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
502                                        NEW_UPDATER_INSTRUCTIONS);
503 
504     private final MemberFinder memberFinder = new MemberFinder();
505 
506 
507     // Fields acting as parameters for the visitors.
508     private Clazz   referencedClass;
509     private String descriptor;
510     private boolean isDeclared;
511     private boolean isField;
512 
513 
514 
515     /**
516      * Creates a new DynamicMemberReferenceInitializer.
517      */
DynamicMemberReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter notePrinter, StringMatcher noteFieldExceptionMatcher, StringMatcher noteMethodExceptionMatcher)518     public DynamicMemberReferenceInitializer(ClassPool      programClassPool,
519                                              ClassPool      libraryClassPool,
520                                              WarningPrinter notePrinter,
521                                              StringMatcher  noteFieldExceptionMatcher,
522                                              StringMatcher  noteMethodExceptionMatcher)
523     {
524         this.programClassPool           = programClassPool;
525         this.libraryClassPool           = libraryClassPool;
526         this.notePrinter                = notePrinter;
527         this.noteFieldExceptionMatcher  = noteFieldExceptionMatcher;
528         this.noteMethodExceptionMatcher = noteMethodExceptionMatcher;
529     }
530 
531 
532     // Implementations for InstructionVisitor.
533 
visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)534     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
535     {
536         // Try to match the SomeClass.class.getField("someField") construct.
537         matchGetMember(clazz, method, codeAttribute, offset, instruction,
538                        constantGetFieldMatcher,
539                        getFieldMatcher, true, false, null, null);
540 
541         // Try to match the SomeClass.class.getDeclaredField("someField") construct.
542         matchGetMember(clazz, method, codeAttribute, offset, instruction,
543                        constantGetDeclaredFieldMatcher,
544                        getDeclaredFieldMatcher, true, true, null, null);
545 
546 //        // Try to match the SomeClass.class.getConstructor(new Class[]
547 //        // {}) construct.
548 //        matchGetMember(clazz, method, codeAttribute, offset, instruction,
549 //                       cnull, //onstantGetConstructorMatcher0,
550 //                       getConstructorMatcher0, false, false,
551 //                       ClassConstants.METHOD_NAME_INIT, null);
552 //
553 //        // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
554 //        // {}) construct.
555 //        matchGetMember(clazz, method, codeAttribute, offset, instruction,
556 //                       null, //constantGetDeclaredConstructorMatcher0,
557 //                       getDeclaredConstructorMatcher0, false, true,
558 //                       ClassConstants.METHOD_NAME_INIT, null);
559 
560         // Try to match the SomeClass.class.getConstructor(new Class[]
561         // { A.class }) construct.
562         matchGetMember(clazz, method, codeAttribute, offset, instruction,
563                        null, //constantGetConstructorMatcher1,
564                        getConstructorMatcher1, false, false,
565                        ClassConstants.METHOD_NAME_INIT, null);
566 
567         // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
568         // { A.class }) construct.
569         matchGetMember(clazz, method, codeAttribute, offset, instruction,
570                        null, //constantGetDeclaredConstructorMatcher1,
571                        getDeclaredConstructorMatcher1, false, true,
572                        ClassConstants.METHOD_NAME_INIT, null);
573 
574         // Try to match the SomeClass.class.getConstructor(new Class[]
575         // { A.class, B.class }) construct.
576         matchGetMember(clazz, method, codeAttribute, offset, instruction,
577                        null, //constantGetConstructorMatcher2,
578                        getConstructorMatcher2, false, false,
579                        ClassConstants.METHOD_NAME_INIT, null);
580 
581         // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
582         // { A.class, B.class }) construct.
583         matchGetMember(clazz, method, codeAttribute, offset, instruction,
584                        null, //constantGetDeclaredConstructorMatcher2,
585                        getDeclaredConstructorMatcher2, false, true,
586                        ClassConstants.METHOD_NAME_INIT, null);
587 
588         // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
589         // {}) construct.
590         matchGetMember(clazz, method, codeAttribute, offset, instruction,
591                        constantGetMethodMatcher0,
592                        getMethodMatcher0, false, false, null, null);
593 
594         // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
595         // new Class[] {}) construct.
596         matchGetMember(clazz, method, codeAttribute, offset, instruction,
597                        constantGetDeclaredMethodMatcher0,
598                        getDeclaredMethodMatcher0, false, true, null, null);
599 
600         // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
601         // { A.class }) construct.
602         matchGetMember(clazz, method, codeAttribute, offset, instruction,
603                        constantGetMethodMatcher1,
604                        getMethodMatcher1, false, false, null, null);
605 
606         // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
607         //  new Class[] { A.class }) construct.
608         matchGetMember(clazz, method, codeAttribute, offset, instruction,
609                        constantGetDeclaredMethodMatcher1,
610                        getDeclaredMethodMatcher1, false, true, null, null);
611 
612         // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
613         // { A.class, B.class }) construct.
614         matchGetMember(clazz, method, codeAttribute, offset, instruction,
615                        constantGetMethodMatcher2,
616                        getMethodMatcher2, false, false, null, null);
617 
618         // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
619         // new Class[] { A.class, B.class }) construct.
620         matchGetMember(clazz, method, codeAttribute, offset, instruction,
621                        constantGetDeclaredMethodMatcher2,
622                        getDeclaredMethodMatcher2, false, true, null, null);
623 
624         // Try to match the AtomicIntegerFieldUpdater.newUpdater(
625         // SomeClass.class, "someField") construct.
626         matchGetMember(clazz, method, codeAttribute, offset, instruction,
627                        constantGetIntegerUpdaterMatcher,
628                        getIntegerUpdaterMatcher, true, false, null,
629                        "" + ClassConstants.TYPE_INT);
630 
631         // Try to match the AtomicLongFieldUpdater.newUpdater(
632         // SomeClass.class, "someField") construct.
633         matchGetMember(clazz, method, codeAttribute, offset, instruction,
634                        constantGetLongUpdaterMatcher,
635                        getLongUpdaterMatcher, true, false, null,
636                        "" + ClassConstants.TYPE_LONG);
637 
638         // Try to match the AtomicReferenceFieldUpdater.newUpdater(
639         // SomeClass.class, SomeClass.class, "someField") construct.
640         matchGetMember(clazz, method, codeAttribute, offset, instruction,
641                        constantGetReferenceUpdaterMatcher,
642                        getReferenceUpdaterMatcher, true, false, null, null);
643     }
644 
645 
646     /**
647      * Tries to match the next instruction and fills out the string constant
648      * or prints out a note accordingly.
649      */
matchGetMember(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction, InstructionSequenceMatcher constantSequenceMatcher, InstructionSequenceMatcher variableSequenceMatcher, boolean isField, boolean isDeclared, String defaultName, String defaultDescriptor)650     private void matchGetMember(Clazz                      clazz,
651                                 Method                     method,
652                                 CodeAttribute              codeAttribute,
653                                 int                        offset,
654                                 Instruction                instruction,
655                                 InstructionSequenceMatcher constantSequenceMatcher,
656                                 InstructionSequenceMatcher variableSequenceMatcher,
657                                 boolean                    isField,
658                                 boolean                    isDeclared,
659                                 String                     defaultName,
660                                 String                     defaultDescriptor)
661     {
662         if (constantSequenceMatcher != null)
663         {
664             // Try to match the next instruction in the constant sequence.
665             instruction.accept(clazz, method, codeAttribute, offset,
666                                constantSequenceMatcher);
667 
668             // Did we find a match to fill out the string constant?
669             if (constantSequenceMatcher.isMatching())
670             {
671                 initializeStringReference(clazz,
672                                           constantSequenceMatcher,
673                                           isField,
674                                           isDeclared,
675                                           defaultDescriptor);
676 
677                 // Don't look for the dynamic construct.
678                 variableSequenceMatcher.reset();
679             }
680         }
681 
682         // Try to match the next instruction in the variable sequence.
683         instruction.accept(clazz, method, codeAttribute, offset,
684                            variableSequenceMatcher);
685 
686         // Did we find a match to print out a note?
687         if (variableSequenceMatcher.isMatching())
688         {
689             // Print out a note about the dynamic invocation.
690             printDynamicInvocationNote(clazz,
691                                        variableSequenceMatcher,
692                                        isField,
693                                        isDeclared,
694                                        defaultName,
695                                        defaultDescriptor);
696         }
697     }
698 
699 
700     /**
701      * Initializes the reference of the matched string constant to the
702      * referenced class member and its class.
703      */
initializeStringReference(Clazz clazz, InstructionSequenceMatcher constantSequenceMatcher, boolean isField, boolean isDeclared, String defaultDescriptor)704     private void initializeStringReference(Clazz                      clazz,
705                                            InstructionSequenceMatcher constantSequenceMatcher,
706                                            boolean                    isField,
707                                            boolean                    isDeclared,
708                                            String                     defaultDescriptor)
709     {
710         this.isField    = isField;
711         this.isDeclared = isDeclared;
712 
713         // Get the member's class.
714         int classIndex = constantSequenceMatcher.matchedConstantIndex(CLASS_INDEX);
715         clazz.constantPoolEntryAccept(classIndex, this);
716 
717         // Get the field's reference type, if applicable.
718         int typeClassIndex = constantSequenceMatcher.matchedConstantIndex(TYPE_CLASS_INDEX);
719         descriptor = typeClassIndex <= 0 ? defaultDescriptor :
720             ClassUtil.internalTypeFromClassName(clazz.getClassName(typeClassIndex));
721 
722         // Fill out the matched string constant.
723         int memberNameIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
724         clazz.constantPoolEntryAccept(memberNameIndex, this);
725     }
726 
727 
728     // Implementations for ConstantVisitor.
729 
730     /**
731      * Remembers the referenced class.
732      */
visitClassConstant(Clazz clazz, ClassConstant classConstant)733     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
734     {
735         if (DEBUG)
736         {
737             System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched class ["+classConstant.getName(clazz)+"]");
738         }
739 
740         // Remember the referenced class.
741         referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
742             null :
743             classConstant.referencedClass;
744     }
745 
746 
747     /**
748      * Fills out the link to the referenced class member.
749      */
visitStringConstant(Clazz clazz, StringConstant stringConstant)750     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
751     {
752         if (referencedClass != null)
753         {
754             String name = stringConstant.getString(clazz);
755 
756             if (DEBUG)
757             {
758                 System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched string ["+name+"]");
759             }
760 
761             // See if we can find the referenced class member locally, or
762             // somewhere in the hierarchy.
763             Member referencedMember = isDeclared ? isField ?
764                 (Member)referencedClass.findField(name, descriptor) :
765                 (Member)referencedClass.findMethod(name, descriptor) :
766                 (Member)memberFinder.findMember(clazz,
767                                                 referencedClass,
768                                                 name,
769                                                 descriptor,
770                                                 isField);
771             if (referencedMember != null)
772             {
773                 stringConstant.referencedMember = referencedMember;
774                 stringConstant.referencedClass  = isDeclared ?
775                     referencedClass :
776                     memberFinder.correspondingClass();
777             }
778         }
779     }
780 
781 
782     // Small utility methods.
783 
784     /**
785      * Prints out a note on the matched dynamic invocation, if necessary.
786      */
printDynamicInvocationNote(Clazz clazz, InstructionSequenceMatcher noteSequenceMatcher, boolean isField, boolean isDeclared, String defaultName, String defaultDescriptor)787     private void printDynamicInvocationNote(Clazz                      clazz,
788                                             InstructionSequenceMatcher noteSequenceMatcher,
789                                             boolean                    isField,
790                                             boolean                    isDeclared,
791                                             String                     defaultName,
792                                             String                     defaultDescriptor)
793     {
794         // Print out a note about the dynamic invocation.
795         if (notePrinter != null &&
796             notePrinter.accepts(clazz.getName()))
797         {
798             // Is the class member name in the list of exceptions?
799             StringMatcher noteExceptionMatcher = isField ?
800                 noteFieldExceptionMatcher :
801                 noteMethodExceptionMatcher;
802 
803             int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
804             String memberName = memberNameIndex <= 0 ? defaultName :
805                 clazz.getStringString(memberNameIndex);
806 
807             if (noteExceptionMatcher == null ||
808                 !noteExceptionMatcher.matches(memberName))
809             {
810                 // Compose the external member name and partial descriptor.
811                 String externalMemberDescription = memberName;
812 
813                 if (!isField)
814                 {
815                     externalMemberDescription += '(';
816                     for (int count = 0; count < 2; count++)
817                     {
818                         int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(
819                             PARAMETER0_CLASS_INDEX + count);
820                         if (memberArgumentIndex > 0)
821                         {
822                             if (count > 0)
823                             {
824                                 externalMemberDescription += ',';
825                             }
826                             String className = clazz.getClassName(memberArgumentIndex);
827                             externalMemberDescription += ClassUtil.isInternalArrayType(className) ?
828                                 ClassUtil.externalType(className) :
829                                 ClassUtil.externalClassName(className);
830                         }
831                     }
832                     externalMemberDescription += ')';
833                 }
834 
835                 // Print out the actual note.
836                 notePrinter.print(clazz.getName(),
837                                   "Note: " +
838                                   ClassUtil.externalClassName(clazz.getName()) +
839                                   " accesses a " +
840                                   (isDeclared ? "declared " : "") +
841                                   (isField    ? "field" :
842                                    memberName.equals(ClassConstants.METHOD_NAME_INIT) ?
843                                                 "constructor" : "method") +
844                                   " '" +
845                                   externalMemberDescription +
846                                   "' dynamically");
847 
848                 // Print out notes about potential candidates.
849                 ClassVisitor classVisitor;
850 
851                 if (isField)
852                 {
853                     classVisitor = defaultDescriptor == null ?
854                        new AllFieldVisitor(
855                        new MemberNameFilter(memberName, this)) :
856                        new AllFieldVisitor(
857                        new MemberNameFilter(memberName,
858                        new MemberDescriptorFilter(defaultDescriptor, this)));
859                 }
860                 else
861                 {
862                     // Compose the partial method descriptor.
863                     String methodDescriptor = "(";
864                     for (int count = 0; count < 2; count++)
865                     {
866                         int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(PARAMETER0_CLASS_INDEX + count);
867                         if (memberArgumentIndex > 0)
868                         {
869                             String className = clazz.getClassName(memberArgumentIndex);
870                             methodDescriptor += ClassUtil.isInternalArrayType(className) ?
871                                 className :
872                                 ClassUtil.internalTypeFromClassName(className);
873                         }
874                     }
875                     methodDescriptor += ")L***;";
876 
877                     classVisitor =
878                         new AllMethodVisitor(
879                         new MemberNameFilter(memberName,
880                         new MemberDescriptorFilter(methodDescriptor, this)));
881                 }
882 
883                 programClassPool.classesAcceptAlphabetically(classVisitor);
884                 libraryClassPool.classesAcceptAlphabetically(classVisitor);
885             }
886         }
887     }
888 
889 
890     // Implementations for MemberVisitor.
891 
visitProgramField(ProgramClass programClass, ProgramField programField)892     public void visitProgramField(ProgramClass programClass, ProgramField programField)
893     {
894         if (notePrinter.accepts(programClass.getName()))
895         {
896             System.out.println("      Maybe this is program field '" +
897                                ClassUtil.externalFullClassDescription(0, programClass.getName()) +
898                                " { " +
899                                ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) +
900                                "; }'");
901         }
902     }
903 
904 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)905     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
906     {
907         if (notePrinter.accepts(programClass.getName()))
908         {
909             System.out.println("      Maybe this is program method '" +
910                                ClassUtil.externalFullClassDescription(0, programClass.getName()) +
911                                " { " +
912                                ClassUtil.externalFullMethodDescription(programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
913                                "; }'");
914         }
915     }
916 
917 
visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)918     public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
919     {
920         if (notePrinter.accepts(libraryClass.getName()))
921         {
922             System.out.println("      Maybe this is library field '" +
923                                ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
924                                " { " +
925                                ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) +
926                                "; }'");
927         }
928     }
929 
930 
visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)931     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
932     {
933         if (notePrinter.accepts(libraryClass.getName()))
934         {
935             System.out.println("      Maybe this is library method '" +
936                                ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
937                                " { " +
938                                ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
939                                "; }'");
940         }
941     }
942 }