1 package org.apache.maven.shared.dependency.analyzer.asm;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.HashSet;
23 import java.util.Set;
24
25 import org.objectweb.asm.AnnotationVisitor;
26 import org.objectweb.asm.Attribute;
27 import org.objectweb.asm.ClassVisitor;
28 import org.objectweb.asm.FieldVisitor;
29 import org.objectweb.asm.Label;
30 import org.objectweb.asm.MethodVisitor;
31 import org.objectweb.asm.Type;
32 import org.objectweb.asm.signature.SignatureReader;
33 import org.objectweb.asm.signature.SignatureVisitor;
34
35 /**
36 * Computes the set of classes referenced by visited code.
37 * Inspired by <code>org.objectweb.asm.depend.DependencyVisitor</code> in the ASM dependencies example.
38 *
39 * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
40 * @version $Id: DependencyVisitor.java 1174427 2011-09-22 22:25:17Z hboutemy $
41 * @see #getClasses()
42 */
43 public class DependencyVisitor
44 implements AnnotationVisitor, SignatureVisitor, ClassVisitor, FieldVisitor, MethodVisitor
45 {
46 // fields -----------------------------------------------------------------
47
48 private final Set<String> classes;
49
50 // constructors -----------------------------------------------------------
51
52 public DependencyVisitor()
53 {
54 classes = new HashSet<String>();
55 }
56
57 // ClassVisitor methods ---------------------------------------------------
58
59 /*
60 * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String,
61 * java.lang.String[])
62 */
63 public void visit( final int version, final int access, final String name, final String signature,
64 final String superName, final String[] interfaces )
65 {
66 if ( signature == null )
67 {
68 addName( superName );
69 addNames( interfaces );
70 }
71 else
72 {
73 addSignature( signature );
74 }
75 }
76
77 /*
78 * @see org.objectweb.asm.ClassVisitor#visitSource(java.lang.String, java.lang.String)
79 */
80 public void visitSource( final String source, final String debug )
81 {
82 // no-op
83 }
84
85 /*
86 * @see org.objectweb.asm.ClassVisitor#visitOuterClass(java.lang.String, java.lang.String, java.lang.String)
87 */
88 public void visitOuterClass( final String owner, final String name, final String desc )
89 {
90 // addName(owner);
91 // addMethodDesc(desc);
92 }
93
94 /*
95 * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
96 */
97 public AnnotationVisitor visitAnnotation( final String desc, final boolean visible )
98 {
99 addDesc( desc );
100
101 return this;
102 }
103
104 /*
105 * @see org.objectweb.asm.ClassVisitor#visitAttribute(org.objectweb.asm.Attribute)
106 */
107 public void visitAttribute( final Attribute attr )
108 {
109 // no-op
110 }
111
112 /*
113 * @see org.objectweb.asm.ClassVisitor#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)
114 */
115 public void visitInnerClass( final String name, final String outerName, final String innerName, final int access )
116 {
117 // addName( outerName);
118 // addName( innerName);
119 }
120
121 /*
122 * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String,
123 * java.lang.Object)
124 */
125 public FieldVisitor visitField( final int access, final String name, final String desc, final String signature,
126 final Object value )
127 {
128 if ( signature == null )
129 {
130 addDesc( desc );
131 }
132 else
133 {
134 addTypeSignature( signature );
135 }
136
137 if ( value instanceof Type )
138 {
139 addType( (Type) value );
140 }
141
142 return this;
143 }
144
145 /*
146 * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String,
147 * java.lang.String[])
148 */
149 public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature,
150 final String[] exceptions )
151 {
152 if ( signature == null )
153 {
154 addMethodDesc( desc );
155 }
156 else
157 {
158 addSignature( signature );
159 }
160
161 addNames( exceptions );
162
163 return this;
164 }
165
166 // MethodVisitor methods --------------------------------------------------
167
168 /*
169 * @see org.objectweb.asm.MethodVisitor#visitAnnotationDefault()
170 */
171 public AnnotationVisitor visitAnnotationDefault()
172 {
173 return this;
174 }
175
176 /*
177 * @see org.objectweb.asm.MethodVisitor#visitParameterAnnotation(int, java.lang.String, boolean)
178 */
179 public AnnotationVisitor visitParameterAnnotation( final int parameter, final String desc, final boolean visible )
180 {
181 addDesc( desc );
182
183 return this;
184 }
185
186 /*
187 * @see org.objectweb.asm.MethodVisitor#visitCode()
188 */
189 public void visitCode()
190 {
191 // no-op
192 }
193
194 /*
195 * @see org.objectweb.asm.MethodVisitor#visitFrame(int, int, java.lang.Object[], int, java.lang.Object[])
196 */
197 public void visitFrame( final int type, final int nLocal, final Object[] local, final int nStack,
198 final Object[] stack )
199 {
200 // no-op
201 }
202
203 /*
204 * @see org.objectweb.asm.MethodVisitor#visitInsn(int)
205 */
206 public void visitInsn( final int opcode )
207 {
208 // no-op
209 }
210
211 /*
212 * @see org.objectweb.asm.MethodVisitor#visitIntInsn(int, int)
213 */
214 public void visitIntInsn( final int opcode, final int operand )
215 {
216 // no-op
217 }
218
219 /*
220 * @see org.objectweb.asm.MethodVisitor#visitVarInsn(int, int)
221 */
222 public void visitVarInsn( final int opcode, final int var )
223 {
224 // no-op
225 }
226
227 /*
228 * @see org.objectweb.asm.MethodVisitor#visitTypeInsn(int, java.lang.String)
229 */
230 public void visitTypeInsn( final int opcode, final String desc )
231 {
232 if ( desc.charAt( 0 ) == '[' )
233 {
234 addDesc( desc );
235 }
236 else
237 {
238 addName( desc );
239 }
240 }
241
242 /*
243 * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, java.lang.String, java.lang.String, java.lang.String)
244 */
245 public void visitFieldInsn( final int opcode, final String owner, final String name, final String desc )
246 {
247 addName( owner );
248 /*
249 * NOTE: Merely accessing a field does not impose a direct dependency on its type. For example, the code line
250 * <code>java.lang.Object var = bean.field;</code> does not directly depend on the type of the field. A direct
251 * dependency is only introduced when the code explicitly references the field's type by means of a variable
252 * declaration or a type check/cast. Those cases are handled by other visitor callbacks.
253 */
254 }
255
256 /*
257 * @see org.objectweb.asm.MethodVisitor#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)
258 */
259 public void visitMethodInsn( final int opcode, final String owner, final String name, final String desc )
260 {
261 addName( owner );
262 /*
263 * NOTE: Merely invoking a method does not impose a direct dependency on its return type nor its parameter
264 * types. For example, the code line <code>bean.method(null);</code> only depends on the owner type of the
265 * method. A direct dependency is only introduced when the code explicitly references the method's types by
266 * means of a variable declaration or a type check/cast. Those cases are handled by other visitor callbacks.
267 */
268 }
269
270 /*
271 * @see org.objectweb.asm.MethodVisitor#visitJumpInsn(int, org.objectweb.asm.Label)
272 */
273 public void visitJumpInsn( final int opcode, final Label label )
274 {
275 // no-op
276 }
277
278 /*
279 * @see org.objectweb.asm.MethodVisitor#visitLabel(org.objectweb.asm.Label)
280 */
281 public void visitLabel( final Label label )
282 {
283 // no-op
284 }
285
286 /*
287 * @see org.objectweb.asm.MethodVisitor#visitLdcInsn(java.lang.Object)
288 */
289 public void visitLdcInsn( final Object cst )
290 {
291 if ( cst instanceof Type )
292 {
293 addType( (Type) cst );
294 }
295 }
296
297 /*
298 * @see org.objectweb.asm.MethodVisitor#visitIincInsn(int, int)
299 */
300 public void visitIincInsn( final int var, final int increment )
301 {
302 // no-op
303 }
304
305 /*
306 * @see org.objectweb.asm.MethodVisitor#visitTableSwitchInsn(int, int, org.objectweb.asm.Label,
307 * org.objectweb.asm.Label[])
308 */
309 public void visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label[] labels )
310 {
311 // no-op
312 }
313
314 /*
315 * @see org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn(org.objectweb.asm.Label, int[],
316 * org.objectweb.asm.Label[])
317 */
318 public void visitLookupSwitchInsn( final Label dflt, final int[] keys, final Label[] labels )
319 {
320 // no-op
321 }
322
323 /*
324 * @see org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn(java.lang.String, int)
325 */
326 public void visitMultiANewArrayInsn( final String desc, final int dims )
327 {
328 addDesc( desc );
329 }
330
331 /*
332 * @see org.objectweb.asm.MethodVisitor#visitTryCatchBlock(org.objectweb.asm.Label, org.objectweb.asm.Label,
333 * org.objectweb.asm.Label, java.lang.String)
334 */
335 public void visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type )
336 {
337 addName( type );
338 }
339
340 /*
341 * @see org.objectweb.asm.MethodVisitor#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String,
342 * org.objectweb.asm.Label, org.objectweb.asm.Label, int)
343 */
344 public void visitLocalVariable( final String name, final String desc, final String signature, final Label start,
345 final Label end, final int index )
346 {
347 if ( signature == null )
348 {
349 addDesc( desc );
350 }
351 else
352 {
353 addTypeSignature( signature );
354 }
355 }
356
357 /*
358 * @see org.objectweb.asm.MethodVisitor#visitLineNumber(int, org.objectweb.asm.Label)
359 */
360 public void visitLineNumber( final int line, final Label start )
361 {
362 // no-op
363 }
364
365 /*
366 * @see org.objectweb.asm.MethodVisitor#visitMaxs(int, int)
367 */
368 public void visitMaxs( final int maxStack, final int maxLocals )
369 {
370 // no-op
371 }
372
373 // AnnotationVisitor methods ----------------------------------------------
374
375 /*
376 * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
377 */
378 public void visit( final String name, final Object value )
379 {
380 if ( value instanceof Type )
381 {
382 addType( (Type) value );
383 }
384 }
385
386 /*
387 * @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)
388 */
389 public void visitEnum( final String name, final String desc, final String value )
390 {
391 addDesc( desc );
392 }
393
394 /*
395 * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
396 */
397 public AnnotationVisitor visitAnnotation( final String name, final String desc )
398 {
399 addDesc( desc );
400
401 return this;
402 }
403
404 /*
405 * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
406 */
407 public AnnotationVisitor visitArray( final String name )
408 {
409 return this;
410 }
411
412 /*
413 * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
414 */
415 public void visitEnd()
416 {
417 // no-op
418 }
419
420 // SignatureVisitor methods -----------------------------------------------
421
422 /*
423 * @see org.objectweb.asm.signature.SignatureVisitor#visitFormalTypeParameter(java.lang.String)
424 */
425 public void visitFormalTypeParameter( final String name )
426 {
427 // no-op
428 }
429
430 /*
431 * @see org.objectweb.asm.signature.SignatureVisitor#visitClassBound()
432 */
433 public SignatureVisitor visitClassBound()
434 {
435 return this;
436 }
437
438 /*
439 * @see org.objectweb.asm.signature.SignatureVisitor#visitInterfaceBound()
440 */
441 public SignatureVisitor visitInterfaceBound()
442 {
443 return this;
444 }
445
446 /*
447 * @see org.objectweb.asm.signature.SignatureVisitor#visitSuperclass()
448 */
449 public SignatureVisitor visitSuperclass()
450 {
451 return this;
452 }
453
454 /*
455 * @see org.objectweb.asm.signature.SignatureVisitor#visitInterface()
456 */
457 public SignatureVisitor visitInterface()
458 {
459 return this;
460 }
461
462 /*
463 * @see org.objectweb.asm.signature.SignatureVisitor#visitParameterType()
464 */
465 public SignatureVisitor visitParameterType()
466 {
467 return this;
468 }
469
470 /*
471 * @see org.objectweb.asm.signature.SignatureVisitor#visitReturnType()
472 */
473 public SignatureVisitor visitReturnType()
474 {
475 return this;
476 }
477
478 /*
479 * @see org.objectweb.asm.signature.SignatureVisitor#visitExceptionType()
480 */
481 public SignatureVisitor visitExceptionType()
482 {
483 return this;
484 }
485
486 /*
487 * @see org.objectweb.asm.signature.SignatureVisitor#visitBaseType(char)
488 */
489 public void visitBaseType( final char descriptor )
490 {
491 // no-op
492 }
493
494 /*
495 * @see org.objectweb.asm.signature.SignatureVisitor#visitTypeVariable(java.lang.String)
496 */
497 public void visitTypeVariable( final String name )
498 {
499 // TODO: verify
500 }
501
502 /*
503 * @see org.objectweb.asm.signature.SignatureVisitor#visitArrayType()
504 */
505 public SignatureVisitor visitArrayType()
506 {
507 return this;
508 }
509
510 /*
511 * @see org.objectweb.asm.signature.SignatureVisitor#visitClassType(java.lang.String)
512 */
513 public void visitClassType( final String name )
514 {
515 addName( name );
516 }
517
518 /*
519 * @see org.objectweb.asm.signature.SignatureVisitor#visitInnerClassType(java.lang.String)
520 */
521 public void visitInnerClassType( final String name )
522 {
523 addName( name );
524 }
525
526 /*
527 * @see org.objectweb.asm.signature.SignatureVisitor#visitTypeArgument()
528 */
529 public void visitTypeArgument()
530 {
531 // no-op
532 }
533
534 /*
535 * @see org.objectweb.asm.signature.SignatureVisitor#visitTypeArgument(char)
536 */
537 public SignatureVisitor visitTypeArgument( final char wildcard )
538 {
539 return this;
540 }
541
542 // public methods ---------------------------------------------------------
543
544 public Set<String> getClasses()
545 {
546 return classes;
547 }
548
549 // private methods --------------------------------------------------------
550
551 private void addName( String name )
552 {
553 if ( name == null )
554 {
555 return;
556 }
557
558 // decode arrays
559 if ( name.startsWith( "[L" ) && name.endsWith( ";" ) )
560 {
561 name = name.substring( 2, name.length() - 1 );
562 }
563
564 // decode internal representation
565 name = name.replace( '/', '.' );
566
567 classes.add( name );
568 }
569
570 private void addNames( final String[] names )
571 {
572 if ( names == null )
573 {
574 return;
575 }
576
577 for ( String name : names )
578 {
579 addName( name );
580 }
581 }
582
583 private void addDesc( final String desc )
584 {
585 addType( Type.getType( desc ) );
586 }
587
588 private void addMethodDesc( final String desc )
589 {
590 addType( Type.getReturnType( desc ) );
591
592 Type[] types = Type.getArgumentTypes( desc );
593
594 for ( Type type : types )
595 {
596 addType( type );
597 }
598 }
599
600 private void addType( final Type t )
601 {
602 switch ( t.getSort() )
603 {
604 case Type.ARRAY:
605 addType( t.getElementType() );
606 break;
607
608 case Type.OBJECT:
609 addName( t.getClassName().replace( '.', '/' ) );
610 break;
611 }
612 }
613
614 private void addSignature( final String signature )
615 {
616 if ( signature != null )
617 {
618 new SignatureReader( signature ).accept( this );
619 }
620 }
621
622 private void addTypeSignature( final String signature )
623 {
624 if ( signature != null )
625 {
626 new SignatureReader( signature ).acceptType( this );
627 }
628 }
629 }