如何匹配对 Wart Remover 中特定方法的调用?
How to match calls to particular methods in Wart Remover?
我正在写一个 Wart Remover 插件。我想检测对某些可能 return 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
的输出,而不是包装在实际包装的任何构造函数中。
好吧,我终于设法找到了 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]
我正在写一个 Wart Remover 插件。我想检测对某些可能 return 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
的输出,而不是包装在实际包装的任何构造函数中。
好吧,我终于设法找到了 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]