lint最早用於C語言,是一種用來檢查程式碼的工具,現在的主流程式語言幾乎都有lint可以使用,尤其是JavaScript、Python等直譯式程式語言,因為它們的程式碼不會經過編譯,所以特別需要使用lint來檢查原始碼。藉由lint,我們可以寫出疑慮較少、效能更好或是更容易閱讀的程式碼。Rust程式語言雖然是靜態型別的程式語言,而且擁有十分嚴謹的編譯器,但官方還是提供了一個lint工具──Clippy。



使用clippy

clippy的使用方法很簡單,建議透過以下指令來執行:

cargo clippy --tests -- -W clippy::cargo

cargo clippy指令加上--tests參數,可以讓它去檢查測試用的Rust程式碼,如果需要的話,也可以加上--features--all-features--no-default-features參數來啟用特色。clippy工具本身的-W參數可以用來設定要將哪一個的lint分類或是規則改設為「警告」(warn)層級,就會輸出不符合該規則的位置,但不影響行程執行結束後回傳的Exit Status;-A參數可以用來設定要將哪一個的lint分類或是規則改設為「允許」(allow)層級,就不會輸出不符合該規則的位置;-D參數可以用來設定要將哪一個的lint分類或是規則改設為「拒絕」(deny)層級,就會輸出不符合該規則的位置,且影響行程執行結束後回傳的Exit Status。

clippy的lint規則分類有以下幾項:

  • clippy::correctness:錯誤或是無用的程式碼,預設為「拒絕」層級。
  • clippy::style:不合乎(官方)習慣的程式碼,預設為「警告」層級。
  • clippy::complexity:可以被簡化的程式碼,預設為「警告」層級。
  • clippy::perf:可以被加速的程式碼,預設為「警告」層級。
  • clippy::all:即表示以上四個分類。方便整體控制層級用的,例如-D clippy::all就是-D clippy::correctness -D clippy::style -D clippy::complexity -D clippy::perf
  • clippy::restriction:程式碼語法結構與風格的規則,預設為「允許」層級。可能會與以上分類的規則有所衝突。
  • clippy::cargo:Cargo設定檔(即Cargo.toml),預設為「允許」層級。Clippy可以檢查Cargo設定檔中缺失的設定項目,和相依crate的版本問題。
  • clippy::pedantic:其它比較嚴格的規則,預設為「允許」層級。
  • clippy::nursery:尚未穩定的規則,預設為「允許」層級。

所有的lint規則,以及規定原因都可以來這個網頁查詢。

利用巨集來設定lint規則

藉由#[allow(...)]#[warn(...)]#[deny(...)]屬性,我們可以在Rust程式碼中臨時設定lint規則。

例如:

fn main(){
    let x: u64 = 61864918973511;

    println!("{}", x);
}

以上程式的第二行敘述會觸犯clippy::unreadable_literal規則,如果要針對這個x變數避免Clippy出現警告,可以對其加上#[allow(clippy::unreadable_literal)]屬性。如下:

fn main(){
    #[allow(clippy::unreadable_literal)]
    let x: u64 = 61864918973511;

    println!("{}", x);
}

可配置的lint規則

有些lint規則可以透過Clippy的設定檔來指定參數。cargo cargo指令在執行的時候,首先會尋找工作目錄中是否有.clippy.toml檔案,如果有的話就會將其作為clippy的設定檔,如果沒有的話就會再尋找工作目錄中是否有clippy.toml檔案,如果還是沒有的話,就會去尋找上層目錄是否有.clippy.tomlclippy.toml檔案,依此類推。

可以被配置的lint規則如下:

blacklisted-names = ["foo", "bar", "baz", "quux"] # clippy::blacklisted_name
cognitive-complexity-threshold = 25               # clippy::cognitive_complexity
doc-valid-idents = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "JavaScript", "NaN", "NaNs", "OAuth", "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap", "TrueType", "iOS", "macOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"] # clippy::doc_markdown
enum-variant-name-threshold = 3                   # clippy::enum_variant_names
enum-variant-size-threshold = 200                 # clippy::large_enum_variant
single-char-binding-names-threshold = 5           # clippy::many_single_char_names
too-large-for-stack = 200                         # clippy::boxed_local
too-many-arguments-threshold = 7                  # clippy::too_many_arguments
trivial-copy-size-limit = 1                       # clippy::trivially_copy_pass_by_ref
type-complexity-threshold = 250                   # clippy::type_complexity
verbose-bit-mask-threshold = 1                    # clippy::verbose_bit_mask

# too_many_lines = 100                              # clippy::too_many_lines (pedantic)