Koddaki hangi parçaların hiç kullanılmadığını nasıl bilebilirim?


312

Kullanılmayan kodu kaldırmak gerekiyordu eski C ++ kodu var. Sorun kod tabanı büyük olmasıdır.

Hangi kodun asla çağrılmadığını / asla kullanılmadığını nasıl öğrenebilirim?


4
Ben bir kod sorgu dili size bir bütün olarak proje daha iyi bir görünüm verecektir düşünüyorum. C ++ dünya hakkında emin değilim ama yeterince iyi görünüyor cppdepend.com (bu ücretsiz değil) gibi görünüyor. Bunun gibi bir şey ücretsiz olarak mevcut olabilir. Başka bir şey, yeniden düzenleme yapmadan önce, şu anda sahip değilseniz, akılcı şey, birim testleri yapmak olacaktır. Birim testleri ile yapabileceğiniz kod kapsamı araçlarınızın kodunuzu oluşturmasıdır, bu kodun içinde yer alamazsanız kendi içinde ölü kodun kaldırılmasına yardımcı olacaktır.
Biswanath

3
Buradaki referansa göz atın: en.wikipedia.org/wiki/Unreachable_code
Martin York

6
Benzer bir konu buluyorum. stackoverflow.com/questions/229069/…
UmmaGumma

3
Evet, C ++'ın komik şeylerinden biri, "kullanılmayan" işlevlerin kaldırılmasının yine de bir programın sonucunu değiştirebilmesidir.
MSalters

1
@MSalters: Bu ilginç bir şey ... Bunun için, belirli bir çağrı için aşırı yük setinde hangi fonksiyonun seçildiğinden bahsetmeliyiz, değil mi? 2 de adı işlevlerini varsa Bildiğim kadarıyla, f()ve bir çağrı f()1'ine açık bir biçimde giderir, sonra sadece adında bir 3 fonksiyonu ekleyerek 2. o çağrı kararlılığını yapmak mümkün değildir f()- "Yapabileceğiniz en kötü "3. işlevi ekleyerek çağrının belirsizleşmesine neden olmak ve böylece programın derlenmesini önlemektir. Karşı bir örnek görmek isterdim (= dehşete düşecek).
j_random_hacker

Yanıtlar:


197

Kullanılmayan iki tür kod vardır:

  • yerel olan, yani bazı işlevlerde bazı yollar veya değişkenler kullanılmaz (veya kullanılır, ancak yazılı olarak değil asla okunmaz gibi anlamlı bir şekilde)
  • küresel olan: asla çağrılmayan fonksiyonlar, asla erişilmeyen global nesneler

