in rsc/src/main/scala/rsc/classpath/javacp/Javacp.scala [25:243]
private def sinfos(
node: ClassNode,
index: Index,
access: Int,
scope: Scope): List[s.SymbolInformation] = {
val buf = ListBuffer.empty[s.SymbolInformation]
val decls = ListBuffer.empty[String]
def addInfo(
symbol: String,
kind: s.SymbolInformation.Kind,
displayName: String,
sig: s.Signature,
access: Int): s.SymbolInformation = {
val info = s.SymbolInformation(
symbol = symbol,
language = l.JAVA,
kind = kind,
properties = sproperties(access, node),
displayName = displayName,
signature = sig,
annotations = sannotations(access),
access = saccess(access, symbol, kind)
)
buf += info
info
}
if (isAnonymousClass(node)) return Nil
val classSymbol = ssym(node.name)
val classDisplayName = sdisplayName(node.name)
val classAccess = node.access | access
val hasOuterClassReference = node.fields.asScala.exists(isOuterClassReference)
val classKind =
if (classAccess.hasFlag(o.ACC_INTERFACE)) k.INTERFACE
else k.CLASS
val isJavaLangObject = node.name == "java/lang/Object"
val classSignature: ClassSignature =
if (isJavaLangObject) {
// java/lang/Object has no super class so node.superName == null.
// ClassSignature requires a non-null superName so we special-handle java/lang/Object
// when assigning classParents below.
ClassSignature.simple("impossible", Nil)
} else if (node.signature == null) {
ClassSignature.simple(node.superName, node.interfaces.asScala.toList)
} else {
JavaTypeSignature.parse(node.signature, new ClassSignatureVisitor)
}
val (classScope: Scope, classTypeParameters) =
classSignature.typeParameters match {
case Some(tp) => addTypeParameters(tp, classSymbol, scope)
case _ => scope -> Nil
}
classTypeParameters.foreach(buf += _)
val classParents =
if (isJavaLangObject) Nil
else classSignature.parents.map(_.toSemanticTpe(classScope))
node.fields.asScala
.filterNot(_.access.hasFlag(o.ACC_SYNTHETIC))
.foreach { field: FieldNode =>
if (isOuterClassReference(field)) {
// Drop the constructor argument that holds the reference to the outer class.
()
} else {
val fieldSymbol = Symbols.Global(classSymbol, d.Term(field.name))
val fieldDisplayName = field.name
val fieldSignature = JavaTypeSignature.parse(
if (field.signature == null) field.desc else field.signature,
new FieldSignatureVisitor
)
val fieldInfo = addInfo(
fieldSymbol,
k.FIELD,
fieldDisplayName,
s.ValueSignature(fieldSignature.toSemanticTpe(classScope)),
field.access
)
decls += fieldInfo.symbol
}
}
val methodSignatures = node.methods.asScala
.filterNot(_.access.hasFlag(o.ACC_SYNTHETIC))
.map { method: MethodNode =>
val signature = JavaTypeSignature.parse(
if (method.signature == null) method.desc else method.signature,
new MethodSignatureVisitor
)
MethodInfo(method, signature)
}
.filterNot(_.signature.params.nonEmpty)
// NOTE: we sort methods by whether they're static or not in order to compute same method symbols as metac.
// In scalac, static class members are separated from non-static members, which makes it impossible
// to recover the original mixed static/non-static member order in the classfile.
val byStaticAccess = methodSignatures.sortBy(_.node.access.hasFlag(o.ACC_STATIC))
methodSignatures.foreach {
case method: MethodInfo if method.node.name == "<clinit>" =>
()
case method: MethodInfo =>
val isConstructor = method.node.name == "<init>"
// FIXME: https://github.com/twitter/rsc/issues/229.
// This is quite incorrect, but quite convenient.
val methodDescriptor = d.Method(method.node.name, "()")
val methodSymbol = Symbols.Global(classSymbol, methodDescriptor)
val (methodScope, methodTypeParameters) = method.signature.typeParameters match {
case Some(tp: TypeParameters) => addTypeParameters(tp, methodSymbol, classScope)
case _ => classScope -> Nil
}
methodTypeParameters.foreach(buf += _)
val params =
if (isConstructor && hasOuterClassReference &&
// Guard against an empty parameter list, which seems to only happen
// in the JDK for java/util/regex/Pattern.class
method.signature.params.nonEmpty) {
// Drop the constructor argument that holds the reference to the outer class.
method.signature.params.tail
} else {
method.signature.params
}
val parameters: List[s.SymbolInformation] = params.zipWithIndex.map {
case (param: JavaTypeSignature, i) =>
val paramDisplayName = {
if (method.node.parameters == null) "param" + i
else method.node.parameters.get(i).name
}
val paramSymbol = Symbols.Global(methodSymbol, d.Parameter(paramDisplayName))
val isRepeatedType = method.node.access.hasFlag(o.ACC_VARARGS) && i == params.length - 1
val paramTpe =
if (isRepeatedType) {
param.toSemanticTpe(methodScope) match {
case s.TypeRef(s.NoType, "scala/Array#", targ :: Nil) =>
s.RepeatedType(targ)
case tpe =>
sys.error(s"expected $paramDisplayName to be a scala/Array#, found $tpe")
}
} else {
param.toSemanticTpe(methodScope)
}
addInfo(
paramSymbol,
k.PARAMETER,
paramDisplayName,
s.ValueSignature(paramTpe),
o.ACC_PUBLIC
)
}
val returnType = {
if (isConstructor) s.NoType
else method.signature.result.toSemanticTpe(methodScope)
}
val methodKind = if (isConstructor) k.CONSTRUCTOR else k.METHOD
val methodDisplayName = method.node.name
val methodSig = s.MethodSignature(
typeParameters = Some(s.Scope(methodTypeParameters.map(_.symbol))),
parameterLists = List(s.Scope(parameters.map(_.symbol))),
returnType = returnType
)
val methodInfo = addInfo(
methodSymbol,
methodKind,
methodDisplayName,
methodSig,
method.node.access
)
decls += methodInfo.symbol
}
// node.innerClasses includes all inner classes, both direct and those nested inside other inner classes.
val directInnerClasses = node.innerClasses.asScala.filter(_.outerName == node.name)
directInnerClasses.foreach { ic =>
val innerClassSymbol = ssym(ic.name)
decls += innerClassSymbol
val innerClassNode = {
val entry = index(ic.name + ".class").asInstanceOf[FileEntry]
val in = entry.openStream()
val node = new ClassNode()
try {
new ClassReader(in).accept(node, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES)
node
} finally {
in.close()
}
}
buf ++= sinfos(innerClassNode, index, ic.access, classScope)
}
val classSig = s.ClassSignature(
typeParameters = Some(s.Scope(classTypeParameters.map(_.symbol))),
parents = classParents,
self = s.NoType,
declarations = Some(s.Scope(decls))
)
addInfo(
classSymbol,
classKind,
classDisplayName,
classSig,
classAccess
)
buf.result()
}