2016-04-27 47 views
12

çağırır, ben böyle kaynak kodunu buldum Aynı modelle üç kez çağrıldı (burada "::").otomatik özdeş ardıl std algılamak :: dize bulmak ::() bir kod inceleme sırasında

Bu kod elbette

bulmak sadece bir kez denir
void f(std::string &className, std::string &testName) 
{ 
    const size_t endOfClassNamePos = className.find("::"); 
    if (endOfClassNamePos != std::string::npos) 
    { 
    testName = className.substr(endOfClassNamePos + 2); 
    (void)className.erase(endOfClassNamePos, std::string::npos); 
    } 
} 

refactored edilebilir.

Soru

herkes böyle böyle bir modelin belirlenmesi için bir strateji biliyor mu? Bu deseni tespit etmek istediğim büyük bir kod tabanı yaşıyorum. Bir Windows veya Linux ortamı kullanmayı planlıyorum.

Potansiyel Stratejiler

  1. Kullanım/tuhaflıklar bu tür algılamaya cppcheck gibi bir statik kod analiz aracı uyarlar.
  2. Düzenli ifade ile kod tabanında arama yapın.
  3. Bu desenin algılanması için clang-tidy kullanın/uyarlayın.
  4. Bazı sorunları (ör. Python) bu sorunları algılayan bir özel denetleyici yazın. Bu durumda, kontrol önceden işlenmiş kod üzerinde yapılmalıdır.

Devam Etme en

  • Manuel inceleme

Güncelleme 1

Ben potansiyel strateji 1) ile başlamaya karar verdik. Bu sorunu yakalamak için cppeck'leri uyarlamayı planlıyorum.

Cppcheck, PCRE düzenli ifadelerine dayanan özelleştirilmiş kurallar yazma olanağı sunar. Bunun için, cppcheck etkin PCRE desteği ile derlenmelidir. aşağıdaki gibi aracı Bundan sonra

git clone https://github.com/danmar/cppcheck.git && cd cppcheck

derlemek ve yüklemek:: Mevcut test ortamı Linux tabanlı olduğundan, aşağıdaki komutlar cppcheck en son sürümünü indirmek için kullanılabilir

sudo make install HAVE_RULES=yes

Şimdi temel araç kurulumu tamamlandı. Bir cppcheck-kuralı geliştirmek için, bu makalenin ilk bölümünde örnek koduna benzer basit bir test durumu (dosya: test.cpp) hazırladım. Bu dosya üç işlev içerir ve cppcheck-kuralı, f_odd ve f_odd1 üzerinde ardışık std::string::find çağrıları hakkında bir uyarı yayınlayacaktır.

testi.cpp:

Şimdiye kadar çok iyi. Şimdi cppcheck, birbirini izleyen std::string::find çağrılarını yakalamak için ayarlanmalıdır. Bunun için ben ardışık özdeş std::string::find çağrıları eşleşen bir düzenli ifade içeren bir cppcheck_rule-file yarattık:

<?xml version="1.0"?> 
<rule> 
<tokenlist>normal</tokenlist> 
<pattern><![CDATA[([a-zA-Z][a-zA-Z0-9]*)(\s*\.\s*find)(\s*\(\s*\"[ -~]*\"\s*\))[ -\{\n]*(\1\2\3)+[ -z\n]]]></pattern> 
<message> 
    <severity>style</severity> 
    <summary>Found identical consecutive std::string::find calls.</summary> 
</message> 

Bu dosya

yeni çek konusunda cppcheck uzatmak için kullanılabilir.

cppcheck --rule-file=rules/rule.xml test/test.cpp

ve çıkış Şimdi, aynı ardışık std::string::find aramalar C/C++ kodları tespit edilebilir

Checking test/test.cpp... 
[test/test.cpp:14]: (style) Found identical consecutive std::string::find calls. 
[test/test.cpp:26]: (style) Found identical consecutive std::string::find calls. 

olup: deneyin sağlar. Daha iyi/daha verimli veya daha akıllı bir çözüm bilen var mı?

Referanslar:


+3

Bunu tespit etmek için kendi [clang-tidy] (http://clang.llvm.org/extra/clang-tidy/) kontrolünü yazabilirsiniz. – Jonas

+0

@Jonas Teşekkür ederim clang-tidy, işi yapabilecek başka bir potentia aracıdır. Potansiyel çözümler bölümünü güncelleyeceğim. – orbitcowboy

+2

Sorunuzu, araç önerileri için bir istek gibi görünmeyecek şekilde yeniden ifade edebilir misiniz? Bunlar, bu sitede [açıkça konu dışı] (https://stackoverflow.com/help/on-topic). – 5gon12eder

cevap

1

böyle bir araç ile temel sorun metinsel tekrarı varsa bir sözcük analizi sadece kontrol edebilirsiniz olmasıdır. Örneğinizi almak için, değişken iki defa aynı dizgeye başvuruyorsa, className.find("::")'u iki kez çağırmak olası bir sorundur. Ama kodunuza bir küçük değişikliği ekleyeyim: className = className.substr(className.find("::") + 2);. Birdenbire className.find'un anlamı değerini önemli ölçüde olarak değiştirmiştir.

Bu tür değişiklikleri bulabilir misiniz? Bunun için tam donanımlı bir derleyiciye ihtiyacın var, ve o zaman bile kötümser olmak zorundasın. Örneğinize bağlı kalarak, className bir yineleyici üzerinden değiştirilebilir mi? Farkında olmanız gereken sadece doğrudan manipülasyon değil.

Olumlu bir haber yok mu? Eh: mevcut derleyiciler benzer bir mekanizma var. Buna Ortak Alt-İfade Eliminasyonu denir ve kavramsal olarak yukarıdaki örnekte çalışmak istediğiniz gibi çalışır. Fakat bu aynı zamanda bir şekilde kötü bir haberdir: Durumun saptanabilir olması durumunda, önemsizdir çünkü zaten derleyici tarafından optimize edilmiştir!