İlk olarak, iyi bir derleyici yardımcı olabilir:

  • -Wunused (GCC Clang ) kullanılmayan değişkenler hakkında uyarmalıdır, Clang kullanılmayan analizörü (hiç kullanılmasa bile) hiç okunmayan değişkenler hakkında uyarmak için bile artırılmıştır.
  • -Wunreachable-code (eski GCC, 2010'da kaldırılan ), hiçbir zaman erişilmeyen yerel bloklar hakkında uyarmalıdır (erken iade veya her zaman doğru olarak değerlendirilen koşullarla olur)
  • kullanılmayan catchbloklar hakkında uyarmak için bildiğim bir seçenek yoktur , çünkü derleyici genellikle bir istisna yapılmayacağını kanıtlayamaz.

İkinci tür için, çok daha zor. Statik olarak tüm program analizi gerektirir ve bağlantı süresi optimizasyonu gerçekte ölü kodu kaldırabilse de, uygulama gerçekleştirildiğinde program o kadar çok dönüşmüştür ki, kullanıcıya anlamlı bilgiler iletmek neredeyse imkansızdır.

Bu nedenle iki yaklaşım vardır:

  • Teorik olan statik bir analiz cihazı kullanmaktır. Tüm kodu bir kerede ayrıntılı olarak inceleyip tüm akış yollarını bulan bir yazılım. Uygulamada burada işe yarayacak hiçbir şey bilmiyorum.
  • Pragmatik olan bir buluşsal yöntem kullanmaktır: bir kod kapsama aracı kullanın (GNU zincirinde gcov. Düzgün çalışması için derleme sırasında belirli bayrakların geçirilmesi gerektiğini unutmayın). Kod kapsama aracını çeşitli girişlerle (birim testleriniz veya regresyon olmayan testleriniz) çalıştırırsınız, ölü kod mutlaka erişilmemiş kodun içindedir ... ve buradan başlayabilirsiniz.

Konu ile son derece ilgileniyorsanız ve aslında bir aracı kendiniz çözmek için zamanınız ve eğiliminiz varsa, böyle bir araç oluşturmak için Clang kütüphanelerini kullanmanızı öneririm.

  1. Bir AST (soyut sözdizimi ağacı) almak için Clang kütüphanesini kullanın
  2. Giriş noktalarından itibaren işaretleme ve süpürme analizi yapın

Clang kodu sizin için ayrıştıracağından ve aşırı yük çözünürlüğü gerçekleştireceğinden, C ++ dil kuralları ile uğraşmanıza gerek kalmayacak ve eldeki soruna konsantre olabileceksiniz.

Bununla birlikte, bu tür bir teknik kullanılmayan sanal geçersiz kılmaları tanımlayamaz, çünkü bunlar aklınıza gelemeyecek üçüncü taraf koduyla çağrılabilir.


7
Çok güzel +1. Statik hiçbir koşulda asla çalışmaya karar verilebilir kod ve belirli bir çalışma çalışmaz, ancak potansiyel olarak olabilir arasındaki kodu ayırmak gibi. Birincisi bence önemli ve tüm programın AST'sini kullanarak ulaşılabilirlik analizi bunu elde etmenin yoludur. ( foo()Sadece göründüğünde "çağrılmış" olarak işaretlenmesini önlemek if (0) { foo(); }bir bonus olur, ancak fazladan akıllı gerektirir.)
j_random_hacker

@j_random_hacker: belki de CFG (Kontrol-Akış Grafiği) kullanmanın şimdi düşündüğümden daha iyi olacağını düşünüyorum (örneğiniz sayesinde). Clang'ın bahsettiğiniz gibi totolojik karşılaştırmalardan bahsetmeye istekli olduğunu biliyorum ve bu nedenle CFG'yi kullanarak muhtemelen ölü kodu erken tespit edebiliriz.
Matthieu M.

@Matthieu: Evet, CFG de AST yerine demek istediğim şeydir :) Demek istediğim: köşelerin fonksiyonlar olduğu ve x fonksiyonunun y fonksiyonunu y olarak tanımlayabildiği bir x kenarı vardır. (Ve aşırı yüklenmiş fonksiyonların hepsi farklı köşeler tarafından temsil edilen önemli özelliğe sahip - Clang sizin için yapar gibi sesler, vay!)
j_random_hacker

1
@j_random_hacker: aslında CFG, basit bir digrafiden daha karmaşıktır, çünkü koşullu ifadelere dayanarak bir bloktan diğerine bağlantıları olan bloklarda yürütülecek tüm kodu temsil eder. Ana avantajı, statik olarak ölü olarak tespit edilebilen budama koduna doğal olarak uygun olmasıdır (tanımlanabilecek ulaşılamaz bloklar oluşturur), bu nedenle, digramı oluşturmak için CFG'yi AST'den daha iyi kullanmak daha iyidir. ... hakkında düşünüyorum ...
Matthieu M.

1
@j_random_hacker: aslında Clang'ın AST'si her şeyi açık yapıyor (ya da neredeyse ...) çünkü kod ile çalışmak, sadece derlemek için değil. Aslında şu anda bir tartışma var, çünkü görünüşe göre AST'de böyle bir örtük dönüşümün görünmediği başlatıcı listelerinde bir sorun var, ancak sanırım düzeltilecek.
Matthieu M.27

35

Kullanılmayan tüm fonksiyonlar (ve kullanılmayan global değişkenler) söz konusu olduğunda, GCC ve GNU ld kullanmanız koşuluyla GCC sizin için çoğu işi yapabilir.

