2016-11-14 131 views
2

我正在一個非常大的代碼庫(超過3M loc),我們顯然有很多類,但他們大多數不在他們的構造函數中使用初始化列表,而是分配值構造函數體(一些代碼在很久以前被寫入了一個LONG,所以這已經成爲事實上的標準)。也許這些被編譯器優化掉了,但我不確定是否真的如此。重構構造函數使用初始化列表

我想推廣初始化列表的使用,但有一個大的代碼庫需要提供最新的,所以有沒有任何工具會自動爲我做這個?將它指向一個類,找到所有m_var = 0;行並將它們移動到初始化列表(如果需要,創建它)。

除了將體內初始化轉換爲初始化列表外,是否有一種方法可以找到成員變量是按照正確的順序初始化的(即它們在類頭文件中定義的順序相同?本來希望CppCheck會挑這個,但它似乎沒有沒有。

+1

至於第二部分:GCC有'-Wreorder'。 – Biffen

+0

@Biffen是不是Visual Studio 2012?這就是我正在使用的。 – fwgx

+1

不是我所知道的,一個快速的谷歌沒有給任何東西。我會留給你做更多的研究。 – Biffen

回答

2

你好,我是一個cppcheck開發商。

Cppcheck也有不匹配順序檢查,但它是一個不確定的檢查。

例如:

class Fred { 
public: 
    Fred() : y(0), x(0) {} 
    int x; 
    int y; 
}; 

Cppcheck輸出:

[email protected]:~/cppcheck$ ./cppcheck --enable=style --inconclusive 1.cpp 
Checking 1.cpp ... 
[1.cpp:3] -> [1.cpp:4]: (style, inconclusive) Member variable 'Fred::x' is in the wrong place in the initializer list. 

我們簡單的檢查將只警告時的順序不匹配。這就是爲什麼它沒有結果。在上面的代碼中,初始化順序實際上並不重要 - 因爲上面代碼中的所有成員都是整數,所有初始化方法都是常量文字。

1

與OP的代碼庫大小一樣,需要的是program transformation system (PTS)。這是一個將目標語言源文件解析爲編譯器數據結構(通常是AST)的工具,允許您將轉換應用到AST,然後可以重新生成有效的源代碼,包括修改程序的原始註釋。把PST看作在大型中重構的工具。

一個很好的PTS將讓你寫源到源轉換形式的

when you see *this*, replace it by *that* if *condition* 

其中在目標語言的語法表達,其中僅當源代碼與顯式語法匹配時才匹配。 [這些不是字符串匹配;他們在AST上工作,所以佈局不會影響他們匹配的能力]。

你需要鑰匙規則看起來是這樣的:

rule move_to_initializer(constructor_name:IDENTIFIER, 
         arguments: argument_list, 
         initializer_list: initializer, 
         member_name:IDENTIFIER, 
         initializer_expression: expression, 
         statements: statement_list 
         ): constructor -> constructor = 
    " \constructor_name(\arguments): \initializer_list 
      { \member_name = \initializer_expression ; 
      \statements } " 
    -> " \constructor_name(\arguments): \initializer_list, \member_name(\initializer_expression) 
      { \statements } "; 

The syntax of these rules/patterns for our DMS Software Reengineering Toolkit is explained here。 DMS是唯一可以處理C++的源碼到源碼PTS;它甚至可以處理MSVS方言]。

我忽略了可能必要的「如果條件」檢查成員名稱確實是類的成員,假設您的構造函數不是濫用。

因爲你的構造可能沒有任何初始化列表,你需要一個幫手規則介紹一個在必要時:

rule move_to_initializer(constructor_name:IDENTIFIER, 
         arguments: argument_list, 
         member_name:IDENTIFIER, 
         initializer_expression: expression, 
         statements: statement_list 
         ): constructor -> constructor = 
    " \constructor_name(\arguments) 
      { \member_name = \initializer_expression ; 
      \statements } " 
    -> " \constructor_name(\arguments): \member_name(\initializer_expression) 
      { \statements } "; 

      { \member_name = \e ; } " 

不變的是你需要額外的規則,以涵蓋其他特殊情況,但它不應該超過一些。

關於對訂單的初始化檢查,則可以使用(DMS)圖案觸發這樣的檢查:

pattern check_initializer_order(constructor_name:IDENTIFIER, 
         initializer_list: initializer, 
         statements: statement_list 
         ): constructor = 
    " \constructor_name(): \initializer_list, 
      { \statements } " 
      if complain_if_not_ordered(constructor_name,initializer_list); 

這需要一個輔助的元謂詞檢查順序,如果它們是抱怨亂序。您需要constructor_name來使謂詞能夠查找相應的類並檢查成員的順序。 [DMS向means to access a symbol table提供這些信息]。

或者,你可能只是簡單地重新排列它們使用不同的重寫規則:

rule order_initializers(constructor_name:IDENTIFIER, 
         arguments: argument_list, 
         initializer_list_prefix: initializer, 
         initializer_list_suffix: initializer, 
         member1_name:IDENTIFIER, 
         initializer1_expression: expression, 
         member2_name:IDENTIFIER, 
         initializer2_expression:expression,        
         statements: statement_list 
         ): constructor -> constructor = 
    " \constructor_name(\arguments): 
      \initializer_list_prefix, 
      \member1_name(\initializer1), 
      \member2_name(\initializer2), 
      \initialize_list_suffix 
      { \statements } " 
    -> 
    " \constructor_name(\arguments): 
      \initializer_list_prefix, 
      \member2_name(\initializer2), 
      \member1_name(\initializer1), 
      \initialize_list_suffix 
      { \statements } " 
     if is_wrong_order(constructor_name,member1_name,member2_name); 

這個規則基本上排序初始化。 [請注意,這是一個冒泡排序:但是初始化列表通常不會很長,並且您只需要爲每個構造函數運行一次。]在將所有初始化器從構造函數體中提取出來之後,您將運行此規則前面顯示的規則。