View Javadoc

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 }