Kaynak derlenirken, -ffunction-sectionsve -fdata-sectionsdüğmelerini kullanın -Wl,--gc-sections,--print-gc-sections. Bağlayıcı, artık çağrılmadığı için kaldırılabilecek tüm işlevleri ve hiç başvurulmayan tüm globalleri listeleyecektir.

(Tabii ki, --print-gc-sectionsparçayı atlayabilir ve bağlayıcının işlevleri sessizce kaldırmasına izin verebilirsiniz , ancak bunları kaynakta saklayabilirsiniz.)

Not: Bu sadece kullanılmayan tam fonksiyonları bulur, fonksiyonlar içinde ölü kod hakkında hiçbir şey yapmaz. Canlı işlevlerde ölü koddan çağrılan işlevler de korunacaktır.

C ++ 'a özgü bazı özellikler de sorunlara neden olur, özellikle:

  • Sanal fonksiyonlar. Hangi alt sınıfların var olduğunu ve hangilerinin çalışma zamanında başlatıldığını bilmeden, son programda hangi sanal işlevlerin var olması gerektiğini bilemezsiniz. Bağlayıcı bu konuda yeterli bilgiye sahip olmadığından, hepsini saklamak zorunda kalacak.
  • Kurucuları olan küreseller ve kurucuları. Genel olarak, bağlayıcı bir global için yapıcısının yan etkileri olmadığını bilemez, bu yüzden onu çalıştırmalıdır. Açıkçası bu, küresel olanın da tutulması gerektiği anlamına gelir.

Her iki durumda da, sanal bir işlev veya global değişken bir kurucu tarafından kullanılan her şey de saklanmalıdır.

Ek bir uyarı, paylaşılan bir kitaplık oluşturuyorsanız, GCC'deki varsayılan ayarların paylaşılan kitaplıktaki her işlevi dışa aktararak bağlayıcıyla ilgili olarak "kullanılmasına" neden olmasıdır. Bunu düzeltmek için varsayılanı dışa aktarma (örn. Kullanarak -fvisibility=hidden) yerine gizleme olarak ayarlamanız ve ardından dışa aktarmanız gereken dışa aktarılan işlevleri açıkça seçmeniz gerekir.


Büyük pratik tavsiyeler. Sadece herhangi bir yerde kullanılmadığı bilinen işlevlerin bir listesini almak (söylediğiniz gibi, bu liste tam olmasa bile) bence çok asılı olan meyvelerin çoğunu alacaktır.
j_random_hacker

Bunların hiçbirinin örneklenmemiş şablonlar için geçerli olduğunu düşünmüyorum .
Jakub Klinkovský

25

Eğer g ++ kullanıyorsanız bu bayrağı kullanabilirsiniz -Wunused

Belgelere göre:

Bir değişken, bildirimi dışında kullanılmadığında, bir işlev statik olarak bildirildiğinde, ancak hiçbir zaman tanımlanmadığında, bir etiket bildirildiğinde, ancak kullanılmadığında ve bir ifade açıkça kullanılmayan bir sonucu hesapladığında uyar.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

Düzenleme : İşte diğer yararlı bayrak -Wunreachable-code Belgelere göre:

Bu seçenek, derleyici en azından tüm kaynak kod satırının hiçbir zaman yürütülmeyeceğini algıladığında uyarılmalıdır, çünkü bazı koşullar hiçbir zaman karşılanmaz veya asla geri dönmeyen bir yordamdan sonradır.

Güncelleme : Benzer konuyu buldum Eski C / C ++ projesinde ölü kod tespiti


4
Bu, hiçbir zaman çağrılmayan prototip işlevleri üstbilgileri yakalamaz. Ya da çağrılmayan genel sınıf yöntemleri. Yalnızca bu kapsamda yerel olarak kapsamlandırılmış değişkenlerin kullanılıp kullanılmadığını kontrol edebilir.
Falmarri

@Falmarri Bu bayrağı hiç kullanmadım. Kendimle ne tür ölü kodlar bulabileceğimi anlamaya çalışıyorum.
UmmaGumma

