Scala编译器插件(Typer阶段后)获取文档注释失败问题
解决Scala编译器插件在Typer后访问文档注释的问题
我之前也踩过这个坑!你说的情况完全合理,global.cookedDocComment(symbol)返回空的核心原因是:常规编译流程(非Scaladoc/交互式REPL)不会自动解析和填充docComments映射。那个forceDocComment是交互式编译器专属的私有逻辑,普通编译阶段根本不会触发它。
不过别担心,我们有两种可行的解决思路:
思路1:直接从AST树节点提取注释
Typer阶段之后,编译单元的AST已经完全构建完成,文档注释其实以DocComment节点的形式附在对应符号的树结构里,只是没被放到docComments映射中而已。我们可以自己遍历AST来提取:
import scala.tools.nsc._ import scala.tools.nsc.plugins.PluginComponent class DocCommentPluginComponent(val global: Global) extends PluginComponent { import global._ override val phaseName = "doc-comment-extractor" override val runsAfter = List("typer") override def newPhase(prev: Phase): Phase = new StdPhase(prev) { override def apply(unit: CompilationUnit): Unit = { // 遍历当前编译单元的所有树节点 traverse(unit.body) { case tree if tree.symbol != NoSymbol => val doc = extractDocComment(tree) if (doc.nonEmpty) { println(s"[Doc Comment] ${tree.symbol.fullName}:\n$doc") } } } // 递归查找树节点的文档注释 private def extractDocComment(tree: Tree): String = { // 先检查当前树的直接注释 tree.comment.orElse { // 遍历子节点找DocComment类型的节点 tree.children.collectFirst { case dc: DocComment => dc.comment } }.getOrElse("") } // 简单的AST遍历工具方法 private def traverse(tree: Tree)(f: Tree => Unit): Unit = { f(tree) tree.children.foreach(traverse(_)(f)) } } }
这个方法的好处是不需要额外依赖,完全基于编译器核心API就能实现,而且能拿到原始的文档注释字符串。
思路2:复用Scaladoc的解析逻辑(如果需要结构化文档)
如果你需要把注释解析成结构化的对象(比如提取参数说明、返回值注释等),可以参考Scaladoc的实现。Scaladoc有一套完整的文档解析流程,你可以在插件中引入Scaladoc的相关类(注意要依赖scala-compiler和scala-library的完整jar包),然后调用它的解析器来处理注释字符串。
不过这种方式需要处理更多的依赖和初始化逻辑,适合对文档注释有复杂处理需求的场景。
关键提醒
- 编译时不需要额外加特殊参数,只要插件运行在Typer之后,AST就已经包含了文档注释节点
- 不同Scala版本的AST结构可能略有差异,比如
DocComment的位置或API,需要对应版本调整代码
内容的提问来源于stack exchange,提问作者Alexey Romanov
相关产品推荐
相关产品推荐

