529 lines
21 KiB
Scala
529 lines
21 KiB
Scala
package scala.reflect
|
|
package runtime
|
|
|
|
import java.lang.{ Class => jClass, Package => jPackage, ClassLoader => JClassLoader }
|
|
import java.io.IOException
|
|
import java.lang.reflect.{
|
|
Method => jMethod,
|
|
Constructor => jConstructor,
|
|
Modifier => jModifier,
|
|
Field => jField,
|
|
Member => jMember,
|
|
Type => jType,
|
|
TypeVariable => jTypeVariable,
|
|
GenericDeclaration,
|
|
GenericArrayType,
|
|
ParameterizedType,
|
|
WildcardType,
|
|
AnnotatedElement
|
|
}
|
|
import internal.MissingRequirementError
|
|
import internal.pickling.ByteCodecs
|
|
import internal.ClassfileConstants._
|
|
import internal.pickling.UnPickler
|
|
import collection.mutable.{ HashMap, ListBuffer }
|
|
import internal.Flags._
|
|
import scala.tools.nsc.util.ScalaClassLoader
|
|
import scala.tools.nsc.util.ScalaClassLoader._
|
|
|
|
trait JavaToScala extends ConversionUtil { self: SymbolTable =>
|
|
|
|
import definitions._
|
|
|
|
private object unpickler extends UnPickler {
|
|
val global: JavaToScala.this.type = self
|
|
}
|
|
|
|
protected def defaultReflectiveClassLoader(): JClassLoader =
|
|
Thread.currentThread.getContextClassLoader
|
|
|
|
/** Paul: It seems the default class loader does not pick up root classes, whereas the system classloader does.
|
|
* Can you check with your newly acquired classloader fu whether this implementation makes sense?
|
|
*/
|
|
def javaClass(path: String): jClass[_] =
|
|
javaClass(path, defaultReflectiveClassLoader())
|
|
def javaClass(path: String, classLoader: JClassLoader): jClass[_] =
|
|
classLoader.loadClass(path)
|
|
|
|
/** Does `path` correspond to a Java class with that fully qualified name? */
|
|
def isJavaClass(path: String): Boolean =
|
|
try {
|
|
javaClass(path)
|
|
true
|
|
} catch {
|
|
case (_: ClassNotFoundException) | (_: NoClassDefFoundError) =>
|
|
false
|
|
}
|
|
|
|
/**
|
|
* Generate types for top-level Scala root class and root companion object
|
|
* from the pickled information stored in a corresponding Java class
|
|
* @param clazz The top-level Scala class for which info is unpickled
|
|
* @param module The top-level Scala companion object for which info is unpickled
|
|
* @param jclazz The Java class which contains the unpickled information in a
|
|
* ScalaSignature or ScalaLongSignature annotation.
|
|
*/
|
|
def unpickleClass(clazz: Symbol, module: Symbol, jclazz: jClass[_]): Unit = {
|
|
def markAbsent(tpe: Type) = setAllInfos(clazz, module, tpe)
|
|
def handleError(ex: Exception) = {
|
|
markAbsent(ErrorType)
|
|
if (settings.debug.value) ex.printStackTrace()
|
|
val msg = ex.getMessage()
|
|
MissingRequirementError.signal(
|
|
(if (msg eq null) "reflection error while loading " + clazz.name
|
|
else "error while loading " + clazz.name) + ", " + msg)
|
|
}
|
|
try {
|
|
markAbsent(NoType)
|
|
val ssig = jclazz.getAnnotation(classOf[scala.reflect.ScalaSignature])
|
|
if (ssig != null) {
|
|
info("unpickling Scala "+clazz + " and " + module+ ", owner = " + clazz.owner)
|
|
val bytes = ssig.bytes.getBytes
|
|
val len = ByteCodecs.decode(bytes)
|
|
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
|
|
} else {
|
|
val slsig = jclazz.getAnnotation(classOf[scala.reflect.ScalaLongSignature])
|
|
if (slsig != null) {
|
|
info("unpickling Scala "+clazz + " and " + module + " with long Scala signature")
|
|
val byteSegments = slsig.bytes map (_.getBytes)
|
|
val lens = byteSegments map ByteCodecs.decode
|
|
val bytes = Array.ofDim[Byte](lens.sum)
|
|
var len = 0
|
|
for ((bs, l) <- byteSegments zip lens) {
|
|
bs.copyToArray(bytes, len, l)
|
|
len += l
|
|
}
|
|
unpickler.unpickle(bytes, 0, clazz, module, jclazz.getName)
|
|
} else { // class does not have a Scala signature; it's a Java class
|
|
info("translating reflection info for Java " + jclazz) //debug
|
|
initClassModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
|
|
}
|
|
}
|
|
} catch {
|
|
case ex: MissingRequirementError =>
|
|
handleError(ex)
|
|
case ex: IOException =>
|
|
handleError(ex)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A fresh Scala type parameter that corresponds to a Java type variable.
|
|
* The association between Scala type parameter and Java type variable is entered in the cache.
|
|
* @param jtvar The Java type variable
|
|
*/
|
|
private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): Symbol = {
|
|
val tparam = sOwner(jtvar).newTypeParameter(NoPosition, newTypeName(jtvar.getName))
|
|
.setInfo(new TypeParamCompleter(jtvar))
|
|
tparamCache enter (jtvar, tparam)
|
|
tparam
|
|
}
|
|
|
|
/**
|
|
* A completer that fills in the type of a Scala type parameter from the bounds of a Java type variable.
|
|
* @param jtvar The Java type variable
|
|
*/
|
|
private class TypeParamCompleter(jtvar: jTypeVariable[_ <: GenericDeclaration]) extends LazyType {
|
|
override def load(sym: Symbol) = complete(sym)
|
|
override def complete(sym: Symbol) = {
|
|
sym setInfo TypeBounds.upper(glb(jtvar.getBounds.toList map typeToScala map objToAny))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copy all annotations of Java annotated element `jann` over to Scala symbol `sym`.
|
|
* Pre: `sym` is already initialized with a concrete type.
|
|
* Note: If `sym` is a method or constructor, its parameter annotations are copied as well.
|
|
*/
|
|
private def copyAnnotations(sym: Symbol, jann: AnnotatedElement) {
|
|
// to do: implement
|
|
}
|
|
|
|
/**
|
|
* A completer that fills in the types of a Scala class and its companion object
|
|
* by copying corresponding type info from a Java class. This completer is used
|
|
* to reflect classes in Scala that do not have a Scala pickle info, be it
|
|
* because they are local classes or have been compiled from Java sources.
|
|
* @param clazz The Scala class for which info is copied
|
|
* @param module The Scala companion object for which info is copied
|
|
* @param jclazz The Java class
|
|
*/
|
|
private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType {
|
|
override def load(sym: Symbol) = {
|
|
debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug
|
|
assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym)
|
|
val flags = toScalaFlags(jclazz.getModifiers, isClass = true)
|
|
clazz setFlag (flags | JAVA)
|
|
if (module != NoSymbol) {
|
|
module setFlag (flags & PRIVATE | JAVA)
|
|
module.moduleClass setFlag (flags & PRIVATE | JAVA)
|
|
}
|
|
|
|
copyAnnotations(clazz, jclazz)
|
|
// to do: annotations to set also for module?
|
|
|
|
clazz setInfo new LazyPolyType(jclazz.getTypeParameters.toList map createTypeParameter)
|
|
if (module != NoSymbol) {
|
|
module setInfo module.moduleClass.tpe
|
|
module.moduleClass setInfo new LazyPolyType(List())
|
|
}
|
|
}
|
|
|
|
override def complete(sym: Symbol): Unit = {
|
|
load(sym)
|
|
completeRest()
|
|
}
|
|
def completeRest(): Unit = {
|
|
val tparams = clazz.rawInfo.typeParams
|
|
|
|
val parents = try {
|
|
parentsLevel += 1
|
|
val jsuperclazz = jclazz.getGenericSuperclass
|
|
val superclazz = if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz)
|
|
superclazz :: (jclazz.getGenericInterfaces.toList map typeToScala)
|
|
} finally {
|
|
parentsLevel -= 1
|
|
}
|
|
clazz setInfo polyType(tparams, new ClassInfoType(parents, newScope, clazz))
|
|
if (module != NoSymbol) {
|
|
module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass)
|
|
}
|
|
|
|
def enter(sym: Symbol, mods: Int) =
|
|
(if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym
|
|
|
|
for (jinner <- jclazz.getDeclaredClasses) {
|
|
enter(jclassAsScala(jinner, clazz), jinner.getModifiers)
|
|
}
|
|
|
|
pendingLoadActions = { () =>
|
|
|
|
for (jfield <- jclazz.getDeclaredFields)
|
|
enter(jfieldAsScala(jfield), jfield.getModifiers)
|
|
|
|
for (jmeth <- jclazz.getDeclaredMethods)
|
|
enter(jmethodAsScala(jmeth), jmeth.getModifiers)
|
|
|
|
for (jconstr <- jclazz.getConstructors)
|
|
enter(jconstrAsScala(jconstr), jconstr.getModifiers)
|
|
|
|
} :: pendingLoadActions
|
|
|
|
if (parentsLevel == 0) {
|
|
while (!pendingLoadActions.isEmpty) {
|
|
val item = pendingLoadActions.head
|
|
pendingLoadActions = pendingLoadActions.tail
|
|
item()
|
|
}
|
|
}
|
|
}
|
|
class LazyPolyType(override val typeParams: List[Symbol]) extends LazyType {
|
|
override def complete(sym: Symbol) {
|
|
completeRest()
|
|
}
|
|
}
|
|
}
|
|
|
|
/** used to avoid cyclies */
|
|
var parentsLevel = 0
|
|
var pendingLoadActions: List[() => Unit] = Nil
|
|
|
|
/**
|
|
* If Java modifiers `mods` contain STATIC, return the module class
|
|
* of the companion module of `clazz`, otherwise the class `clazz` itself.
|
|
*/
|
|
private def followStatic(clazz: Symbol, mods: Int) =
|
|
if (jModifier.isStatic(mods)) clazz.companionModule.moduleClass else clazz
|
|
|
|
/**
|
|
* The Scala owner of the Scala class corresponding to the Java class `jclazz`
|
|
*/
|
|
private def sOwner(jclazz: jClass[_]): Symbol = {
|
|
if (jclazz.isMemberClass)
|
|
followStatic(classToScala(jclazz.getEnclosingClass), jclazz.getModifiers)
|
|
else if (jclazz.isLocalClass)
|
|
methodToScala(jclazz.getEnclosingMethod) orElse constrToScala(jclazz.getEnclosingConstructor)
|
|
else if (jclazz.isPrimitive || jclazz.isArray)
|
|
ScalaPackageClass
|
|
else if (jclazz.getPackage != null)
|
|
packageToScala(jclazz.getPackage)
|
|
else
|
|
EmptyPackageClass
|
|
}
|
|
|
|
/**
|
|
* The Scala owner of the Scala symbol corresponding to the Java member `jmember`
|
|
*/
|
|
private def sOwner(jmember: jMember): Symbol = {
|
|
followStatic(classToScala(jmember.getDeclaringClass), jmember.getModifiers)
|
|
}
|
|
|
|
/**
|
|
* The Scala owner of the Scala type parameter corresponding to the Java type variable `jtvar`
|
|
*/
|
|
private def sOwner(jtvar: jTypeVariable[_ <: GenericDeclaration]): Symbol =
|
|
genericDeclarationToScala(jtvar.getGenericDeclaration)
|
|
|
|
/**
|
|
* Returns `true` if Scala name `name` equals Java name `jstr`, possibly after
|
|
* make-not-private expansion.
|
|
*/
|
|
private def approximateMatch(sym: Symbol, jstr: String): Boolean =
|
|
(sym.name.toString == jstr) ||
|
|
sym.isPrivate && nme.expandedName(sym.name, sym.owner).toString == jstr
|
|
|
|
/**
|
|
* Find declarations or definition in class `clazz` that maps to a Java
|
|
* entity with name `jname`. Because of name-mangling, this is more difficult
|
|
* than a simple name-based lookup via `decl`. If `decl` fails, members
|
|
* that start with the given name are searched instead.
|
|
*/
|
|
private def lookup(clazz: Symbol, jname: String): Symbol =
|
|
clazz.info.decl(newTermName(jname)) orElse {
|
|
(clazz.info.decls.iterator filter (approximateMatch(_, jname))).toList match {
|
|
case List() => NoSymbol
|
|
case List(sym) => sym
|
|
case alts => clazz.newOverloaded(alts.head.tpe.prefix, alts)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Scala method corresponding to given Java method.
|
|
* @param jmeth The Java method
|
|
* @return A Scala method object that corresponds to `jmeth`.
|
|
*/
|
|
def methodToScala(jmeth: jMethod): Symbol = methodCache.toScala(jmeth) {
|
|
val owner = followStatic(classToScala(jmeth.getDeclaringClass), jmeth.getModifiers)
|
|
lookup(owner, jmeth.getName) suchThat (erasesTo(_, jmeth)) orElse jmethodAsScala(jmeth)
|
|
}
|
|
|
|
/**
|
|
* The Scala constructor corresponding to given Java constructor.
|
|
* @param jconstr The Java constructor
|
|
* @return A Scala method object that corresponds to `jconstr`.
|
|
*/
|
|
def constrToScala(jconstr: jConstructor[_]): Symbol = constructorCache.toScala(jconstr) {
|
|
val owner = followStatic(classToScala(jconstr.getDeclaringClass), jconstr.getModifiers)
|
|
lookup(owner, "<init>") suchThat (erasesTo(_, jconstr)) orElse jconstrAsScala(jconstr)
|
|
}
|
|
|
|
/**
|
|
* The Scala package corresponding to given Java package
|
|
*/
|
|
def packageToScala(jpkg: jPackage): Symbol = packageCache.toScala(jpkg) {
|
|
makeScalaPackage(jpkg.getName)
|
|
}
|
|
|
|
/**
|
|
* The Scala package with given fully qualified name.
|
|
*/
|
|
def packageNameToScala(fullname: String): Symbol = {
|
|
val jpkg = jPackage.getPackage(fullname)
|
|
if (jpkg != null) packageToScala(jpkg) else makeScalaPackage(fullname)
|
|
}
|
|
|
|
/**
|
|
* The Scala package with given fully qualified name. Unlike `packageNameToScala`,
|
|
* this one bypasses the cache.
|
|
*/
|
|
def makeScalaPackage(fullname: String): Symbol = {
|
|
val split = fullname lastIndexOf '.'
|
|
val owner = if (split > 0) packageNameToScala(fullname take split) else RootClass
|
|
assert(owner.isModuleClass, owner+" when making "+fullname)
|
|
val name = newTermName(fullname drop (split + 1))
|
|
var pkg = owner.info decl name
|
|
if (pkg == NoSymbol) {
|
|
pkg = owner.newPackage(NoPosition, name)
|
|
pkg.moduleClass setInfo new LazyPackageType
|
|
pkg setInfo pkg.moduleClass.tpe
|
|
owner.info.decls enter pkg
|
|
info("made Scala "+pkg)
|
|
} else if (!pkg.isPackage)
|
|
throw new ReflectError(pkg+" is not a package")
|
|
pkg.moduleClass
|
|
}
|
|
|
|
/**
|
|
* The Scala class that corresponds to a given Java class.
|
|
* @param jclazz The Java class
|
|
* @return A Scala class symbol that reflects all elements of the Java class,
|
|
* in the form they appear in the Scala pickling info, or, if that is
|
|
* not available, wrapped from the Java reflection info.
|
|
*/
|
|
def classToScala(jclazz: jClass[_]): Symbol = classCache.toScala(jclazz) {
|
|
if (jclazz.isMemberClass && !nme.isImplClassName(jclazz.getName)) {
|
|
val sym = sOwner(jclazz).info.decl(newTypeName(jclazz.getSimpleName))
|
|
assert(sym.isType, sym+"/"+jclazz+"/"+sOwner(jclazz)+"/"+jclazz.getSimpleName)
|
|
sym.asInstanceOf[ClassSymbol]
|
|
} else if (jclazz.isLocalClass || invalidClassName(jclazz.getName)) {
|
|
// local classes and implementation classes not preserved by unpickling - treat as Java
|
|
jclassAsScala(jclazz)
|
|
} else if (jclazz.isArray) {
|
|
ArrayClass
|
|
} else jclazz match {
|
|
case java.lang.Void.TYPE => UnitClass
|
|
case java.lang.Byte.TYPE => ByteClass
|
|
case java.lang.Character.TYPE => CharClass
|
|
case java.lang.Short.TYPE => ShortClass
|
|
case java.lang.Integer.TYPE => IntClass
|
|
case java.lang.Long.TYPE => LongClass
|
|
case java.lang.Float.TYPE => FloatClass
|
|
case java.lang.Double.TYPE => DoubleClass
|
|
case java.lang.Boolean.TYPE => BooleanClass
|
|
case _ =>
|
|
// jclazz is top-level - get signature
|
|
sOwner(jclazz).info decl newTypeName(jclazz.getSimpleName)
|
|
// val (clazz, module) = createClassModule(
|
|
// sOwner(jclazz), newTypeName(jclazz.getSimpleName), new TopClassCompleter(_, _))
|
|
// classCache enter (jclazz, clazz)
|
|
// clazz
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Scala type parameter that corresponds to a given Java type parameter.
|
|
* @param jparam The Java type parameter
|
|
* @return A Scala type parameter symbol that has the same owner and name as the Java type parameter
|
|
*/
|
|
def tparamToScala(jparam: jTypeVariable[_ <: GenericDeclaration]): Symbol = tparamCache.toScala(jparam) {
|
|
val owner = genericDeclarationToScala(jparam.getGenericDeclaration)
|
|
owner.info match {
|
|
case PolyType(tparams, _) => tparams.find(_.name.toString == jparam.getName).get
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Scala symbol that corresponds to a given Java generic declaration (class, method, or constructor)
|
|
*/
|
|
def genericDeclarationToScala(jdecl: GenericDeclaration) = jdecl match {
|
|
case jclazz: jClass[_] => classToScala(jclazz)
|
|
case jmeth: jMethod => methodToScala(jmeth)
|
|
case jconstr: jConstructor[_] => constrToScala(jconstr)
|
|
}
|
|
|
|
/**
|
|
* Given some Java type arguments, a corresponding list of Scala types, plus potentially
|
|
* some existentially bound type variables that represent wildcard arguments.
|
|
*/
|
|
private def targsToScala(owner: Symbol, args: List[jType]): (List[Type], List[Symbol]) = {
|
|
val tparams = new ListBuffer[Symbol]
|
|
def targToScala(arg: jType): Type = arg match {
|
|
case jwild: WildcardType =>
|
|
val tparam = owner.newExistential(NoPosition, newTypeName("T$" + tparams.length))
|
|
.setInfo(TypeBounds(
|
|
lub(jwild.getLowerBounds.toList map typeToScala),
|
|
glb(jwild.getUpperBounds.toList map typeToScala map objToAny)))
|
|
tparams += tparam
|
|
typeRef(NoPrefix, tparam, List())
|
|
case _ =>
|
|
typeToScala(arg)
|
|
}
|
|
(args map targToScala, tparams.toList)
|
|
}
|
|
|
|
/**
|
|
* The Scala type that corresponds to given Java type
|
|
*/
|
|
def typeToScala(jtpe: jType): Type = jtpe match {
|
|
case jclazz: jClass[_] =>
|
|
if (jclazz.isArray)
|
|
arrayType(typeToScala(jclazz.getComponentType))
|
|
else {
|
|
val clazz = classToScala(jclazz)
|
|
rawToExistential(typeRef(clazz.owner.thisType, clazz, List()))
|
|
}
|
|
case japplied: ParameterizedType =>
|
|
val (pre, sym) = typeToScala(japplied.getRawType) match {
|
|
case ExistentialType(tparams, TypeRef(pre, sym, _)) => (pre, sym)
|
|
case TypeRef(pre, sym, _) => (pre, sym)
|
|
}
|
|
val args0 = japplied.getActualTypeArguments
|
|
val (args, bounds) = targsToScala(pre.typeSymbol, args0.toList)
|
|
ExistentialType(bounds, typeRef(pre, sym, args))
|
|
case jarr: GenericArrayType =>
|
|
arrayType(typeToScala(jarr.getGenericComponentType))
|
|
case jtvar: jTypeVariable[_] =>
|
|
val tparam = tparamToScala(jtvar)
|
|
typeRef(NoPrefix, tparam, List())
|
|
}
|
|
|
|
/**
|
|
* The Scala class that corresponds to given Java class without taking
|
|
* Scala pickling info into account.
|
|
* @param jclazz The Java class
|
|
* @return A Scala class symbol that wraps all reflection info of `jclazz`
|
|
*/
|
|
private def jclassAsScala(jclazz: jClass[_]): Symbol = jclassAsScala(jclazz, sOwner(jclazz))
|
|
|
|
private def jclassAsScala(jclazz: jClass[_], owner: Symbol): Symbol = {
|
|
val name = newTypeName(jclazz.getSimpleName)
|
|
val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, jclazz)
|
|
val (clazz, module) = createClassModule(owner, name, completer)
|
|
classCache enter (jclazz, clazz)
|
|
clazz
|
|
}
|
|
|
|
/**
|
|
* The Scala field that corresponds to given Java field without taking
|
|
* Scala pickling info into account.
|
|
* @param jfield The Java field
|
|
* @return A Scala value symbol that wraps all reflection info of `jfield`
|
|
*/
|
|
private def jfieldAsScala(jfield: jField): Symbol = fieldCache.toScala(jfield) {
|
|
val field = sOwner(jfield).newValue(NoPosition, newTermName(jfield.getName))
|
|
.setFlag(toScalaFlags(jfield.getModifiers, isField = true) | JAVA)
|
|
.setInfo(typeToScala(jfield.getGenericType))
|
|
fieldCache enter (jfield, field)
|
|
copyAnnotations(field, jfield)
|
|
field
|
|
}
|
|
|
|
private def setMethType(meth: Symbol, tparams: List[Symbol], paramtpes: List[Type], restpe: Type) = {
|
|
meth setInfo polyType(tparams, MethodType(meth.owner.newSyntheticValueParams(paramtpes map objToAny), restpe))
|
|
}
|
|
|
|
/**
|
|
* The Scala method that corresponds to given Java method without taking
|
|
* Scala pickling info into account.
|
|
* @param jmeth The Java method
|
|
* @return A Scala method symbol that wraps all reflection info of `jmethod`
|
|
*/
|
|
private def jmethodAsScala(jmeth: jMethod): Symbol = methodCache.toScala(jmeth) {
|
|
val clazz = sOwner(jmeth)
|
|
val meth = clazz.newMethod(NoPosition, newTermName(jmeth.getName))
|
|
.setFlag(toScalaFlags(jmeth.getModifiers) | JAVA)
|
|
methodCache enter (jmeth, meth)
|
|
val tparams = jmeth.getTypeParameters.toList map createTypeParameter
|
|
val paramtpes = jmeth.getGenericParameterTypes.toList map typeToScala
|
|
val resulttpe = typeToScala(jmeth.getGenericReturnType)
|
|
setMethType(meth, tparams, paramtpes, resulttpe)
|
|
copyAnnotations(meth, jmeth)
|
|
if ((jmeth.getModifiers & JAVA_ACC_VARARGS) != 0) {
|
|
meth.setInfo(arrayToRepeated(meth.info))
|
|
}
|
|
meth
|
|
}
|
|
|
|
/**
|
|
* The Scala constructor that corresponds to given Java constructor without taking
|
|
* Scala pickling info into account.
|
|
* @param jconstr The Java constructor
|
|
* @return A Scala constructor symbol that wraps all reflection info of `jconstr`
|
|
*/
|
|
private def jconstrAsScala(jconstr: jConstructor[_]): Symbol = {
|
|
// [Martin] Note: I know there's a lot of duplication wrt jmethodAsScala, but don't think it's worth it to factor this out.
|
|
val clazz = sOwner(jconstr)
|
|
val constr = clazz.newMethod(NoPosition, nme.CONSTRUCTOR)
|
|
.setFlag(toScalaFlags(jconstr.getModifiers) | JAVA)
|
|
constructorCache enter (jconstr, constr)
|
|
val tparams = jconstr.getTypeParameters.toList map createTypeParameter
|
|
val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala
|
|
setMethType(constr, tparams, paramtpes, clazz.tpe)
|
|
constr setInfo polyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe))
|
|
copyAnnotations(constr, jconstr)
|
|
constr
|
|
}
|
|
}
|
|
|
|
class ReflectError(msg: String) extends java.lang.Error(msg)
|