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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/* NSC -- new Scala compiler
* Copyright 2005-2010 LAMP/EPFL
* @author Paul Phillips
*/
package scala.tools.nsc
package interpreter
import java.lang.reflect
import reflect.{ Modifier, AccessibleObject }
import Modifier.{ isPrivate, isProtected, isStatic }
import scala.reflect.NameTransformer
import scala.collection.mutable.HashMap
import ReflectionCompletion._
import Completion.{ excludeMethods }
trait ReflectionCompletion extends CompletionAware {
def clazz: Class[_]
protected def visibleMembers: List[AccessibleObject]
protected def memberCompletions = visibleMembers filter isPublic map reflectName
def reflectName(m: AccessibleObject) = m match {
case x: reflect.Method => x.getName
case x: reflect.Field => x.getName
case x => error(x.toString)
}
def isPublic(m: AccessibleObject) = m match {
case x: reflect.Method => Modifier isPublic x.getModifiers
case x: reflect.Field => Modifier isPublic x.getModifiers
case x => error(x.toString)
}
override def filterNotFunction(s: String): Boolean = {
(excludeMethods contains s) ||
(s contains "$$super") ||
(s == "MODULE$")
}
lazy val (staticMethods, instanceMethods) = clazz.getMethods.toList partition (x => isStatic(x.getModifiers))
lazy val (staticFields, instanceFields) = clazz.getFields.toList partition (x => isStatic(x.getModifiers))
/** Oops, mirror classes don't descend from scalaobject.
*/
def isScalaClazz(cl: Class[_]) = {
(allInterfacesFor(cl) exists (_.getName == "scala.ScalaObject")) ||
(classForName(cl.getName + "$").isDefined)
}
def allInterfacesFor(cl: Class[_]): List[Class[_]] = allInterfacesFor(cl, Nil)
private def allInterfacesFor(cl: Class[_], acc: List[Class[_]]): List[Class[_]] = {
if (cl == null) acc.distinct
else allInterfacesFor(cl.getSuperclass, acc ::: cl.getInterfaces.toList)
}
}
/** An instance completion which hides a few useless members.
*/
class PackageObjectCompletion(clazz: Class[_]) extends InstanceCompletion(clazz) {
override lazy val completions = memberCompletions
override def filterNotFunction(s: String) = {
super.filterNotFunction(s) || (s == "getClass") || (s == "toString")
}
}
/** A completion aware object representing a single instance of some class.
* It completes to instance fields and methods, and delegates to another
* InstanceCompletion object if it can determine the result type of the element.
*/
class InstanceCompletion(val clazz: Class[_]) extends ReflectionCompletion {
protected def visibleMembers = instanceMethods ::: instanceFields
def extras = List("isInstanceOf", "asInstanceOf", "toString")
lazy val completions = memberCompletions ::: extras
val (zeroArg, otherArg) = instanceMethods partition (_.getParameterTypes.size == 0)
override def follow(id: String) = {
val nextClazz = zeroArg find (m => m.getName == id) map (_.getReturnType)
if (nextClazz.isDefined) nextClazz map (x => new InstanceCompletion(x))
else instanceFields find (_.getName == id) map (x => new InstanceCompletion(x.getType))
}
}
/** The complementary class to InstanceCompletion. It has logic to deal with
* java static members and scala companion object members.
*/
class StaticCompletion(val clazz: Class[_]) extends ReflectionCompletion {
protected def visibleMembers = whichMethods ::: whichFields
lazy val completions = memberCompletions
private def aliasForPath(path: String) = ByteCode aliasForType path flatMap (x => classForName(x + "$"))
def className = clazz.getName
def isJava = !isScalaClazz(clazz)
private def whichMethods = if (isJava) staticMethods else instanceMethods
private def whichFields = if (isJava) staticFields else instanceFields
val (zeroArg, otherArg) = whichMethods partition (_.getParameterTypes.size == 0)
override def follow(id: String) = {
val nextClazz = zeroArg find (m => m.getName == id) map (_.getReturnType)
if (nextClazz.isDefined) nextClazz map (x => new InstanceCompletion(x))
else staticFields find (_.getName == id) map (x => new InstanceCompletion(x.getType))
}
override def toString = "StaticCompletion(%s) => %s".format(clazz.getName, completions)
}
object ReflectionCompletion {
import java.io.File
import java.util.jar.{ JarEntry, JarFile }
import scala.tools.nsc.io.Streamable
// XXX at the moment this is imperfect because scala's protected semantics
// differ from java's, so protected methods appear public via reflection;
// yet scala enforces the protection. The result is that protected members
// appear in completion yet cannot actually be called. Fixing this
// properly requires a scala.reflect.* API. Fixing it uglily is possible
// too (cast to structural type!) but I deem poor use of energy.
private def skipModifiers(m: reflect.Method) = {
import java.lang.reflect.Modifier._
val flags = STATIC | PRIVATE | PROTECTED
(m.getModifiers & flags) == 0
}
private def getAnyClass(x: Any): Class[_] = x.asInstanceOf[AnyRef].getClass
def methodsOf(target: Any): List[String] =
getAnyClass(target).getMethods filter skipModifiers map (_.getName) toList
}
|