Dead Code Finder: Trudna rzeczywistość analizy statycznej

Zbudowałem narzędzie na hackathon, aby znajdować martwy kod. Cel był prosty: znaleźć kod, którego nikt nie wywołuje.

Nie chciałem wiedzieć, co się popsuje po usunięciu kodu. Chciałem wiedzieć, czy jakakolwiek część kodu w ogóle wywołuje dany fragment.

Nazwałem je Dead Code Finder. Narzędzie wykorzystuje graf wiedzy do wyszukiwania wywołań i importów. Każde znalezisko sortuje do trzech kategorii:

• Pewne (Confident): Zero krawędzi przychodzących i nie jest to punkt wejścia. • Niepewne (Uncertain): Przypadki takie jak dziedziczenie, gdzie analiza statyczna jest niewystarczająca. • Pominięte (Skipped): Elementy takie jak dekoratory czy frameworki testowe, których narzędzie nie potrafi rozstrzygnąć.

Trzymałem się jednej surowej zasady: nigdy nie twierdzić, że kod można bezpiecznie usunąć. Raport informuje jedynie, że w grafie nie znaleziono żadnego odniesienia.

Projekt okazał się trudniejszy, niż się spodziewałem. Napotkałem dwa główne problemy z platformą:

  1. Brakujące narzędzia: Narzędzia grafowe nie były dostępne podczas działania programu, mimo że znajdowały się w konfiguracji.
  2. Niestabilna iniekcja: System czasami nie dostarczał pełnej logiki dla agenta.

Rozwiązałem to, budując tryb fallback. Jeśli narzędzia grafowe są niedostępne, narzędzie czyta rzeczywiste pliki w repozytorium. Wykorzystuje przeszukiwanie plików, aby znaleźć odniesienia. Jeśli używa tej metody, oznacza znaleziska jako wywnioskowane (inferred).

Musiałem również naprawić błędy logiczne w konkretnych przypadkach:

  • Metody dunder: Metody takie jak __init__ często wykazują zero krawędzi przychodzących, ponieważ graf łączy wywołanie z klasą, a nie z metodą. Naprawiłem to, sprawdzając klasę otaczającą.
  • Dekoratory: Funkcje wywoływane poprzez wyszukiwanie ciągów znaków w słowniku wydają się martwe dla statycznego grafu. Przeniosłem je do kategorii Skipped.
  • Testy: Frameworki testowe znajdują metody poprzez refleksję. One również trafiają do kategorii Skipped.

Wyniki były wiarygodne. Mój tryb fallback poprawnie identyfikował martwy kod i zgadzał się z rzeczywistymi danymi z grafu. Poprawnie oznaczał również przypadki niepewne, takie jak dziedziczenie.

Wyciągnięte wnioski:

  • Potwierdź dostępność narzędzi przed pisaniem logiki, która od nich zależy.
  • Raport, który mówi „nie wiem”, jest lepszy niż raport, który jest pewny siebie, ale błędny.
  • Oznaczanie niepewności sprawia, że Twoje pewne znaleziska są warte podjęcia działań.

Źródło: https://dev.to/hereforlolz/dead-code-finder-gitlab-orbit-based-static-analysis-that-turned-out-to-be-harder-than-expected-4jgk

Opcjonalna społeczność edukacyjna: https://t.me/GyaanSetuAi