1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.plugin.classanalysis
import org.objectweb.asm._
import com.yahoo.osgi.annotation.{ExportPackage, Version}
import collection.mutable
/**
* Picks up classes used in class files.
* @author tonytv
*/
private class AnalyzeClassVisitor extends ClassVisitor(Opcodes.ASM5) with AnnotationVisitorTrait with AttributeVisitorTrait {
private var name : String = null
protected val imports : ImportsSet = mutable.Set()
protected var exportPackageAnnotation: Option[ExportPackageAnnotation] = None
override def visitAttribute(attribute: Attribute): Unit = super.visitAttribute(attribute)
override def visitMethod(access: Int, name: String, desc: String, signature: String,
exceptions: Array[String]): MethodVisitor = {
imports ++= (Type.getReturnType(desc) +: Type.getArgumentTypes(desc)).flatMap(getClassName)
imports ++= Option(exceptions) getOrElse(Array()) flatMap internalNameToClassName
AnalyzeSignatureVisitor.analyzeMethod(signature, this)
new AnalyzeMethodVisitor(this)
}
override def visitField(access: Int, name: String, desc: String, signature: String, value: AnyRef): FieldVisitor = {
imports ++= getClassName(Type.getType(desc)).toList
AnalyzeSignatureVisitor.analyzeField(signature, this)
new FieldVisitor(Opcodes.ASM5) with SubVisitorTrait with AttributeVisitorTrait with AnnotationVisitorTrait {
val analyzeClassVisitor = AnalyzeClassVisitor.this
override def visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor = super.visitAnnotation(desc, visible)
override def visitAttribute(attribute: Attribute): Unit = super.visitAttribute(attribute)
override def visitEnd(): Unit = super.visitEnd()
}
}
override def visit(version: Int, access: Int, name: String, signature: String, superName: String, interfaces: Array[String]) {
this.name = internalNameToClassName(name).get
imports ++= (superName +: interfaces) flatMap internalNameToClassName
AnalyzeSignatureVisitor.analyzeClass(signature, this)
}
override def visitInnerClass(name: String, outerName: String, innerName: String, access: Int) {}
override def visitOuterClass(owner: String, name: String, desc: String) {}
override def visitSource(source: String, debug: String) {}
override def visitEnd() {}
def addImports(imports: TraversableOnce[String]) {
this.imports ++= imports
}
override def visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor = {
if (Type.getType(desc).getClassName == classOf[ExportPackage].getName) {
visitExportPackage()
} else {
super.visitAnnotation(desc, visible)
}
}
def visitExportPackage(): AnnotationVisitor = {
def defaultVersionValue[T](name: String) = classOf[Version].getMethod(name).getDefaultValue().asInstanceOf[T]
new AnnotationVisitor(Opcodes.ASM5) {
var major: Int = defaultVersionValue("major")
var minor: Int = defaultVersionValue("minor")
var micro: Int = defaultVersionValue("micro")
var qualifier: String = defaultVersionValue("qualifier")
override def visit(name: String, value: AnyRef) {
def valueAsInt = value.asInstanceOf[Int]
name match {
case "major" => major = valueAsInt
case "minor" => minor = valueAsInt
case "micro" => micro = valueAsInt
case "qualifier" => qualifier = value.asInstanceOf[String]
}
}
override def visitEnd() {
exportPackageAnnotation = Some(ExportPackageAnnotation(major, minor, micro, qualifier))
}
override def visitEnum(name: String, desc: String, value: String) {}
override def visitArray(name: String): AnnotationVisitor = this
override def visitAnnotation(name: String, desc: String): AnnotationVisitor = this
}
}
def result = {
assert(!imports.contains("int"))
new ClassFileMetaData(name, imports.toSet, exportPackageAnnotation)
}
}
|