-Wunusedbildirilen (veya tek seferde bildirilen ve tanımlanan) ancak aslında hiç kullanılmayan değişkenler hakkında uyarır. Bu arada kapsamlı korumalarla oldukça sinir bozucu: p Clang'da, yazılan ancak hiç okunmayan uçucu olmayan değişkenler için de uyarılması için deneysel bir uygulama var (Ted Kremenek tarafından). -Wunreachable-codeulaşılamazsa bir işlev içinde kod hakkında uyarır, bir sonra yer kod olabilir throwveya returnörneğin (totolojik karşılaştırmalar durumunda olur) almamış olan bir dalda açıklamada veya kod.
Matthieu M.

18

Bence bir kod kapsama aracı arıyorsunuz . Bir kod kapsamı aracı, kodunuzu çalışırken analiz eder ve hangi kod satırlarının yürütüldüğünü ve kaç kez ve hangilerinin yürütülmediğini size bildirir.

Bu açık kaynak kod kapsama aracına bir şans vermeyi deneyebilirsiniz: TestCocoon - C / C ++ ve C # için kod kapsama aracı.


7
Buradaki anahtar "çalışıyor gibi" dir - giriş verileriniz bazı kod yollarını kullanmazsa bu yol kullanılmış olarak algılanmayacak mı?
sharptooth

1
Bu doğru. Kodu çalıştırmadan hangi satırlara ulaşılmadığını bilmenin bir yolu yoktur. Birkaç normal çalışmayı taklit etmek için bazı Birim Testleri kurmanın ne kadar zor olacağını merak ediyorum.
Carlos V

1
@drhishch Bence, bu tür kullanılmayan kod derleyici değil bağlayıcı bulmak gerekir.
UmmaGumma

1
@drhirsch Doğru, derleyici, bildirilen ancak çağrılmayan işlevler ve bazı kısa devre değerlendirmeleri gibi erişilemeyen bazı kodlarla ilgilenebilir, ancak kullanıcı eylemine veya çalışma zamanı değişkenlerine bağlı kod hakkında ne söylenebilir?
Carlos V

1
@golcarcol Tamam, void func()b.cpp'de kullanılan a.cpp işlevine sahip olalım. Derleyici programda kullanıldığını nasıl kontrol edebilir? Bağlayıcıların işi.
UmmaGumma

15

Buradaki asıl cevap: Asla kesin olarak bilemezsiniz.

En azından, önemsiz durumlarda, hepsini aldığınızdan emin olamazsınız. Wikipedia'nın ulaşılamaz kod hakkındaki makalesinde aşağıdakileri göz önünde bulundurun :

double x = sqrt(2);
if (x > 5)
{
  doStuff();
}

Wikipedia'nın doğru şekilde belirttiği gibi, akıllı bir derleyici böyle bir şeyi yakalayabilir. Ancak bir değişiklik düşünün:

int y;
cin >> y;
double x = sqrt((double)y);

if (x != 0 && x < 1)
{
  doStuff();
}

Derleyici bunu yakalayacak mı? Olabilir. Ancak bunu yapmak için, sqrtsabit bir skaler değere karşı çalıştırmaktan daha fazlasını yapması gerekecektir . Her (double)yzaman bir tamsayı (kolay) olacağını ve sonra sqrttamsayılar kümesinin (sert) matematiksel aralığını anlaması gerekecektir . Çok karmaşık bir derleyici bunu sqrtişlev için veya math.h dosyasındaki her işlev için veya etki alanını anlayabileceği herhangi bir sabit giriş işlevi için yapabilir. Bu çok, çok karmaşık hale gelir ve karmaşıklık temel olarak sınırsızdır. Derleyicinize gelişmişlik katmanları eklemeye devam edebilirsiniz, ancak her zaman belirli bir girdi kümesi için erişilemeyecek bazı kodlarda gizlice girmenin bir yolu olacaktır.

Ve daha sonra hiç girilmeyen girdi setleri var . Gerçek hayatta bir anlam ifade etmeyecek veya başka bir yerde doğrulama mantığı ile engellenecek girdiler. Derleyicinin bunları bilmesinin bir yolu yoktur.

