Scalafix中如何实现带可选语义检查的语法规则?(Kyo版本升级)
实现Kyo升级Scalafix规则:语法优先+可选语义检查
完全可以实现这种“语法规则为基础,SemanticDb可用时自动启用符号检查”的模式,具体改造思路和代码如下:
核心改造思路
- 将规则从
SemanticRule改为继承SyntaxRule,让规则可以在无SemanticDb的环境下运行 - 封装判断逻辑:默认仅通过语法特征匹配,当SemanticDb可用时,额外验证目标符号是否属于Kyo的API,避免误修改同名代码
改造后的完整代码
package kyo.rules import scala.meta._ import scalafix.v1._ class KyoUpdateToV1_0 extends SyntaxRule("KyoUpdateToV1_0") { // 封装语法匹配+可选语义检查的判断逻辑 private def shouldApply[T <: Tree](tree: T, targetSymbol: String)(implicit semDoc: Option[SemanticDocument]): Boolean = semDoc match { // 无SemanticDb时,仅通过语法特征匹配 case None => true // 有SemanticDb时,必须通过符号匹配验证 case implicit Some(doc) => SymbolMatcher.normalized(targetSymbol).matches(tree) } override def fix(implicit doc: Document): Patch = { // 获取可选的语义上下文 val semanticDoc = doc.semanticDocument doc.tree.collect({ // 替换defer为direct case defer @ Term.Name("defer") if shouldApply(defer, "kyo.Direct$package.defer.") => Patch.replaceTree(defer, "direct") // 替换IO.apply为Sync.defer case ioApply @ Term.Select(Term.Name("IO"), Term.Name("apply")) if shouldApply(ioApply, "kyo.IO$package.IO.apply.") => Patch.replaceTree(ioApply, "Sync.defer") // 替换IO(...)调用为Sync.defer(...) case Term.Apply.After_4_6_0(io @ Term.Name("IO"), args) if shouldApply(io, "kyo.IO$package.IO.") => Patch.replaceTree(io, "Sync.defer") // 替换IO类型为Sync case io @ Type.Name("IO") if shouldApply(io, "kyo/IO$package.IO#") => Patch.replaceTree(io, "Sync") }).asPatch } }
关键细节说明
- 兼容性:继承
SyntaxRule后,规则不再强制要求生成SemanticDb,可直接作为纯语法规则运行,适合快速批量升级场景 - 精确性:当项目配置了SemanticDb时,自动启用符号检查,确保只修改Kyo库的目标API,不会误改自定义的同名变量/类型
- 灵活性:如果担心纯语法匹配的误改风险(比如"IO"是常见命名),可以在
shouldApply的None分支中添加额外语法约束(比如检查文件中是否存在import kyo._导入),进一步缩小匹配范围
内容的提问来源于stack exchange,提问作者jwinandy
相关产品推荐
相关产品推荐

