我正在写一个Wart Remover插件。我想检测对可能返回null
的某些方法的调用,例如System.getProperty
。但是,我试图匹配它们的所有方法都失败了。这是我最近的尝试:
import org.brianmckenna.wartremover.{WartTraverser, WartUniverse}
import scala.language.{implicitConversions,reflectiveCalls}
object LegacyJavaAPIs extends WartTraverser {
def apply(u: WartUniverse): u.Traverser = {
import u.universe._
@SuppressWarnings(Array("org.brianmckenna.wartremover.warts.AsInstanceOf",
"com.example.wart.LegacyJavaAPIs"))
val getProperty = reify(System.getProperty("x")).tree match {
case Apply(a,b) => a.toString
}
new u.Traverser {
override def traverse(tree: Tree): Unit = {
if(tree.toString == getProperty)
u.error(tree.pos,
"""|Do not use System.getProperty - it may return null.
|Use sys.props instead.""".stripMargin)
else
super.traverse(tree)
}
}
}
}
我尝试的大多数方法都会导致应该出错的行没有错误 - 尽管当我尝试.symbol
而不是.toString
时,顶级树开始在任何地方匹配。我猜这些情境中.symbol
是null
......
我还尝试使用showRaw
并复制并粘贴相关的构造函数,但这不起作用,因为它不是有效的Scala代码 - java.lang
出现了showRaw
输出中的标识符,而不是包含在它实际包含的任何构造函数中。
答案 0 :(得分:0)
好吧,我终于设法找到了一个没有被破坏的scala反射API的一部分:
object LegacyJavaAPIs extends WartTraverser {
def apply(u: WartUniverse): u.Traverser = {
import u.universe._
@SuppressWarnings(Array("org.brianmckenna.wartremover.warts.AsInstanceOf"))
val systemStatic = rootMirror.typeOf[System].companion
val getProperty = systemStatic.decl(TermName("getProperty")).alternatives
new u.Traverser {
override def traverse(tree: Tree): Unit =
if(getProperty.contains(tree.symbol))
u.error(tree.pos,
"""|Do not use System.getProperty - it may return null.
|Use sys.props.get instead.""".stripMargin)
else
super.traverse(tree)
}
}
我们需要致电companion
(即使java.lang.System
没有伴侣对象,因为它是Java)因为scala-reflect没有认识到静态方法,并将它们视为伴随对象上的方法。我们还需要致电alternatives
,因为getProperty
已超载。
如果感兴趣的类型是scala.Predef
,则需要稍微调整一下:
val predef = rootMirror.typeOf[scala.Predef.type]