在包开发过程中查找未使用/"orphaned" 未导出的对象

Find unused/"orphaned" non-exported objects during package development

我正在重构一个包含许多非导出函数和其他非导出对象的包。除了手动全文搜索包中每个函数的名称外,有没有一种方法可以快速识别已定义但未导出或未在包中其他任何位置调用的所有“孤立”对象?

一个额外的复杂问题是一些函数在 glue f 风格的字符串中被调用,所以可能会出现调用的函数不能被解析为表达式的情况(这可能不是一个好的设计模式) .

但我会满足于仅用于函数和其他对象的方法,这些对象在定义后从未作为普通表达式出现。

这会给你一个部分答案(从原来的编辑):

pkg <- "testpkg"
library(pkg, character.only = TRUE)
ns <- getNamespace(pkg)
allnames <- ls(ns)
exports <- ls(paste0("package:", pkg))

nsInfo <- readRDS(system.file("Meta/nsInfo.rds", package = pkg))

if (!is.null(nsInfo$S3methods)) {
  S3methods <- with(nsInfo, paste(S3methods[,1], S3methods[,2], sep = "."))
} else
  S3methods <- NULL

locals <- setdiff(allnames, c(exports, S3methods))

used <- character()
newones <- c(exports, S3methods)
while (length(newones)) {
  mentioned <- unique(unlist(lapply(newones, function(n) {
      fun <- get(n, envir = ns)
      if (is.function(fun)) 
        codetools::findGlobals(fun)
        })))
  used <- c(used, newones)
  newones <- setdiff(intersect(mentioned, locals), used)
}
 
unused <- setdiff(locals, used)
unused

这仍然不太正确,但它应该可以帮助您入门。一些问题:

  • 它假设没有函数在做像 assign() 这样有趣的事情,或者摆弄 与环境等
  • 它不检测完全用于构建其他函数的函数 包裹中的物品。
  • 它不会检测使用非标准名称声明的奇怪 S3 方法。