从Scala项目中排除特定的隐式对象

Klu*_*ßer 7 scala sbt implicit-conversion scalafix

如何防止在scala代码中使用特定的隐式?

例如,最近我被https://github.com/scala/scala/blob/68bad81726d15d03a843dc476d52cbbaf52fb168/src/library/scala/io/Codec.scala#L76Codec提供的默认值所困扰。有没有办法确保任何调用a的代码都implicit codec: Codec不会使用所提供的代码fallbackSystemCodec?或者,是否可以阻止所有隐式编解码器?

这是应该使用scalafix进行的吗?

Mar*_*lic 5

Scalafix can inspect implicit arguments using SemanticTree. Here is an example solution by defining a custom scalafix rule.

Given

import scala.io.Codec

object Hello {
  def foo(implicit codec: Codec) = 3
  foo
}
Run Code Online (Sandbox Code Playgroud)

we can define a custom rule

class ExcludedImplicitsRule(config: ExcludedImplicitsRuleConfig)
    extends SemanticRule("ExcludedImplicitsRule") {

...

  override def fix(implicit doc: SemanticDocument): Patch = {
    doc.tree.collect {
      case term: Term if term.synthetic.isDefined => // TODO: Use ApplyTree(func, args)
        val struct = term.synthetic.structure
        val isImplicit = struct.contains("implicit")
        val excludedImplicit = config.blacklist.find(struct.contains)
        if (isImplicit && excludedImplicit.isDefined)
          Patch.lint(ExcludedImplicitsDiagnostic(term, excludedImplicit.getOrElse(config.blacklist.mkString(","))))
        else
          Patch.empty
    }.asPatch
  }

}
Run Code Online (Sandbox Code Playgroud)

and corresponding .scalafix.conf

rule = ExcludedImplicitsRule
ExcludedImplicitsRuleConfig.blacklist = [
  fallbackSystemCodec
]
Run Code Online (Sandbox Code Playgroud)

should enable sbt scalafix to raise the diagnostic

[error] /Users/mario/IdeaProjects/scalafix-exclude-implicits/example-project/scalafix-exclude-implicits-example/src/main/scala/example/Hello.scala:7:3: error: [ExcludedImplicitsRule] Attempting to pass excluded implicit fallbackSystemCodec to foo'
[error]   foo
[error]   ^^^
[error] (Compile / scalafix) scalafix.sbt.ScalafixFailed: LinterError
Run Code Online (Sandbox Code Playgroud)

Note the output of println(term.synthetic.structure)

Some(ApplyTree(
  OriginalTree(Term.Name("foo")),
  List(
    IdTree(SymbolInformation(scala/io/LowPriorityCodecImplicits#fallbackSystemCodec. => implicit lazy val method fallbackSystemCodec: Codec))
  )
))
Run Code Online (Sandbox Code Playgroud)

Clearly the above solution is not efficient as it searches strings, however it should give some direction. Perhaps matching on ApplyTree(func, args) would be better.

scalafix-exclude-implicits-example shows how to configure the project to use ExcludedImplicitsRule.