2016-04-27 11 views
12

を呼び出して、私はこのようなソースコードが見つかりました:のstd ::文字列、この関数内で自動的に同一の連続したSTDを検出::文字列::見つける()は、コードレビューの際

void f_odd(std::string &className, std::string &testName) 
{ 
    if (className.find("::") != std::string::npos) 
    { 
    testName = className.substr(className.find("::") + 2); 
    (void)className.erase(className.find("::"), std::string::npos); 
    } 
} 

を::見つける()であります同じパターン(ここでは "::")で3回呼ばれます。

このコードはもちろん、検索は一度だけ呼び出され

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); 
    } 
} 

にリファクタリングすることができます。

質問

誰もがこのようなパターンを検出するための戦略を知っていますか?私はこのパターンを見つけようとしている巨大なコードベースを持っています。 私は、WindowsまたはLinux環境を使用する予定です。

潜在的な戦略

  1. 使用/奇妙これらの種類を検出するcppcheckのように、静的コード解析ツールを適応させます。
  2. コードベース内で正規表現で検索します。
  3. このパターンの検出には、/ clang-tidyを使用してください。
  4. これらの問題を検出する言語(Pythonなど)でカスタムチェッカーを作成します。この場合、チェックは事前処理されたコードで実行する必要があります。

ノーゴーの

  • マニュアルレビュー

更新は1

私は、潜在的な戦略1)を開始することを決めました。私はこの問題を捕まえるためにcppcheckを適応させる予定です。

Cppcheckは、PCRE正規表現に基づいてカスタマイズされたルールを書くことができます。このためには、cppcheckをPCREサポートを有効にしてコンパイルする必要があります。以下のようなツールをコンパイルしてインストールし、その後

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

:現在のテスト環境はLinuxベースされているので、次のコマンドはcppcheckの最新バージョンをダウンロードするために使用することができ

sudo make install HAVE_RULES=yes

これで基本的なツールの設定が完了しました。 cppcheckルールを開発するために、私はこの記事の最初のセクションのサンプルコードに似た単純なテストケース(file:test.cpp)を用意しました。このファイルには3つの関数が含まれており、cppcheck-ruleはf_oddf_odd1で連続して同じstd::string::find呼び出しについての警告を発するものとします。

試験。cpp:

#include <string> 
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); 
    } 
} 

void f_odd(std::string &className, std::string &testName) 
{ 
    if (className.find("::") != std::string::npos) 
    { 
     testName = className.substr(className.find("::") + 2); 
     (void)className.erase(className.find("::"), std::string::npos); 
    } 
} 

#define A "::" 
#define B "::" 
#define C "::" 
void f_odd1(std::string &className, std::string &testName) 
{ 
    if (className.find(A) != std::string::npos) 
    { 
     testName = className.substr(className.find(B) + 2); 
     (void)className.erase(className.find(C), std::string::npos); 
    } 
} 

これまでのところとても良いです。連続して同じstd::string::findコールを受信するには、cppcheckを調整する必要があります。このファイルには、新しいチェックについてcppcheckを拡張するために使用することができます

<?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> 

:。このために私は連続で同じstd::string::find呼び出しにマッチする正規表現が含まれているcppcheck_rule-fileを作成しました

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

の出力は次に、同じ連続std::string::findコールはC/C++コードで検出することができる

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. 

ある: が試すことができます。誰かがより良い/より効率的な、あるいはより巧妙な解決策を知っていますか?

参考文献:


+3

これを検出するには、独自の[clang-tidy](http://clang.llvm.org/extra/clang-tidy/)チェックを書くことができます。 – Jonas

+0

@Jonasありがとうclang-tidyは、仕事をすることができるもう一つの強力なツールです。潜在的なソリューションのセクションを更新します。 – orbitcowboy

+2

あなたの質問をツールの推奨事項のように表示されないように修正することはできますか?これらは、このサイトの[明示的にオフトピック](https://stackoverflow.com/help/on-topic)です。 – 5gon12eder

答えて

1

そのようなツールの主な問題点は原文繰り返しがあれば字句解析のみを確認することができるということです。たとえば変数が同じ文字列を2回参照する場合は、className.find("::")を2回呼び出しても問題はありません。しかし、私は小さなあなたのコードに変更を追加させてください:className = className.substr(className.find("::") + 2);。突然次のclassName.findの意味がに劇的に変わった

このような変更はありますか?そのためには、本格的なコンパイラが必要です。それでも悲観的でなければなりません。あなたの例に従えば、classNameはイテレーターで変更できますか?あなたが気づく必要があるのはそれだけではありません。

肯定的なニュースはありませんか?まあ、既存のコンパイラにも同じような仕組みがあります。これはCommon Subexpression Eliminationと呼ばれ、上記の例で動作するように概念的に機能します。しかし、これはまた一つのやり方では悪いニュースです:状況が検出可能な場合、それはコンパイラによって既に最適化されているので重要ではありません!