Bunun sonucu, diğerlerinin bahsettiği yazılım araçları son derece yararlı olsa da, daha sonra kodu manuel olarak geçmedikçe her şeyi yakaladığınızdan emin olmayacaksınız. O zaman bile, hiçbir şeyi kaçırmadığınızdan asla emin olmayacaksınız.

Tek gerçek çözüm olan IMHO, olabildiğince uyanık olmak, emrinizde otomasyonu kullanmak, yapabileceğiniz yerlerde refactor kullanmak ve kodunuzu iyileştirmenin yollarını aramaktır. Tabii ki, yine de bunu yapmak iyi bir fikir.


1
Doğru ve ölü kodu bırakmayın! Bir özelliği kaldırırsanız, ölü kodu öldürün. "Her ihtimale karşı" orada bırakmak sadece (tartıştığınız gibi) daha sonra bulmak zor olan şişkinliğe neden olur. Sürüm kontrolü sizin için istifleme yapalım.
Yörüngedeki Hafiflik Yarışları

12

Ben kendim kullanmadım, ama cppcheck , kullanılmayan fonksiyonları bulduğunu iddia ediyor. Muhtemelen sorunun tamamını çözmeyecektir, ancak bir başlangıç ​​olabilir.


Evet, yerel başvurulmamış değişkenleri ve işlevi bulabilir.
Chugaister

Evet cppcheck --enable=unusedFunction --language=c++ .bu kullanılmayan işlevleri bulmak için kullanın .
Jason Harris

9

Gimple Software'den PC-lint / FlexeLint kullanmayı deneyebilirsiniz . İddia ediyor

tüm proje boyunca kullanılmayan makrolar, typedef'ler, sınıflar, üyeler, bildirimler vb. bulun

Statik analiz için kullandım ve çok iyi buldum ama özellikle ölü kodu bulmak için kullanmadığımı itiraf etmeliyim.


5

Kullanılmayan şeyleri bulma konusundaki normal yaklaşımım

  1. derleme sisteminin bağımlılık izlemeyi doğru şekilde işlediğinden emin olun
  2. tam ekran bir terminal penceresi ile ikinci bir monitör kurmak, tekrarlanan yapıları çalıştırmak ve ilk ekran çıkışını gösterir. watch "make 2>&1"Unix'te hile yapmaya eğilimlidir.
  3. her satırın başına "//?" ekleyerek kaynak ağacın tamamında bir bul ve değiştir işlemi gerçekleştirin
  4. derleyici tarafından işaretlenen ilk hatayı "//?" karşılık gelen satırlarda.
  5. Hata kalmayıncaya kadar tekrarlayın.

Bu biraz uzun bir süreçtir, ancak iyi sonuçlar verir.


2
Haklı ama çok emek yoğundur. Ayrıca, bir işlevin tüm aşırı yüklerini aynı anda açtığınızdan emin olmalısınız - birden fazla uygulanabilir varsa, daha az tercih edilen bir tanesinin kaldırılması derlemenin başarılı olmasına izin verebilir, ancak yanlış program davranışıyla sonuçlanabilir (ve işlevleri kullanılır).
j_random_hacker

Ben sadece ilk adımda (tüm aşırı yükler) ve bir sonraki yinelemede hangi açıklamaların eksik olduğunu görmek; bu şekilde hangi aşırı yüklerin gerçekten kullanıldığını görebiliyorum.
Simon Richter

@Simon: İlginç bir şekilde ana soru üzerine yapılan bir yorumda, MSalters, hiç çağrılmayan bir fonksiyon için bir deklarasyonun varlığının / yokluğunun bile, aşırı yük çözünürlüğü ile başka bir 2 fonksiyondan hangisinin bulunabileceğini etkileyebileceğine dikkat çekiyor. Kuşkusuz bu son derece tuhaf ve özenli bir kurulum gerektirir, bu yüzden pratikte bir sorun olması muhtemel değildir.
j_random_hacker

4

