EN JP CN

Klocwork Refactoring

Klocwork Refactoring

Klocwork Refactoring

Klocwork Refactoring

リファクタリングは、プログラムの動作を変更しないでコードを簡略化および明確化するためのプロセスです。最初と最後の生成物は、機能的に同じです。リファクタリングにより、コードは次のようになります。

  • 維持および再利用がしやすくなる
  • 理解しやすくなる
  • 変更コストが抑えられる

使用可能なリファクタリング

以下の操作ができます。

  • エンティティの名前の変更 範囲はファイルローカルです。 識別子名をわかりやすいものにします。
  • メソッドまたは関数の抽出 (Eclipse および Visual Studio での重複検出) 小さく論理的な関数を作成するために、大きく不便な関数から抽出します。新たに抽出された関数はソースファイルに追加され、選択したコードはその関数の呼び出しに置換されます。
  • 変数の導入 (Eclipse および Visual Studio での重複検出) 複雑な式を簡略化します。式の出現は新しい変数に置換されます。
  • インライン変数 与えられた変数のすべての出現を初期値に置換します。 これは、変数の導入の逆です。
  • インライン関数 過度にセグメント化されたソースレイアウトのオーバーヘッドを削除します。インラインの典型的な候補は、少ないいくつかの場所から呼び出される単関数ですが、内部ループからの呼び出しなど、実行時に頻繁に呼び出されることもあります。これらは、関数呼び出しのオーバーヘッドの削除により最高の利点が得られることのある関数です。インライン関数には、メソッドのボディの呼び出し側のボディへの配置、およびメソッドの削除が含まれます。
  • ヘッダーの解析 欠落した推移的 include および不要な include を報告します。
  • ヘッダーの最適化 使用していないヘッダーおよび欠落した推移的ヘッダーの変更を、ユーザーの確認なしにすべて 1 つのステップで適用します。

名前の変更

識別子名をわかりやすいものにするために、変数または関数の名前を変更します。デモを見るには。以下の名前を変更できます。

  • ローカル変数
  • 関数パラメーター
  • static 関数および変数

既存の変数、関数、タイプ、または名前空間の非表示や、名前の競合を回避するために、新しい名前は、既存のコードに対してチェックされます。

int boo(int b) { 
}
int bar(int (*func)(char*)) { 		 
    return 1; 
} 
void foo(int a) { 
    int i = 2;
    i = 3;
    a = 567;
    a = boo(a); 
}

上の抜粋で、bfunca および i は、すべて指定したとおりに名前を変更できます。

抽出関数

抽出関数オプションを使用すると、新しい関数が作成され、選択したコードはその関数のボディとして挿入されます。選択したコードは、完全なステートメントおよび/または式の、構文的に完全で空のないシーケンスであることが必要です。

実装に関する注意事項

  • 選択したコードフラグメントは、新しい関数の呼び出しに置換されます。コードフラグメント内で使用されている変数があれば、入力または出力のパラメーターとして新しい関数に渡されます。
  • プリミティブ型 (pointer、char、bool、int など) の 1 つの出力パラメーターのみを持つ新しい関数は自動的に 1 つの関数に変換され、この型の値を返します。出力パラメーターは返されません。
  • C 出力の場合、パラメーターは元の型のポインターとして宣言されます。
  • C++ 出力の場合、パラメーターは元の型のリファレンスとして宣言されます。現在の関数が C++ クラスのメンバー関数である場合、新しい関数の宣言が、保護されているメンバーとしてクラス定義に挿入されます。
  • 元のインデントおよび空白は、可能な限り保存されます。
  • 選択内のコメント、マクロ、およびプリプロセッサディレクティブは、コード変換中に保存されます。次のコードの例は、リファクタリング用に選択されたコードを示します。
int foo() {
  int a;
  /* selection starts -> */
  #define MY_MACRO 1
  a = MY_MACRO;
  /*<- selection ends*/
  a = a + 20;
  return a;
}

抽出された関数に 'define' ディレクティブが保存されることがわかります。

int extracted_function()
{
  int a;
  #define MY_MACRO 1
  a = MY_MACRO;
  return a;
}

制限事項

  • 選択したコードフラグメントにジャンプステートメント ("goto") を含めることはできませんが、return ステートメントは機能します。
  • 選択したコードフラグメントにラベルステートメントを含めることはできませんが、(ラベル付きの) switch ステートメントは機能します。
  • テンプレート関数からの抽出はサポートされません。

