自動現代化C++程式碼

hokein發表於2019-05-11

原文連結: http://hokein.me/clang-tools-…

雖然C++11標準出來已經有好些年了,但是由於歷史的原因,現在大部分C++專案仍然是C++03的語法。那麼有沒方法能夠自動地把老的C++03程式碼替換成C++11程式碼?從而讓我們享受到C++11新特性,像for-range loop,auto,nullptr,override等。

答案當然有的——clang-tidy。clang-tidy提供一系列的modernize-*checks。這些checks就是用C++11改寫C++03。具體有下面這些:

  • modernize-avoid-bind: 使用lambda替換std::binding

  • modernize-deprecated-headers: 將C標準庫的標頭檔案include替換成C++style,#include <assert.h> => #include <cassert>

  • modernize-loop-convert: 使用for-range loop替換for(...;...;...;), 並更新for語句的相關變數。

  • modernize-make-shared: 找出所有顯式建立std::shared_ptr變數的表示式,並使用make_shared替換。

  • modernize-make-unique: 跟make-shared一樣,使用std::make_unique替換所有std::unique_ptr顯式建立表示式。

  • modernize-pass-by-value: 在建構函式中使用move語義

  • modernize-raw-string-literal: 用C++11的raw string literal(R"...")替換原來的string literal, 這樣的好處就是不用再新增轉義符“了。

  • modernize-redundant-void-arg: 去掉void函式引數。

  • modernize-replace-auto-ptr: 用std::unique_ptr替換std::shared_ptr, std::shared_ptr是不推薦使用的,即使在C++98。

  • modernize-shrink-to-fit: 在C++03中,如果我們想修改STL容器的capacity,只能通過copy & swap的方式,C++11提供了shink_to_fit的方法。

  • modernize-use-auto: 在變數定義的時候,使用auto代替顯式的型別宣告,這個在定義STL容器類的Iterator特別方便。

  • modernize-use-bool-literals: 找出所有隱式從int轉成boolliteral, 使用true或者false代替。

  • modernize-use-default: 對於沒有任何自定義行為(定義為{})的特殊的成員函式,建構函式,解構函式,移動/複製建構函式,用=default代替掉{}

  • modernize-use-emplace: 使用STL容器中的emplace代替push_back

  • modernize-use-equals-delete: 在C++98中,類設計為了實現禁止呼叫某些特殊的成員函式,通常把它們宣告成private;在C++11中,只需要在宣告中體檢=delete,找出所有private的特殊成員函式,並將它們標記成=delete

  • modernize-use-nullptr: 用nullptr代替NULL

  • modernize-use-override: 對於子類改寫父類的virtual方法,在方法後面新增override, 並刪掉virtual字首,即virtual void NewOveride() => void NewOverride() override {}

  • modernize-use-using: 用using代替typedef, 如typedef int V => using V = int

如何應用到專案中

這裡將以GitHub的electron開源專案為例子,如何應用clang-tidy來改寫它的C++03程式碼:

  • 你需要匯出專案的compilation database, 通常命名為compile_commands.json, 因為clang-tidy作為一個clang-based工具,需要知道如何編譯每一個原始檔(從compile_commands.json查詢). ninja提供這個匯出功能,只需要簡單執行下面命令。對於其它不用ninja編譯的專案,也是有工具匯出的,方法請檢視前一篇介紹clang-tidy文章

cd path/to/electron
# Make sure you can build electron successfully.
./script/build.py -c D
# Dump compilation database.
ninja -C out/D -t compdb cc cxx > compile_commands.json
  • 現在,我們可以嘗試對專案中某個檔案執行modernize-use-nullptr check, 我們需要新增-fix的命令引數,clang-tidy才會執行對原檔案修改, 不然結果會定向到標準輸出stdout

# Diagnose any `NULL` usage.
clang-tidy -checks="-*,modernize-use-nullptr" atom/browser/api/atom_api_menu.cc
# Replace all NULL usages to C++11 nullptr.
clang-tidy -checks="-*,modernize-use-nullptr" -fix atom/browser/api/atom_api_menu.cc
  • 我們當然不需要每次都手動執行一個原始檔,run_clang_tidy.py指令碼能夠對每個compilation database中的每個檔案都執行clang-tidy(使用多程式方法)。

# Run `modernize-use-auto` on all files in atom/* and apply fixes.
path/to/run_clang_tidy.py -checks="-*,modernize-use-auto" -fix atom/*

真實執行的結果,請檢視electron#6423,已經被merge進upstream了。

相關文章