Derleme hatasına neden olmadan ortak işlevleri ve değişkenleri özel veya korumalı olarak işaretleyin, bunu yaparken de kodu yeniden düzenlemeyi deneyin. Özel ve bir dereceye kadar korumalı işlevler yaparak, özel işlevler yalnızca aynı sınıftan çağrılabileceğinden (erişim kısıtlamasını aşmak için aptal makro veya başka püf noktaları yoksa ve bu durumda size öneririm) arama alanınızı azaltmış olursunuz. yeni bir iş bul). Yalnızca şu anda üzerinde çalıştığınız sınıf bu işlevi çağırabildiğinden özel bir işleve ihtiyacınız olmadığını belirlemek çok daha kolaydır. Kod tabanınızın küçük sınıfları varsa ve gevşek bağlanmışsa bu yöntem daha kolaydır. Kod tabanınızın küçük sınıfları yoksa veya çok sıkı bir bağlantısı varsa, önce bunları temizlemenizi öneririm.

Daha sonra kalan tüm ortak fonksiyonları işaretlemek ve sınıflar arasındaki ilişkiyi anlamak için bir çağrı grafiği yapmak olacaktır. Bu ağaçtan, dalın hangi kısmının kesilebileceğini anlamaya çalışın.

Bu yöntemin avantajı, modül bazında yapabilmenizdir, bu nedenle, kod tabanınızı kırdığınızda uzun bir süre olmadan birim testinizi geçmeye devam etmek kolaydır.


3

Linux'taysanız, paketin bir callgrindparçası olan ve valgrindayrıca bellek sızıntılarını ve diğer bellek hatalarını (ayrıca kullanmanız gerekir) kontrol eden araçlar içeren bir C / C ++ program analiz aracına da bakmak isteyebilirsiniz . Programınızın çalışan bir örneğini analiz eder ve çağrı grafiği ve çağrı grafiğindeki düğümlerin performans maliyetleri hakkında veri üretir. Genellikle performans analizi için kullanılır, ancak uygulamalarınız için bir çağrı grafiği de üretir, böylece hangi işlevlerin yanı sıra arayanların da adlandırıldığını görebilirsiniz.

Bu açıkça sayfanın başka bir yerinde belirtilen statik yöntemleri tamamlayıcıdır ve sadece tamamen kullanılmayan sınıfları, yöntemleri ve işlevleri ortadan kaldırmak için yardımcı olacaktır - aslında çağrılan yöntemlerin içinde ölü kodu bulmanıza yardımcı olmaz.


3

Gerçekten böyle bir şey yapan herhangi bir araç kullanmadım ... Ancak, tüm cevaplarda gördüğüm kadarıyla, hiç kimse bu sorunun hesaplanamaz olduğunu söylemedi.

Bununla ne demek istiyorum? Bu sorun, bir bilgisayardaki herhangi bir algoritma ile çözülemez. Bu teorem (böyle bir algoritmanın mevcut olmadığı) Turing'in Durma Probleminin bir sonucudur.

Kullanacağınız tüm araçlar algoritma değil sezgisel tarama (tam algoritma değil). Size kullanılmayan tüm kodları vermeyeceklerdir.


1
Bence OP esas olarak hiçbir yerde çağrılmayan, kesinlikle hesaplanamayan işlevleri bulmak istiyor - çoğu modern bağlayıcı bunu yapabilir! Sadece bu bilgiyi en az acı ve angarya ile elde etme meselesi.
j_random_hacker

Haklısın, ana sorunun son yorumunu görmedim. Bu arada, gerçekte kullanılmayan kodda atıfta bulunulan fonksiyonlar olabilir. Bu tür şeyler tespit edilemeyebilir.
geekazoid

2

Bunun bir yolu, derleme sırasında kullanılmayan makine kodunu ortadan kaldırmak için bir hata ayıklayıcı ve derleyici özelliğini kullanmaktır.

Bazı makine kodları kaldırıldıktan sonra hata ayıklayıcı, kaynak kodun ilgili satırına bir kesme işareti koymanıza izin vermez. Böylece kesme noktalarını her yere koyar ve programı başlatır ve kesme noktalarını - "bu kaynak için kod yüklenmedi" durumunda olanları elenen koda karşılık gelir - ya bu kod hiçbir zaman çağrılmaz veya satır içine alınmaz ve bir miktar minimum işlem yapmanız gerekir. Bu ikisinden hangisinin olduğunu bulmak için analiz.