int main() {		 
 int a;			       
   a++ ;			
  return a;
}

フィールド'a++' を 'new_function' に抽出できます。

結果

 void new_function(int *a) {  
  (*a)++ ; 
}
int main() { 
 int a; 
 new_function(&a) ; 
 return a; 
}


変数の導入

変数の導入では、選択した式から新しいローカル変数を簡単に作成し、そのローカル変数を式で初期化し、コード内のすべての式の出現を新しく導入された変数の参照で置換します。反対のアクションは、変数を初期の式で置換する、変数のインラインによるリファクタリングです。

実装に関する注意事項

  • 選択した式で初期化された、新しいローカル変数の宣言は、現在のステートメントに挿入されます。選択した式は、新しい変数の名前に置換されます。
  • 既存の変数、関数、タイプ、または名前空間の非表示や、名前の競合を回避するために、新しい名前は、既存のコードに対してチェックされます。
  • C++ の場合、新しい変数の宣言および初期化子は、1 つのステートメントに統合され、選択したステートメントの前に直接挿入されます。
  • C の場合、宣言および初期化子を分割する必要があることがあります。宣言は、現在のブロックまたは関数の最初に挿入され、割り当ての初期化は、選択したステートメントの前に直接挿入されます。

下の抜粋の太字テキストは、変数に置換できます。

int main() { 				
    int c; 				     
    c = 1 +  2 + 3 + 4 + 5 ;		     
    return c; 				      
}

結果

int main() { 
  int temp ; 
 int c;
  temp = 2 + 3 + 4 + 5 ; 
 c = 1 +  temp ;				     				  
 return c; 
}

インライン変数

インライン変数では、与えられた変数のすべての出現を初期値に置換します。反対のアクションは、変数の導入によるリファクタリングです。

太字の変数は、式で置換できます。

int main() { 
  int temp ; 
 int c;
  temp  = 2 + 3 + 4 + 5; 
 c = 1 +  temp ;				     				  
 return c; 
}

結果

int main() { 				
    int c; 				     
    c = 1 +  2 + 3 + 4 + 5 ;		     
    return c; 				      
}

インライン関数

関数をインラインすると、関数の完全なボディが、選択した関数の出現ごとに挿入されます。

この機能に関するデモを見るにはここをクリックします

実装に関する注意事項

  • 関数の定義を選択すると、関数がソースファイルから削除され、この関数の各呼び出しは、関数のボディに置換されます。
  • 関数の呼び出しを選択すると、この呼び出しのみがインラインされ、関数定義は変更されません。
  • 関数のパラメーターおよびローカル変数は、置換時に名前が変更されます。

制限事項

  • サポートされるのはインライン関数および static 関数のみです。
  • 次のものはインラインできません。
    • 再帰関数
    • 複数の return ステートメントを持つ関数
    • アドレスにより参照される関数

static int foo(int a) {			  
    int b = a + 2;				    
    return b;				      
}						  
int main() {				      
    int c;					     
    c =  foo(1) ;				 
    return c; 
} 

この例では、'foo' をインラインできません。

結果

int main() { 
 int c;
  int a = 1;  
  int b = a + 2;  
  c = b; 
 return c;
}

システムヘッダーで宣言された関数はインラインできない

システムヘッダーで関数定義が検出された場合、次のようなメッセージが表示されます。

たとえば、このメッセージは、下の抜粋の 'math.h' から 'pow' をインラインしようとすると、表示されます。

#include <iostream>
 #include <stdio.h>
 #include <math.h>
 
 using namespace std;
 
 #define PI 3.14
 
 static float getArea(float radius) {
   float area = PI * *pow(radius, 2)*;
   return area;
 }

関数をインラインできません:この関数は、その完全修飾名で呼び出されます

別のクラスメンバーから直接呼び出される関数はインラインできますが、次のような状況で 'x->foo()'、'x.foo()' などの関数をインラインしようとすると、このメッセージが表示されます。

 class A{
    void foo() {...}
    void abc();
 }
 void A::abc()
 {
    foo(); //we can inline this
 
    A::foo(); //we can't inline this
    A x = new A();
    x->foo(); //we can't inline this
 }