OldJii/dead-code-pruner
GitHub: OldJii/dead-code-pruner
基于 tree-sitter 的多语言源码级死代码清理工具,通过布尔常量传播和项目级引用分析安全移除废弃代码。
Stars: 64 | Forks: 0
# dead-code-pruner
`dead-code-pruner` 是一款基于 [tree-sitter](https://tree-sitter.github.io/) 驱动的、稳健的源码级死代码清理工具。
给定一组永远为 `true` 或 `false` 的表达式,它会将这些事实传播到源代码树中,简化生成的控制流,并移除那些被证明已不再使用的声明和文件。
该工具目前支持 Java、Kotlin、Go、Swift 和 Dart。它专为 Android、JVM 服务、Go 服务、iOS 和 Flutter 仓库设计,包括多模块项目。
## 可清理的内容
从配置的常量开始,该工具可以产生如下源代码更改:
- 将废弃的 feature flags 和编译时条件替换为布尔字面量。
- 简化布尔表达式、逻辑非、相等性检查、短路表达式、三元运算符以及特定语言的 conditional 表达式。
- 移除废弃的 `if` 分支,以及在 `return`、`throw`、`break` 或 `continue` 之后变得不可达的代码。
- 传播不可变的局部布尔变量,并在其所有使用处消失后移除其声明。
- 内联总是返回 `true` 或 `false` 的无参方法,然后继续清理新暴露出来的分支。
- 移除空方法、未使用的返回常量的辅助方法及其安全的调用处。
- 当全项目范围的引用和项目边界规则证明删除是安全的时,移除未使用的不可变字段。
- 移除未引用的空类以及不再包含任何声明的源文件。
- 重复级联清理,直到无法再得出进一步的源代码更改为止。
例如,一个已废弃的 feature 可以跨多个文件折叠到剩余的活跃路径中:
```
diff --git a/LegacyFeatureController.java b/LegacyFeatureController.java
--- a/LegacyFeatureController.java
+++ b/LegacyFeatureController.java
@@
final class LegacyFeatureController {
- private static final boolean RETIRED_DEFAULT = false;
-
- private boolean isLegacyMode() {
- return false;
- }
-
- private void recordLegacyExposure() {}
-
void render() {
- final boolean legacyEnabled = FeatureFlags.LEGACY_MODE;
- recordLegacyExposure();
- if (!legacyEnabled
- && (LegacyFeatureController.RETIRED_DEFAULT || isLegacyMode())) {
- RetiredFeature.renderLegacy();
- return;
- unreachableLegacyCleanup();
- } else {
- renderCurrent();
- }
+ renderCurrent();
}
}
diff --git a/LegacyScreen.kt b/LegacyScreen.kt
--- a/LegacyScreen.kt
+++ b/LegacyScreen.kt
@@
-val title = if (false) legacyTitle else currentTitle
+val title = currentTitle
diff --git a/RetiredFeature.java b/RetiredFeature.java
deleted file mode 100644
--- a/RetiredFeature.java
+++ /dev/null
@@
-package com.example.legacy;
-
-final class RetiredFeature {
- static void renderLegacy() {}
-}
```
这种清理是刻意保持稳健的。除非该工具能证明移除它们是安全的,否则被注解的声明、框架 entry point、契约、override、动态引用以及可能在扫描的仓库之外使用的 public API 都会被保留。
## 用法
需要 Python 3.10 或更高版本。
```
git clone https://github.com/OldJii/dead-code-pruner.git
cd dead-code-pruner
pip install -r requirements.txt
cp pruner.example.yaml pruner.yaml
```
编辑 `pruner.yaml` 并将示例替换为您项目中废弃的常量:
```
project_boundary:
mode: auto
replacements:
- pattern: "FeatureFlags.LEGACY_MODE"
value: false
- pattern: "BuildConfig.CURRENT_VARIANT"
value: true
```
针对项目目录运行清理:
```
python3 -m pruner /path/to/your/project --config pruner.yaml
```
请在单独的 Git 分支上运行,检查生成的 diff,并在合并更改之前对目标项目进行编译和测试。
## 在 Android 之外使用
该实现包含针对 Java、Kotlin、Go、Swift 和 Dart 的语言适配器和测试,但到目前为止,其大规模生产使用仅在 Android 项目上得到了验证。
对于非 Android 仓库,请从 fork 开始。如果某个语言结构未被正确处理,请将该有问题的源代码作为一个小型的可复现测试用例,让 AI 编程代理分析 AST 或引用解析的缺失,并在调整适配器或清理规则之前添加输入/预期输出的测试。一旦新用例和现有测试套件全部通过,该行为就被固定为一条可重复的规则,您可以放心地将清理应用到目标仓库。
扩展该工具后,请运行完整的测试集:
```
python3 tests/run_tests.py
python3 tests/run_project_tests.py
python3 tests/test_language_matrix.py
python3 tests/test_project_boundary.py
```
## 工作原理
tree-sitter 将源文件解析为语法树,使得该工具能够区分表达式、声明、调用、注释、字符串和控制流边界,而无需依赖脆弱的文本替换。
该工具首先根据配置的布尔事实简化每个文件。然后,它为声明、引用、继承、契约、生成的 accessor 和动态 entry point 构建项目级别的索引。只有没有剩余安全引用的声明才会被移除。修改后的文件会被再次分析,从而允许一次删除暴露出下一次删除,直到项目达到稳定的结果。
语言适配器为每个生态系统提供语法和框架规则,而项目边界检测则在库中保留外部可见的 API,并允许在应用程序和已部署的服务中进行更广泛的清理。
主要 pipeline 包含两个阶段:
1. **源代码简化** 按源代码顺序运行八个语法级别的步骤,并对每个文件重复执行,直到该文件稳定。
2. **项目清理** 扫描项目一次,移除被证明已废弃的声明,对更改过的文件重新运行源代码简化,在项目索引中刷新这些文件,并重复执行直到稳定。然后移除未引用的空类和文件。
全项目范围的布尔方法内联也作为独立的实用工具公开,用于集中的集成,但它并不是一个单独的 pipeline 阶段。
## 许可证
MIT
标签:IPv6支持, JS文件枚举, 日志审计, 逆向工具