Dead Code Finder: Thực tế khắc nghiệt của Phân tích Tĩnh

Tôi đã xây dựng một công cụ cho một cuộc thi hackathon để tìm mã nguồn chết (dead code). Mục tiêu rất đơn giản: Tìm những đoạn mã mà không có gì gọi đến.

Tôi không muốn biết điều gì sẽ bị hỏng nếu bạn xóa mã. Tôi muốn biết liệu có bất kỳ thứ gì thực sự gọi đến một đoạn mã cụ thể hay không.

Tôi gọi nó là Dead Code Finder. Nó sử dụng một đồ thị tri thức (knowledge graph) để tìm kiếm các lời gọi (calls) và các lệnh import. Nó phân loại mọi kết quả tìm thấy vào ba nhóm:

• Tự tin (Confident): Không có cạnh đến (incoming edges) nào và không phải là điểm bắt đầu (entry point). • Không chắc chắn (Uncertain): Các trường hợp như kế thừa (inheritance) mà phân tích tĩnh là không đủ. • Bỏ qua (Skipped): Những thứ như decorator hoặc các framework kiểm thử mà công cụ không thể giải quyết được.

Tôi đã tuân theo một quy tắc nghiêm ngặt: Không bao giờ khẳng định mã nguồn an toàn để xóa. Bản báo cáo chỉ nói rằng không tìm thấy tham chiếu nào trong đồ thị.

Dự án này khó hơn tôi tưởng. Tôi đã gặp phải hai vấn đề chính với nền tảng:

  1. Thiếu công cụ: Các công cụ đồ thị bị thiếu trong quá trình thực thi (runtime) mặc dù chúng đã có trong cấu hình (config).
  2. Injection không đáng tin cậy: Hệ thống đôi khi không cung cấp đầy đủ logic cho agent.

Tôi đã khắc phục điều này bằng cách xây dựng một chế độ dự phòng (fallback mode). Nếu các công cụ đồ thị bị thiếu, công cụ sẽ đọc các tệp thực tế trong kho lưu trữ (repository). Nó sử dụng việc tìm kiếm tệp để tìm các tham chiếu. Nếu sử dụng phương pháp này, nó sẽ đánh dấu các kết quả tìm thấy là "được suy luận" (inferred).

Tôi cũng phải sửa các lỗi logic cho các trường hợp cụ thể:

  • Các phương thức dunder: Các phương thức như __init__ thường hiển thị không có cạnh đến nào vì đồ thị liên kết lời gọi với lớp (class) thay vì phương thức. Tôi đã khắc phục điều này bằng cách kiểm tra lớp bao quanh (enclosing class).
  • Decorators: Các hàm được gọi thông qua việc tra cứu chuỗi trong một dictionary sẽ trông như mã chết đối với một đồ thị tĩnh. Tôi đã chuyển chúng vào nhóm Bỏ qua (Skipped).
  • Kiểm thử (Tests): Các framework kiểm thử tìm thấy các phương thức thông qua reflection. Những trường hợp này cũng được đưa vào nhóm Bỏ qua (Skipped).

Kết quả rất đáng tin cậy. Chế độ dự phòng của tôi đã xác định chính xác mã chết và khớp với dữ liệu đồ thị thực tế. Nó cũng dán nhãn chính xác các trường hợp không chắc chắn như kế thừa.

Bài học rút ra:

  • Xác nhận các công cụ có sẵn trước khi viết logic phụ thuộc vào chúng.
  • Một bản báo cáo nói "Tôi không biết" sẽ tốt hơn một bản báo cáo sai lầm một cách đầy tự tin.
  • Việc dán nhãn sự không chắc chắn giúp các kết quả tìm thấy một cách tự tin của bạn trở nên đáng để thực hiện hành động.

Nguồn: https://dev.to/hereforlolz/dead-code-finder-gitlab-orbit-based-static-analysis-that-turned-out-to-be-harder-than-expected-4jgk

Cộng đồng học tập tùy chọn: https://t.me/GyaanSetuAi