2014-04-28 16 views
8

Jestem nowy w Perlu, a obecnie mam za zadanie porządkowanie i utrzymywanie dużego i dość niechlujnego projektu Perla. Używam perl-krytyka, aby pomóc mi wykryć problemy w kodzie (a także nauczyć mnie najlepszych praktyk).Jak wykryć nieosiągalny kod w warunku Perla, który zawsze jest fałszywy?

Istniejący kod zawiera miejsca, w których programista utworzył nieosiągalny kod. Na przykład, dodali „& & 0” jako leniwe sposób komentując niektóre z gałęzi kodu:

if ($req->param('donut') && 0) { 
    unreachable code... 
} else { 
    always branches to here... 
} 

Miałem nadzieję, że Perl lub Krytyk by ostrzec mnie martwy kod w takich przypadkach (gdzie wartość warunkowa ma stałą wartość, która jest wartością false), ale tak nie jest.

Czy istnieje narzędzie lub fragment skryptu, którego mogę użyć, który może niezawodnie wykryć tego rodzaju rzeczy?

Oczywiście mógłbym szukać „& & 0” w źródle, ale istnieje wiele sposobów, że koder mogły powstać martwy kod oprócz dołączanie „& & 0” do if.

Odpowiedz

9

Korzystanie B::Deparse, można wykryć martwy kod w niektórych sytuacjach:

perl -MO=Deparse -e 'if (0 && $x) {print 1} else {print 2}' 
do { 
    print 2 
}; 
-e syntax OK 

To nie jest tak łatwe, jeśli 0 nie jest pierwszy warunek, choć:

perl -MO=Deparse -e 'if ($x && 0) {print 1} else {print 2}' 
if ($x and 0) { 
    print 1; 
} 
else { 
    print 2; 
} 
-e syntax OK 

Dlaczego jest inaczej? Cóż, jeśli 0 jest ostatnim, wszystkie warunki przed nim muszą zostać sprawdzone. Mogą mieć skutki uboczne, które nadal będą występować. Ponadto, && wymusza kontekst skalarny, dzięki czemu może zmienić zachowanie kodu wywoływanego podczas oceniania warunku.

To nie wyjaśnia, dlaczego sam blok nie został skompilowany, przepraszam. Zgaduję, że to byłoby po prostu zbyt skomplikowane.

+0

+1 za poinformowanie mnie o B :: Deparse.Wprawdzie efekt uboczny pierwszej części warunku był dla mnie jasny (co oznacza, że ​​samo wyrażenie warunkowe nie może być skompilowane), nie zdawałem sobie sprawy ze zmiany kontekstu wprowadzonego przez drugą część warunkowego warunku. . –

5

Zgodnie z odpowiedzią choroby, B :: Deparse będzie w stanie pokazać ci przypadki, w których kod jest tak nieosiągalny, że kompilator Perla go optymalizuje. Ale w ogólnym przypadku nie można tego wykryć. Poniższy kod zawiera blok efektywnie nieosiągalny.

use 5.006; 

if ($] < 5) { ... } 

Ponieważ $] jest zmienną, która zwraca aktualnie uruchomionej wersji Perl, która jest zagwarantowana musi wynosić co najmniej 5,006 linią use. Ale potrzebujesz dość sprytnych technik, aby to zrozumieć za pomocą statycznej analizy kodu źródłowego. (Na marginesie, choć jest to rzecz niezwykła, można zmienić wartość $] w czasie wykonywania - patrz Acme::Futuristic::Perl - w takim przypadku kod stanie się osiągalny.)

Jeśli masz przyzwoity zestaw testowy Twój kod może być przydatny pod numerem Devel::Cover. Ustawiasz zmienną środowiskową PERL5OPT na -MDevel::Cover, a następnie uruchamiasz pakiet testowy (zauważ, że będzie działać nieco wolniej niż zwykle), a następnie uruchom polecenie cover, które wygeneruje ładny raport HTML. Ten raport podświetli, które subskrypcje nie zostały wykonane, które gałęzie nigdy nie były używane itd.