jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,766 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Clippy 告警修复模块。"""
3
+
4
+ import json
5
+ import os
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import Callable
9
+ from typing import Dict
10
+ from typing import List
11
+
12
+ from jarvis.jarvis_utils.output import PrettyOutput
13
+
14
+ from jarvis.jarvis_agent.events import AFTER_TOOL_CALL
15
+ from jarvis.jarvis_agent.events import BEFORE_TOOL_CALL
16
+ from jarvis.jarvis_c2rust.optimizer_options import OptimizeOptions
17
+ from jarvis.jarvis_c2rust.optimizer_options import OptimizeStats
18
+ from jarvis.jarvis_c2rust.optimizer_progress import ProgressManager
19
+ from jarvis.jarvis_c2rust.optimizer_utils import cargo_check_full
20
+ from jarvis.jarvis_c2rust.optimizer_utils import check_clippy_warnings
21
+ from jarvis.jarvis_c2rust.optimizer_utils import git_toplevel
22
+ from jarvis.jarvis_c2rust.optimizer_utils import iter_rust_files
23
+ from jarvis.jarvis_c2rust.optimizer_utils import run_cargo_fmt
24
+ from jarvis.jarvis_c2rust.optimizer_utils import run_cmd
25
+ from jarvis.jarvis_code_agent.code_agent import CodeAgent
26
+
27
+
28
+ class ClippyOptimizer:
29
+ """Clippy 告警修复优化器。"""
30
+
31
+ def __init__(
32
+ self,
33
+ crate_dir: Path,
34
+ options: OptimizeOptions,
35
+ stats: OptimizeStats,
36
+ progress_manager: ProgressManager,
37
+ append_additional_notes_func: Callable[[str], str],
38
+ verify_and_fix_after_step_func: Callable[[str, List[Path]], bool],
39
+ ):
40
+ self.crate_dir = crate_dir
41
+ self.options = options
42
+ self.stats = stats
43
+ self.progress_manager = progress_manager
44
+ self.append_additional_notes = append_additional_notes_func
45
+ self.verify_and_fix_after_step = verify_and_fix_after_step_func
46
+
47
+ def try_clippy_auto_fix(self) -> bool:
48
+ """
49
+ 尝试使用 `cargo clippy --fix` 自动修复 clippy 告警。
50
+ 修复时同时包含测试代码(--tests),避免删除测试中使用的变量。
51
+ 修复后运行测试验证,如果测试失败则撤销修复。
52
+
53
+ 返回:
54
+ True: 自动修复成功且测试通过
55
+ False: 自动修复失败或测试未通过(已撤销修复)
56
+ """
57
+ crate = self.crate_dir.resolve()
58
+ PrettyOutput.auto_print(
59
+ "🔄 [c2rust-optimizer][clippy-auto-fix] 尝试使用 clippy --fix 自动修复(包含测试代码)...",
60
+ color="cyan",
61
+ )
62
+
63
+ # 记录修复前的 commit id
64
+ commit_before = self.progress_manager.get_crate_commit_hash()
65
+ if not commit_before:
66
+ PrettyOutput.auto_print(
67
+ "⚠️ [c2rust-optimizer][clippy-auto-fix] 无法获取 commit id,跳过自动修复",
68
+ color="yellow",
69
+ )
70
+ return False
71
+
72
+ # 执行 cargo clippy --fix,添加 --tests 标志以包含测试代码
73
+ try:
74
+ res = subprocess.run(
75
+ [
76
+ "cargo",
77
+ "clippy",
78
+ "--fix",
79
+ "--tests",
80
+ "--allow-dirty",
81
+ "--allow-staged",
82
+ "--",
83
+ "-W",
84
+ "clippy::all",
85
+ ],
86
+ capture_output=True,
87
+ text=True,
88
+ check=False,
89
+ cwd=str(crate),
90
+ timeout=300, # 5 分钟超时
91
+ )
92
+
93
+ if res.returncode != 0:
94
+ PrettyOutput.auto_print(
95
+ f"❌ [c2rust-optimizer][clippy-auto-fix] clippy --fix 执行失败(返回码: {res.returncode})",
96
+ color="yellow",
97
+ )
98
+ if res.stderr:
99
+ PrettyOutput.auto_print(
100
+ f"📄 [c2rust-optimizer][clippy-auto-fix] 错误输出: {res.stderr[:500]}",
101
+ color="yellow",
102
+ )
103
+ return False
104
+
105
+ # 检查是否有文件被修改(通过 git status 或直接检查)
106
+ # 如果没有修改,说明 clippy --fix 没有修复任何问题
107
+ repo_root = git_toplevel(crate)
108
+ has_changes = False
109
+ if repo_root:
110
+ try:
111
+ code, out, _ = run_cmd(
112
+ ["git", "diff", "--quiet", "--exit-code"], repo_root
113
+ )
114
+ has_changes = code != 0 # 非零表示有修改
115
+ except Exception:
116
+ # 如果无法检查 git 状态,假设有修改
117
+ has_changes = True
118
+ else:
119
+ # 不在 git 仓库中,假设有修改
120
+ has_changes = True
121
+
122
+ if not has_changes:
123
+ PrettyOutput.auto_print(
124
+ "📊 [c2rust-optimizer][clippy-auto-fix] clippy --fix 未修改任何文件",
125
+ color="cyan",
126
+ )
127
+ return False
128
+
129
+ PrettyOutput.auto_print(
130
+ "🔍 [c2rust-optimizer][clippy-auto-fix] clippy --fix 已执行,正在验证测试...",
131
+ color="cyan",
132
+ )
133
+
134
+ # 运行 cargo test 验证
135
+ ok, diag_full = cargo_check_full(
136
+ self.crate_dir,
137
+ self.stats,
138
+ self.options.max_checks,
139
+ timeout=self.options.cargo_test_timeout,
140
+ )
141
+
142
+ if ok:
143
+ PrettyOutput.auto_print(
144
+ "✅ [c2rust-optimizer][clippy-auto-fix] 自动修复成功且测试通过",
145
+ color="green",
146
+ )
147
+ return True
148
+ else:
149
+ PrettyOutput.auto_print(
150
+ "🔙 [c2rust-optimizer][clippy-auto-fix] 自动修复后测试失败,正在撤销修复...",
151
+ color="yellow",
152
+ )
153
+ # 撤销修复:回退到修复前的 commit
154
+ if commit_before and self.progress_manager.reset_to_commit(
155
+ commit_before
156
+ ):
157
+ PrettyOutput.auto_print(
158
+ f"[c2rust-optimizer][clippy-auto-fix] 已成功撤销自动修复,回退到 commit: {commit_before[:8]}",
159
+ color="cyan",
160
+ )
161
+ else:
162
+ PrettyOutput.auto_print(
163
+ "[c2rust-optimizer][clippy-auto-fix] 撤销修复失败,请手动检查代码状态",
164
+ color="red",
165
+ )
166
+ return False
167
+
168
+ except subprocess.TimeoutExpired:
169
+ PrettyOutput.auto_print(
170
+ "[c2rust-optimizer][clippy-auto-fix] clippy --fix 执行超时,正在检查是否有修改并撤销...",
171
+ color="yellow",
172
+ )
173
+ # 检查是否有修改,如果有则回退
174
+ if commit_before:
175
+ repo_root = git_toplevel(crate)
176
+ if repo_root:
177
+ try:
178
+ code, _, _ = run_cmd(
179
+ ["git", "diff", "--quiet", "--exit-code"], repo_root
180
+ )
181
+ has_changes = code != 0 # 非零表示有修改
182
+ if has_changes:
183
+ if self.progress_manager.reset_to_commit(commit_before):
184
+ PrettyOutput.auto_print(
185
+ f"✅ [c2rust-optimizer][clippy-auto-fix] 已撤销超时前的修改,回退到 commit: {commit_before[:8]}",
186
+ color="cyan",
187
+ )
188
+ else:
189
+ PrettyOutput.auto_print(
190
+ "❌ [c2rust-optimizer][clippy-auto-fix] 撤销修改失败,请手动检查代码状态",
191
+ color="red",
192
+ )
193
+ except Exception:
194
+ # 无法检查状态,尝试直接回退
195
+ self.progress_manager.reset_to_commit(commit_before)
196
+ return False
197
+ except Exception as e:
198
+ PrettyOutput.auto_print(
199
+ f"[c2rust-optimizer][clippy-auto-fix] clippy --fix 执行异常: {e},正在检查是否有修改并撤销...",
200
+ color="yellow",
201
+ )
202
+ # 检查是否有修改,如果有则回退
203
+ if commit_before:
204
+ repo_root = git_toplevel(crate)
205
+ if repo_root:
206
+ try:
207
+ code, _, _ = run_cmd(
208
+ ["git", "diff", "--quiet", "--exit-code"], repo_root
209
+ )
210
+ has_changes = code != 0 # 非零表示有修改
211
+ if has_changes:
212
+ if self.progress_manager.reset_to_commit(commit_before):
213
+ PrettyOutput.auto_print(
214
+ f"✅ [c2rust-optimizer][clippy-auto-fix] 已撤销异常前的修改,回退到 commit: {commit_before[:8]}",
215
+ color="cyan",
216
+ )
217
+ else:
218
+ PrettyOutput.auto_print(
219
+ "❌ [c2rust-optimizer][clippy-auto-fix] 撤销修改失败,请手动检查代码状态",
220
+ color="red",
221
+ )
222
+ except Exception:
223
+ # 无法检查状态,尝试直接回退
224
+ self.progress_manager.reset_to_commit(commit_before)
225
+ return False
226
+
227
+ def codeagent_eliminate_clippy_warnings(
228
+ self, target_files: List[Path], clippy_output: str
229
+ ) -> bool:
230
+ """
231
+ 使用 CodeAgent 消除 clippy 告警。
232
+ 按文件修复,每次修复单个文件的前10个告警(不足10个就全部给出),修复后重新扫描,不断迭代。
233
+
234
+ 注意:CodeAgent 必须在 crate 目录下创建和执行,以确保所有文件操作和命令执行都在正确的上下文中进行。
235
+
236
+ 返回:
237
+ True: 所有告警已消除
238
+ False: 仍有告警未消除(达到最大迭代次数或无法提取告警)
239
+ """
240
+ crate = self.crate_dir.resolve()
241
+ file_list: List[str] = []
242
+ for p in target_files:
243
+ try:
244
+ rel = p.resolve().relative_to(crate).as_posix()
245
+ except Exception:
246
+ rel = p.as_posix()
247
+ file_list.append(rel)
248
+ self.stats.files_scanned += 1
249
+
250
+ # 切换到 crate 目录,确保 CodeAgent 在正确的上下文中创建和执行
251
+ prev_cwd = os.getcwd()
252
+ iteration = 0
253
+
254
+ try:
255
+ os.chdir(str(crate))
256
+
257
+ # 循环修复告警,按文件处理
258
+ while True:
259
+ iteration += 1
260
+
261
+ # 检查当前告警
262
+ has_warnings, current_clippy_output = check_clippy_warnings(crate)
263
+ if not has_warnings:
264
+ PrettyOutput.auto_print(
265
+ f"[c2rust-optimizer][codeagent][clippy] 所有告警已消除(共迭代 {iteration - 1} 次)",
266
+ color="green",
267
+ )
268
+ return True # 所有告警已消除
269
+
270
+ # 按文件提取告警
271
+ warnings_by_file = self.extract_warnings_by_file(current_clippy_output)
272
+ if not warnings_by_file:
273
+ PrettyOutput.auto_print(
274
+ "[c2rust-optimizer][codeagent][clippy] 无法提取告警,停止修复",
275
+ color="yellow",
276
+ )
277
+ return False # 仍有告警未消除
278
+
279
+ # 找到第一个有告警的文件(优先处理目标文件列表中的文件)
280
+ target_file_path = None
281
+ target_warnings = None
282
+
283
+ # 优先处理目标文件列表中的文件
284
+ for file_rel in file_list:
285
+ # 尝试匹配文件路径(可能是相对路径或绝对路径)
286
+ for file_path, warnings in warnings_by_file.items():
287
+ if file_rel in file_path or file_path.endswith(file_rel):
288
+ target_file_path = file_path
289
+ target_warnings = warnings
290
+ break
291
+ if target_file_path:
292
+ break
293
+
294
+ # 如果目标文件列表中没有告警,选择第一个有告警的文件
295
+ if not target_file_path:
296
+ target_file_path = next(iter(warnings_by_file.keys()))
297
+ target_warnings = warnings_by_file[target_file_path]
298
+
299
+ # 获取该文件的前10个告警(不足10个就全部给出)
300
+ warnings_to_fix = (
301
+ target_warnings[:10] if target_warnings is not None else []
302
+ )
303
+ warning_count = len(warnings_to_fix)
304
+ total_warnings_in_file = (
305
+ len(target_warnings) if target_warnings is not None else 0
306
+ )
307
+
308
+ PrettyOutput.auto_print(
309
+ f"🔧 [c2rust-optimizer][codeagent][clippy] 第 {iteration} 次迭代:修复文件 {target_file_path} 的前 {warning_count} 个告警(共 {total_warnings_in_file} 个)",
310
+ color="cyan",
311
+ )
312
+
313
+ # 格式化告警信息
314
+ formatted_warnings = self.format_warnings_for_prompt(
315
+ warnings_to_fix, max_count=10
316
+ )
317
+
318
+ # 构建提示词,修复该文件的前10个告警
319
+ prompt_lines: List[str] = [
320
+ "你是资深 Rust 代码工程师。请在当前 crate 下修复指定文件中的 Clippy 告警,并以补丁形式输出修改:",
321
+ f"- crate 根目录:{crate}",
322
+ "",
323
+ "本次修复仅允许修改以下文件(严格限制,只处理这一个文件):",
324
+ f"- {target_file_path}",
325
+ "",
326
+ f"重要:本次修复仅修复该文件中的前 {warning_count} 个告警,不要修复其他告警。",
327
+ "",
328
+ "优化目标:",
329
+ f"1) 修复文件 {target_file_path} 中的 {warning_count} 个 Clippy 告警:",
330
+ " - 根据以下 Clippy 告警信息,修复这些告警;",
331
+ " - 告警信息包含文件路径、行号、警告类型、消息和建议,请根据这些信息进行修复;",
332
+ " - 对于无法自动修复的告警,请根据 Clippy 的建议进行手动修复;",
333
+ " - **如果确认是误报**(例如:告警建议的修改会导致性能下降、代码可读性降低、或与项目设计意图不符),可以添加 `#[allow(clippy::...)]` 注释来屏蔽该告警;",
334
+ " - 使用 `#[allow(...)]` 时,必须在注释中说明为什么这是误报,例如:`#[allow(clippy::unnecessary_wraps)] // 保持 API 一致性,返回值类型需要与接口定义一致`;",
335
+ " - 优先尝试修复告警,只有在确认是误报时才使用 `#[allow(...)]` 屏蔽。",
336
+ "",
337
+ "2) 修复已有实现的问题:",
338
+ " - 如果在修复告警的过程中,发现代码已有的实现有问题(如逻辑错误、潜在 bug、性能问题、内存安全问题等),也需要一并修复;",
339
+ " - 这些问题可能包括但不限于:空指针解引用、数组越界、未初始化的变量、资源泄漏、竞态条件等;",
340
+ " - 修复时应该保持最小改动原则,优先修复最严重的问题。",
341
+ "",
342
+ "约束与范围:",
343
+ f"- **仅修改文件 {target_file_path},不要修改其他文件**;除非必须(如修复引用路径),否则不要修改其他文件。",
344
+ "- 保持最小改动,不要进行与消除告警无关的重构或格式化。",
345
+ f"- **只修复该文件中的前 {warning_count} 个告警,不要修复其他告警**。",
346
+ "- 修改后需保证 `cargo test` 可以通过;如需引入少量配套改动,请一并包含在补丁中以确保通过。",
347
+ "- 输出仅为补丁,不要输出解释或多余文本。",
348
+ "",
349
+ "优先级说明:",
350
+ "- **如果优化过程中出现了测试不通过或编译错误,必须优先解决这些问题**;",
351
+ "- 在修复告警之前,先确保代码能够正常编译和通过测试;",
352
+ "- 如果修复告警导致了编译错误或测试失败,必须立即修复这些错误,然后再继续优化。",
353
+ "",
354
+ "自检要求:在每次输出补丁后,请使用 execute_script 工具在 crate 根目录执行 `cargo test -q` 进行验证;",
355
+ "若出现编译错误或测试失败,请优先修复这些问题,然后再继续修复告警;",
356
+ "若未通过,请继续输出新的补丁进行最小修复并再次自检,直至 `cargo test` 通过为止。",
357
+ "",
358
+ f"文件 {target_file_path} 中的 Clippy 告警信息如下:",
359
+ "<WARNINGS>",
360
+ formatted_warnings,
361
+ "</WARNINGS>",
362
+ ]
363
+ prompt = "\n".join(prompt_lines)
364
+ prompt = self.append_additional_notes(prompt)
365
+
366
+ # 修复前执行 cargo fmt
367
+ run_cargo_fmt(crate)
368
+
369
+ # 记录运行前的 commit id
370
+ commit_before = self.progress_manager.get_crate_commit_hash()
371
+
372
+ # CodeAgent 在 crate 目录下创建和执行
373
+ agent = CodeAgent(
374
+ name=f"ClippyWarningEliminator-iter{iteration}",
375
+ need_summary=False,
376
+ non_interactive=self.options.non_interactive,
377
+ model_group=self.options.llm_group,
378
+ enable_task_list_manager=False,
379
+ disable_review=True,
380
+ )
381
+ # 订阅 BEFORE_TOOL_CALL 和 AFTER_TOOL_CALL 事件,用于细粒度检测测试代码删除
382
+ agent.event_bus.subscribe(
383
+ BEFORE_TOOL_CALL, self.progress_manager.on_before_tool_call
384
+ )
385
+ agent.event_bus.subscribe(
386
+ AFTER_TOOL_CALL, self.progress_manager.on_after_tool_call
387
+ )
388
+ # 记录 Agent 创建时的 commit id(作为初始值)
389
+ agent_id = id(agent)
390
+ agent_key = f"agent_{agent_id}"
391
+ initial_commit = self.progress_manager.get_crate_commit_hash()
392
+ if initial_commit:
393
+ self.progress_manager._agent_before_commits[agent_key] = (
394
+ initial_commit
395
+ )
396
+ agent.run(
397
+ prompt, prefix="[c2rust-optimizer][codeagent][clippy]", suffix=""
398
+ )
399
+
400
+ # 检测并处理测试代码删除
401
+ if self.progress_manager.check_and_handle_test_deletion(
402
+ commit_before, agent
403
+ ):
404
+ # 如果回退了,需要重新运行 agent
405
+ PrettyOutput.auto_print(
406
+ f"[c2rust-optimizer][codeagent][clippy] 检测到测试代码删除问题,已回退,重新运行 agent (iter={iteration})",
407
+ color="yellow",
408
+ )
409
+ commit_before = self.progress_manager.get_crate_commit_hash()
410
+ agent.run(
411
+ prompt,
412
+ prefix="[c2rust-optimizer][codeagent][clippy][retry]",
413
+ suffix="",
414
+ )
415
+ # 再次检测
416
+ if self.progress_manager.check_and_handle_test_deletion(
417
+ commit_before, agent
418
+ ):
419
+ PrettyOutput.auto_print(
420
+ f"[c2rust-optimizer][codeagent][clippy] 再次检测到测试代码删除问题,已回退 (iter={iteration})",
421
+ color="red",
422
+ )
423
+
424
+ # 验证修复是否成功(通过 cargo test)
425
+ ok, _ = cargo_check_full(
426
+ crate,
427
+ self.stats,
428
+ self.options.max_checks,
429
+ timeout=self.options.cargo_test_timeout,
430
+ )
431
+ if ok:
432
+ # 修复成功,保存进度和 commit id
433
+ try:
434
+ # 确保 target_file_path 是 Path 对象
435
+ target_file_path_obj = Path(target_file_path)
436
+ file_path_to_save: Path = (
437
+ crate / target_file_path_obj
438
+ if not target_file_path_obj.is_absolute()
439
+ else target_file_path_obj
440
+ )
441
+ if file_path_to_save.exists():
442
+ self.progress_manager.save_fix_progress(
443
+ "clippy_elimination",
444
+ f"{target_file_path}-iter{iteration}",
445
+ [file_path_to_save],
446
+ )
447
+ else:
448
+ self.progress_manager.save_fix_progress(
449
+ "clippy_elimination",
450
+ f"{target_file_path}-iter{iteration}",
451
+ None,
452
+ )
453
+ except Exception:
454
+ self.progress_manager.save_fix_progress(
455
+ "clippy_elimination",
456
+ f"{target_file_path}-iter{iteration}",
457
+ None,
458
+ )
459
+ PrettyOutput.auto_print(
460
+ f"[c2rust-optimizer][codeagent][clippy] 文件 {target_file_path} 的前 {warning_count} 个告警修复成功,已保存进度",
461
+ color="green",
462
+ )
463
+ else:
464
+ # 测试失败,回退到运行前的 commit
465
+ if commit_before:
466
+ PrettyOutput.auto_print(
467
+ f"[c2rust-optimizer][codeagent][clippy] 文件 {target_file_path} 修复后测试失败,回退到运行前的 commit: {commit_before[:8]}",
468
+ color="yellow",
469
+ )
470
+ if self.progress_manager.reset_to_commit(commit_before):
471
+ PrettyOutput.auto_print(
472
+ f"[c2rust-optimizer][codeagent][clippy] 已成功回退到 commit: {commit_before[:8]}",
473
+ color="cyan",
474
+ )
475
+ else:
476
+ PrettyOutput.auto_print(
477
+ "[c2rust-optimizer][codeagent][clippy] 回退失败,请手动检查代码状态",
478
+ color="red",
479
+ )
480
+ else:
481
+ PrettyOutput.auto_print(
482
+ f"[c2rust-optimizer][codeagent][clippy] 文件 {target_file_path} 修复后测试失败,但无法获取运行前的 commit,继续修复",
483
+ color="yellow",
484
+ )
485
+
486
+ # 修复后再次检查告警,如果告警数量没有减少,可能需要停止
487
+ has_warnings_after, _ = check_clippy_warnings(crate)
488
+ if not has_warnings_after:
489
+ PrettyOutput.auto_print(
490
+ f"[c2rust-optimizer][codeagent][clippy] 所有告警已消除(共迭代 {iteration} 次)",
491
+ color="green",
492
+ )
493
+ return True # 所有告警已消除
494
+ finally:
495
+ os.chdir(prev_cwd)
496
+
497
+ def extract_warnings_by_file(
498
+ self, clippy_json_output: str
499
+ ) -> Dict[str, List[Dict]]:
500
+ """
501
+ 从 clippy JSON 输出中提取所有告警并按文件分组。
502
+
503
+ Returns:
504
+ 字典,键为文件路径,值为该文件的告警列表
505
+ """
506
+ if not clippy_json_output:
507
+ return {}
508
+
509
+ warnings_by_file: Dict[str, List[Dict]] = {}
510
+
511
+ for line in clippy_json_output.splitlines():
512
+ line = line.strip()
513
+ if not line:
514
+ continue
515
+ try:
516
+ msg = json.loads(line)
517
+ # 只处理 warning 类型的消息
518
+ if (
519
+ msg.get("reason") == "compiler-message"
520
+ and msg.get("message", {}).get("level") == "warning"
521
+ ):
522
+ message = msg.get("message", {})
523
+ spans = message.get("spans", [])
524
+ if spans:
525
+ primary_span = spans[0]
526
+ file_path = primary_span.get("file_name", "")
527
+ if file_path:
528
+ if file_path not in warnings_by_file:
529
+ warnings_by_file[file_path] = []
530
+ warnings_by_file[file_path].append(msg)
531
+ except (json.JSONDecodeError, KeyError, TypeError):
532
+ continue
533
+
534
+ return warnings_by_file
535
+
536
+ def format_warnings_for_prompt(
537
+ self, warnings: List[Dict], max_count: int = 10
538
+ ) -> str:
539
+ """
540
+ 格式化告警列表,用于提示词。
541
+
542
+ Args:
543
+ warnings: 告警消息列表
544
+ max_count: 最多格式化多少个告警(默认10个)
545
+
546
+ Returns:
547
+ 格式化后的告警信息字符串
548
+ """
549
+ if not warnings:
550
+ return ""
551
+
552
+ # 只取前 max_count 个告警
553
+ warnings_to_format = warnings[:max_count]
554
+ formatted_warnings = []
555
+
556
+ for idx, warning_msg in enumerate(warnings_to_format, 1):
557
+ message = warning_msg.get("message", {})
558
+ spans = message.get("spans", [])
559
+
560
+ warning_parts = [f"告警 {idx}:"]
561
+
562
+ # 警告类型和消息
563
+ code = message.get("code", {})
564
+ code_str = code.get("code", "") if code else ""
565
+ message_text = message.get("message", "")
566
+ warning_parts.append(f" 警告类型: {code_str}")
567
+ warning_parts.append(f" 消息: {message_text}")
568
+
569
+ # 文件位置
570
+ if spans:
571
+ primary_span = spans[0]
572
+ line_start = primary_span.get("line_start", 0)
573
+ column_start = primary_span.get("column_start", 0)
574
+ line_end = primary_span.get("line_end", 0)
575
+ column_end = primary_span.get("column_end", 0)
576
+
577
+ if line_start == line_end:
578
+ warning_parts.append(
579
+ f" 位置: {line_start}:{column_start}-{column_end}"
580
+ )
581
+ else:
582
+ warning_parts.append(
583
+ f" 位置: {line_start}:{column_start} - {line_end}:{column_end}"
584
+ )
585
+
586
+ # 代码片段
587
+ label = primary_span.get("label", "")
588
+ if label:
589
+ warning_parts.append(f" 代码: {label}")
590
+
591
+ # 建议(help 消息)
592
+ children = message.get("children", [])
593
+ for child in children:
594
+ if child.get("level") == "help":
595
+ help_message = child.get("message", "")
596
+ help_spans = child.get("spans", [])
597
+ if help_message:
598
+ warning_parts.append(f" 建议: {help_message}")
599
+ if help_spans:
600
+ help_span = help_spans[0]
601
+ help_label = help_span.get("label", "")
602
+ if help_label:
603
+ warning_parts.append(f" 建议代码: {help_label}")
604
+
605
+ formatted_warnings.append("\n".join(warning_parts))
606
+
607
+ if len(warnings) > max_count:
608
+ formatted_warnings.append(
609
+ f"\n(该文件还有 {len(warnings) - max_count} 个告警,将在后续迭代中处理)"
610
+ )
611
+
612
+ return "\n\n".join(formatted_warnings)
613
+
614
+ def handle_clippy_after_auto_fix(
615
+ self, clippy_targets: List[Path], clippy_output: str
616
+ ) -> bool:
617
+ """
618
+ 处理自动修复后的 clippy 告警检查。
619
+ 如果仍有告警,使用 CodeAgent 继续修复。
620
+
621
+ Args:
622
+ clippy_targets: 目标文件列表
623
+ clippy_output: 当前的 clippy 输出
624
+
625
+ Returns:
626
+ True: 所有告警已消除
627
+ False: 仍有告警未消除(步骤未完成)
628
+ """
629
+ PrettyOutput.auto_print(
630
+ "[c2rust-optimizer] 自动修复后仍有告警,继续使用 CodeAgent 修复...",
631
+ color="cyan",
632
+ )
633
+ all_warnings_eliminated = self.codeagent_eliminate_clippy_warnings(
634
+ clippy_targets, clippy_output
635
+ )
636
+
637
+ # 验证修复后是否还有告警
638
+ if not self.verify_and_fix_after_step("clippy_elimination", clippy_targets):
639
+ return False
640
+
641
+ # 再次检查是否还有告警
642
+ has_warnings_after, _ = check_clippy_warnings(self.crate_dir)
643
+ if not has_warnings_after and all_warnings_eliminated:
644
+ PrettyOutput.auto_print(
645
+ "[c2rust-optimizer] Clippy 告警已全部消除", color="green"
646
+ )
647
+ self.progress_manager.save_step_progress(
648
+ "clippy_elimination", clippy_targets
649
+ )
650
+ return True
651
+ else:
652
+ PrettyOutput.auto_print(
653
+ "[c2rust-optimizer] 仍有部分 Clippy 告警无法自动消除,步骤未完成,停止后续优化步骤",
654
+ color="yellow",
655
+ )
656
+ return False
657
+
658
+ def run_clippy_elimination_step(self) -> bool:
659
+ """
660
+ 执行 Clippy 告警修复步骤(第 0 步)。
661
+
662
+ Returns:
663
+ True: 步骤完成(无告警或已修复)
664
+ False: 步骤未完成(仍有告警未修复,应停止后续步骤)
665
+ """
666
+ if self.options.dry_run:
667
+ return True
668
+
669
+ PrettyOutput.auto_print(
670
+ "🔍 [c2rust-optimizer] 检查 Clippy 告警...", color="cyan"
671
+ )
672
+ has_warnings, clippy_output = check_clippy_warnings(self.crate_dir)
673
+
674
+ # 如果步骤已标记为完成,但仍有告警,说明之前的完成标记是错误的,需要清除
675
+ if (
676
+ "clippy_elimination" in self.progress_manager.steps_completed
677
+ and has_warnings
678
+ ):
679
+ PrettyOutput.auto_print(
680
+ "[c2rust-optimizer] 检测到步骤已标记为完成,但仍有 Clippy 告警,清除完成标记并继续修复",
681
+ color="yellow",
682
+ )
683
+ self.progress_manager.steps_completed.discard("clippy_elimination")
684
+ if "clippy_elimination" in self.progress_manager._step_commits:
685
+ del self.progress_manager._step_commits["clippy_elimination"]
686
+
687
+ if not has_warnings:
688
+ PrettyOutput.auto_print(
689
+ "[c2rust-optimizer] 未发现 Clippy 告警,跳过消除步骤",
690
+ color="cyan",
691
+ )
692
+ # 如果没有告警,标记 clippy_elimination 为完成(跳过状态)
693
+ if "clippy_elimination" not in self.progress_manager.steps_completed:
694
+ clippy_targets = list(iter_rust_files(self.crate_dir))
695
+ if clippy_targets:
696
+ self.progress_manager.save_step_progress(
697
+ "clippy_elimination", clippy_targets
698
+ )
699
+ return True
700
+
701
+ # 有告警,需要修复
702
+ PrettyOutput.auto_print(
703
+ "\n[c2rust-optimizer] 第 0 步:消除 Clippy 告警(必须完成此步骤才能继续其他优化)",
704
+ color="magenta",
705
+ )
706
+ self.progress_manager.snapshot_commit()
707
+
708
+ clippy_targets = list(iter_rust_files(self.crate_dir))
709
+ if not clippy_targets:
710
+ PrettyOutput.auto_print(
711
+ "[c2rust-optimizer] 警告:未找到任何 Rust 文件,无法修复 Clippy 告警",
712
+ color="yellow",
713
+ )
714
+ return False
715
+
716
+ # 先尝试使用 clippy --fix 自动修复
717
+ auto_fix_success = self.try_clippy_auto_fix()
718
+ if auto_fix_success:
719
+ PrettyOutput.auto_print(
720
+ "[c2rust-optimizer] clippy 自动修复成功,继续检查是否还有告警...",
721
+ color="green",
722
+ )
723
+ # 重新检查告警
724
+ has_warnings, clippy_output = check_clippy_warnings(self.crate_dir)
725
+ if not has_warnings:
726
+ PrettyOutput.auto_print(
727
+ "[c2rust-optimizer] 所有 Clippy 告警已通过自动修复消除",
728
+ color="green",
729
+ )
730
+ self.progress_manager.save_step_progress(
731
+ "clippy_elimination", clippy_targets
732
+ )
733
+ return True
734
+ else:
735
+ # 仍有告警,使用 CodeAgent 继续修复
736
+ return self.handle_clippy_after_auto_fix(clippy_targets, clippy_output)
737
+ else:
738
+ # 自动修复失败或未执行,继续使用 CodeAgent 修复
739
+ PrettyOutput.auto_print(
740
+ "[c2rust-optimizer] clippy 自动修复未成功,继续使用 CodeAgent 修复...",
741
+ color="cyan",
742
+ )
743
+ all_warnings_eliminated = self.codeagent_eliminate_clippy_warnings(
744
+ clippy_targets, clippy_output
745
+ )
746
+
747
+ # 验证修复后是否还有告警
748
+ if not self.verify_and_fix_after_step("clippy_elimination", clippy_targets):
749
+ return False
750
+
751
+ # 再次检查是否还有告警
752
+ has_warnings_after, _ = check_clippy_warnings(self.crate_dir)
753
+ if not has_warnings_after and all_warnings_eliminated:
754
+ PrettyOutput.auto_print(
755
+ "[c2rust-optimizer] Clippy 告警已全部消除", color="green"
756
+ )
757
+ self.progress_manager.save_step_progress(
758
+ "clippy_elimination", clippy_targets
759
+ )
760
+ return True
761
+ else:
762
+ PrettyOutput.auto_print(
763
+ "[c2rust-optimizer] 仍有部分 Clippy 告警无法自动消除,步骤未完成,停止后续优化步骤",
764
+ color="yellow",
765
+ )
766
+ return False