En azından Visual Studio'da bu şekilde çalışıyor ve sanırım diğer araç setleri de bunu yapabilir.

Bu çok iş, ama tüm kodu elle analiz daha hızlı sanırım.


4
Bence OP'nin sorusu kaynak kodun daha küçük, daha yönetilebilir bir alt kümesini nasıl bulacağımızla ilgili.
j_random_hacker

@j_random_hacker Ben bir verdim - ve kod ortadan kaldırılması bile orijinal kaynak koduna geri izlemek için kullanılabilir.
sharptooth

Bunu başarmak için görsel stüdyodaki bazı derleyici bayraklarına ihtiyacınız var mı? ve sadece serbest bırakma modunda mı çalışıyor yoksa hata ayıklamada da çalışır mı?
Naveen

Derleyici tarafından kullanılan ancak optimize edilen satırlar ne olacak?
Itamar Katz

@Naveen: Visual C ++ 9'da optimizasyonu açmanız ve kullanmanız gerekir / OPT: ICF
sharptooth

2

CppDepend kullanılmayan türleri, yöntemleri ve alanları tespit edebilen ve çok daha fazlasını yapabilen ticari bir araçtır. Windows ve Linux için kullanılabilir (ancak şu anda 64 bit desteği yoktur) ve 2 haftalık bir deneme sürümüyle birlikte gelir.

Yasal Uyarı: Orada çalışmıyor, ancak bu araç için bir lisans var (hem de NDepend , .NET kodu için daha güçlü bir alternatif).

Meraklılar için , CQLinq'de yazılmış ölü yöntemleri tespit etmek için yerleşik (özelleştirilebilir) bir örnek :

// <Name>Potentially dead Methods</Name>
warnif count > 0
// Filter procedure for methods that should'nt be considered as dead
let canMethodBeConsideredAsDeadProc = new Func<IMethod, bool>(
    m => !m.IsPublic &&       // Public methods might be used by client applications of your Projects.
         !m.IsEntryPoint &&            // Main() method is not used by-design.
         !m.IsClassConstructor &&      
         !m.IsVirtual &&               // Only check for non virtual method that are not seen as used in IL.
         !(m.IsConstructor &&          // Don't take account of protected ctor that might be call by a derived ctors.
           m.IsProtected) &&
         !m.IsGeneratedByCompiler
)

// Get methods unused
let methodsUnused = 
   from m in JustMyCode.Methods where 
   m.NbMethodsCallingMe == 0 && 
   canMethodBeConsideredAsDeadProc(m)
   select m

// Dead methods = methods used only by unused methods (recursive)
let deadMethodsMetric = methodsUnused.FillIterative(
   methods => // Unique loop, just to let a chance to build the hashset.
              from o in new[] { new object() }
              // Use a hashet to make Intersect calls much faster!
              let hashset = methods.ToHashSet()
              from m in codeBase.Application.Methods.UsedByAny(methods).Except(methods)
              where canMethodBeConsideredAsDeadProc(m) &&
                    // Select methods called only by methods already considered as dead
                    hashset.Intersect(m.MethodsCallingMe).Count() == m.NbMethodsCallingMe
              select m)

from m in JustMyCode.Methods.Intersect(deadMethodsMetric.DefinitionDomain)
select new { m, m.MethodsCallingMe, depth = deadMethodsMetric[m] }

Güncelleme: Sürüm 3.1'de 64 bit Linux desteği eklendi.
Roman Boiko

1

Uygulamanızı oluşturmak için kullandığınız platforma bağlıdır.

Örneğin, Visual Studio kullanıyorsanız , kodunuzu ayrıştırıp profil oluşturabilen .NET ANTS Profiler gibi bir araç kullanabilirsiniz . Bu şekilde, kodunuzun hangi bölümünün gerçekten kullanıldığını hızlıca bilmelisiniz. Eclipse'in eşdeğer eklentileri de var.

