有没有办法阻止使用依赖项提供的特定功能?
Is there a way to prevent usage of a specific function provided by a dependency?
我的应用程序对库 A 有编译依赖性。我知道这个库中有一个特定函数会导致性能问题。但它并未被弃用,如果您没有此先验信息,您会认为使用它是安全的。我正在寻找一种方法来以某种方式弃用此功能或阻止它被直接调用。
是否可以通过静态分析工具或内置编译器标志来实现?
您可以为 Scalafix 编写规则
https://scalacenter.github.io/scalafix/docs/developers/setup.html
例如,让我们弃用 scala.Predef.println
class DeprecateFunction extends SemanticRule("DeprecateFunction") {
case class Deprecation(position: Position) extends Diagnostic {
override def message = "Use loggers instead of println"
override def severity = LintSeverity.Warning
}
val deprecatedFunction = SymbolMatcher.normalized("scala.Predef.println")
override def fix(implicit doc: SemanticDocument): Patch = {
doc.tree.collect {
case deprecatedFunction(t: Name) =>
Patch.lint(Deprecation(t.pos))
}.asPatch
}
}
示例:
object Scalafixdemo {
println(1)
}
输出:
[IJ]sbt:scalafix> scalafix --rules=file:rules/src/main/scala/fix/DeprecateFunction.scala
[info] Running scalafix on 1 Scala sources
[warn] .../scalafix/input/src/main/scala/fix/Scalafixdemo.scala:8:3: warning: [DeprecateFunction] Use loggers instead of println
[warn] println(1)
[warn] ^^^^^^^
[success] Total time: 2 s, completed 27.05.2020 21:12:13
我已经检查过 scalafix,但是设置这种 linting 太复杂了。我最终使用了 wartremover 并添加了一个定制的疣。
自定义疣位于子项目中,如此 example 所示。
lazy val myWarts = project.in(file("my-warts")).settings(
commonSettings,
libraryDependencies ++= Seq(
"org.wartremover" % "wartremover" % wartremover.Wart.PluginVersion cross CrossVersion.full
)
)
lazy val main = project.in(file("main")).settings(
commonSettings,
wartremoverWarnings += Wart.custom("mywarts.ExtractOrElse"),
wartremoverClasspaths ++= {
(fullClasspath in (myWarts, Compile)).value.map(_.data.toURI.toString)
}
)
我通过简单地修改内置 EitherProjectionPartial wart 创建了一个自定义 wart。
object ExtractOrElse extends WartTraverser {
def apply(u: WartUniverse): u.Traverser = {
import u.universe._
val extractableJsonAstNode = rootMirror.staticClass("org.json4s.ExtractableJsonAstNode")
new u.Traverser {
override def traverse(tree: Tree): Unit = {
tree match {
// Ignore trees marked by SuppressWarnings
case t if hasWartAnnotation(u)(t) =>
case Select(left, TermName("extractOrElse")) if left.tpe.baseType(extractableJsonAstNode) != NoType =>
error(u)(tree.pos, "extractOrElse is deprecated - use toOption.map or extract[Option[A]] instead")
super.traverse(tree)
case _ => super.traverse(tree)
}
}
}
}
}
我的应用程序对库 A 有编译依赖性。我知道这个库中有一个特定函数会导致性能问题。但它并未被弃用,如果您没有此先验信息,您会认为使用它是安全的。我正在寻找一种方法来以某种方式弃用此功能或阻止它被直接调用。
是否可以通过静态分析工具或内置编译器标志来实现?
您可以为 Scalafix 编写规则
https://scalacenter.github.io/scalafix/docs/developers/setup.html
例如,让我们弃用 scala.Predef.println
class DeprecateFunction extends SemanticRule("DeprecateFunction") {
case class Deprecation(position: Position) extends Diagnostic {
override def message = "Use loggers instead of println"
override def severity = LintSeverity.Warning
}
val deprecatedFunction = SymbolMatcher.normalized("scala.Predef.println")
override def fix(implicit doc: SemanticDocument): Patch = {
doc.tree.collect {
case deprecatedFunction(t: Name) =>
Patch.lint(Deprecation(t.pos))
}.asPatch
}
}
示例:
object Scalafixdemo {
println(1)
}
输出:
[IJ]sbt:scalafix> scalafix --rules=file:rules/src/main/scala/fix/DeprecateFunction.scala
[info] Running scalafix on 1 Scala sources
[warn] .../scalafix/input/src/main/scala/fix/Scalafixdemo.scala:8:3: warning: [DeprecateFunction] Use loggers instead of println
[warn] println(1)
[warn] ^^^^^^^
[success] Total time: 2 s, completed 27.05.2020 21:12:13
我已经检查过 scalafix,但是设置这种 linting 太复杂了。我最终使用了 wartremover 并添加了一个定制的疣。
自定义疣位于子项目中,如此 example 所示。
lazy val myWarts = project.in(file("my-warts")).settings(
commonSettings,
libraryDependencies ++= Seq(
"org.wartremover" % "wartremover" % wartremover.Wart.PluginVersion cross CrossVersion.full
)
)
lazy val main = project.in(file("main")).settings(
commonSettings,
wartremoverWarnings += Wart.custom("mywarts.ExtractOrElse"),
wartremoverClasspaths ++= {
(fullClasspath in (myWarts, Compile)).value.map(_.data.toURI.toString)
}
)
我通过简单地修改内置 EitherProjectionPartial wart 创建了一个自定义 wart。
object ExtractOrElse extends WartTraverser {
def apply(u: WartUniverse): u.Traverser = {
import u.universe._
val extractableJsonAstNode = rootMirror.staticClass("org.json4s.ExtractableJsonAstNode")
new u.Traverser {
override def traverse(tree: Tree): Unit = {
tree match {
// Ignore trees marked by SuppressWarnings
case t if hasWartAnnotation(u)(t) =>
case Select(left, TermName("extractOrElse")) if left.tpe.baseType(extractableJsonAstNode) != NoType =>
error(u)(tree.pos, "extractOrElse is deprecated - use toOption.map or extract[Option[A]] instead")
super.traverse(tree)
case _ => super.traverse(tree)
}
}
}
}
}