Aksi takdirde, uygulamanızın hangi işlevinin gerçekte son kullanıcınız tarafından kullanıldığını bilmeniz gerekiyorsa ve uygulamanızı kolayca serbest bırakabiliyorsanız, denetim için bir günlük dosyası kullanabilirsiniz.

Her ana işlev için kullanımını izleyebilir ve haftada birkaç gün sonra bu günlük dosyasını alabilir ve bir göz atabilirsiniz.


1
.net ANTS Profiler C # için görünüyor - C ++ için de çalıştığından emin misiniz?
j_random_hacker

@j_random_hacker: Bildiğim kadarıyla, yönetilen kod ile çalışır. Net ANTS kesinlikle 'standart' C ++ kodunu (yani gcc, ... ile derlenmiş) analiz edemeyecektir.
AUS

0

Otomatik olarak yapılabileceğini sanmıyorum.

Kod kapsama araçlarıyla bile, çalıştırmak için yeterli giriş verisi sağlamanız gerekir.

Çok karmaşık olabilir ve Coverity veya LLVM derleyicisi gibi yüksek fiyatlı statik analiz aracı yardımcı olabilir.

Ama emin değilim ve manuel kod inceleme tercih ederim.

GÜNCELLENMİŞ

Peki .. sadece kullanılmayan değişkenleri kaldırmak, kullanılmayan fonksiyonlar olsa zor değil.

GÜNCELLENMİŞ

Diğer cevapları ve yorumları okuduktan sonra, bunun yapılamayacağına ikna oldum.

Anlamlı bir kod kapsamı ölçüsü olması için kodu bilmeniz gerekir ve çok fazla manuel düzenlemenin kapsama sonuçlarını hazırlamak / çalıştırmak / gözden geçirmekten daha hızlı olacağını biliyorsanız.


2
cevabınızın ifadesi yanıltıcı, LLVM hakkında pahalı bir şey yok ... ücretsiz!
Matthieu M.

manuel düzenleme, programınızdaki mantık dallarından geçen çalışma süresi değişkenlerinde size yardımcı olmaz. Kodunuz hiçbir zaman belirli bir kriteri karşılamıyorsa ve bu nedenle her zaman aynı yolu izliyorsa ne olur?
Carlos V

0

Bugün bana bu soruyu soran bir arkadaşım vardı ve bazı umut verici Clang gelişmelerine baktım, örneğin ASTMatcher s ve ve ölü kod bölümlerini belirlemek için derleme sırasında yeterli görünürlüğü olan Statik Analizör gibi , ama sonra ben bunu buldu:

https://blog.flameeyes.eu/2008/01/today-how-to-identify-unused-exported-functions-and-variables

Referanssız sembollerin tanımlanması amacıyla tasarlanmış görünen birkaç GCC bayrağının nasıl kullanılacağına dair tam bir açıklama!


0

Bazı fonksiyonların çağrılıp çağrılmayacağı genel problem NP-Complete'tir. Bir Turing makinesinin durup durmayacağını bilmeyeceğiniz için bazı işlevler çağrılacaksa, genel olarak önceden bilemezsiniz. Main () 'dan yazdığınız işleve giden bir yol (statik olarak) varsa alabilirsiniz, ancak bu sizi hiçbir zaman çağırmayacağınızı garanti etmez.


-3

Eğer g ++ kullanıyorsanız bu bayrağı kullanabilirsiniz -Wunused

Belgelere göre:

Warn whenever a variable is unused aside from its declaration, whenever a function is declared static but never defined, whenever a label is declared but not used, and whenever a statement computes a result that is explicitly not used.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

Düzenle: İşte diğer yararlı bayrak -Wunreachable-code Belgelere göre:

This option is intended to warn when the compiler detects that at least a whole line of source code will never be executed, because some condition is never satisfied or because it is after a procedure that never returns.

6
Bu tam bilgi şu anda en çok puan alan cevapta zaten belirtilmiştir. Gereksiz çoğaltmayı önlemek için lütfen mevcut cevapları okuyun.
j_random_hacker

1
Artık Akran Basıncı rozeti kazanabilirsiniz!
Andrew Grimm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.