mcpField
R
rust-quality

rust-quality

github.com/claude-dev-suite测试与质量4644 次安装2 天前更新
代码仓库

关于 rust-quality

面向 Rust 项目维护者的代码质量参考技能,汇集格式化、静态检查、IDE 分析、代码模式及 CI 检查的常用工具指引。

主要功能

  1. 01rustfmt 格式化指引
  2. 02Clippy 检查配置
  3. 03rust-analyzer IDE 分析
  4. 04代码异味与错误处理示例
  5. 05Pre-commit 和 Makefile 配置
  6. 06CI 质量检查

适用场景

  1. 01配置格式化和静态检查规则
  2. 02检查 Rust 代码的可维护性
  3. 03在 CI 中加入质量检查

MCP 相关

README 提到可通过 mcp__documentation__fetch_docs 获取完整的 Rust 文档。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill rust-quality

安装后在 Claude Code 中输入/rust-quality确认已加载。

详细介绍

Rust 代码质量 - 快速参考

何时不使用此技能

  • SonarQube 设置 - 使用 sonarqube 技能
  • 安全扫描 - 使用 rust-security 技能

深入了解:使用 mcp__documentation__fetch_docs,并将 technology 设为 rust,以获取完整文档。

工具概览

工具重点命令
rustfmt格式化cargo fmt
Clippy代码检查cargo clippy
rust-analyzerIDE 分析LSP
cargo-deny依赖策略cargo deny
cargo-audit安全审计cargo audit

Clippy 设置

运行 Clippy
# Basic check
cargo clippy

# Strict mode - deny all warnings
cargo clippy -- -D warnings

# With pedantic lints
cargo clippy -- -W clippy::pedantic

# Fix auto-fixable
cargo clippy --fix

# All targets (tests, benches, examples)
cargo clippy --all-targets --all-features
clippy.toml
# Maximum cognitive complexity
cognitive-complexity-threshold = 15

# Maximum function length
too-many-lines-threshold = 50

# Maximum arguments
too-many-arguments-threshold = 5

# Allowed wildcard imports
allowed-wildcard-imports = ["crate::prelude::*"]
Cargo.toml 代码检查配置
[lints.rust]
unsafe_code = "deny"
missing_docs = "warn"

[lints.clippy]
# Categories
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }

# Specific lints
unwrap_used = "warn"
expect_used = "warn"
panic = "warn"
todo = "warn"
dbg_macro = "warn"

# Allow specific pedantic lints
module_name_repetitions = "allow"
must_use_candidate = "allow"
CI 配置
# Strict CI check
cargo clippy --all-targets --all-features -- \
  -D warnings \
  -D clippy::pedantic \
  -D clippy::nursery \
  -A clippy::module_name_repetitions

rustfmt 设置

rustfmt.toml
edition = "2021"
max_width = 100
tab_spaces = 4
newline_style = "Unix"

# Imports
imports_granularity = "Module"
group_imports = "StdExternalCrate"
reorder_imports = true

# Items
reorder_modules = true
reorder_impl_items = true

# Formatting
use_small_heuristics = "Default"
fn_single_line = false
where_single_line = false
struct_lit_single_line = true

# Comments
comment_width = 100
wrap_comments = true
normalize_comments = true

# Macros
format_macro_matchers = true
format_macro_bodies = true
命令
# Format all
cargo fmt

# Check without changing
cargo fmt -- --check

# Format specific file
rustfmt src/main.rs

常见 Clippy 检查项

unwrap_used / expect_used
// BAD - Panics on None/Err
let value = some_option.unwrap();
let result = some_result.expect("should work");

// GOOD - Handle errors properly
let value = some_option.ok_or(MyError::NotFound)?;
let result = some_result.map_err(|e| MyError::from(e))?;

// GOOD - When panic is intentional (with justification)
let value = config.get("required_key")
    .expect("required_key must be set in configuration");
clone_on_ref_ptr
// BAD - Cloning Arc/Rc unnecessarily
let clone = arc_value.clone();

// GOOD - Use Arc::clone for clarity
let clone = Arc::clone(&arc_value);
needless_pass_by_value
// BAD - Takes ownership unnecessarily
fn process(data: String) {
    println!("{}", data);
}

// GOOD - Borrow instead
fn process(data: &str) {
    println!("{}", data);
}
cognitive_complexity
// BAD - Too complex
fn process(data: &Data) -> Result<Output, Error> {
    if data.is_valid() {
        if data.type_a() {
            if data.has_value() {
                // deep nesting...
            }
        }
    }
    // ... more conditions
}

// GOOD - Extract and simplify
fn process(data: &Data) -> Result<Output, Error> {
    validate(data)?;

    match data.data_type() {
        DataType::A => process_type_a(data),
        DataType::B => process_type_b(data),
    }
}
missing_errors_doc
// BAD - No error documentation
/// Processes the data.
pub fn process(data: &Data) -> Result<Output, Error> { ... }

// GOOD - Document errors
/// Processes the data.
///
/// # Errors
///
/// Returns `Error::InvalidData` if the data is malformed.
/// Returns `Error::NotFound` if the resource doesn't exist.
pub fn process(data: &Data) -> Result<Output, Error> { ... }

常见代码异味及修复方法

1. 字符串类型代码
// BAD - Using strings for types
fn set_status(status: &str) {
    match status {
        "active" => { ... }
        "inactive" => { ... }
        _ => panic!("unknown status"),
    }
}

// GOOD - Use enums
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Status {
    Active,
    Inactive,
}

fn set_status(status: Status) {
    match status {
        Status::Active => { ... }
        Status::Inactive => { ... }
    }
}
2. 错误处理
// BAD - Using unwrap in library code
pub fn parse_config(path: &Path) -> Config {
    let content = fs::read_to_string(path).unwrap();
    serde_json::from_str(&content).unwrap()
}

// GOOD - Proper error handling with thiserror
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
    #[error("failed to read config file: {0}")]
    Io(#[from] std::io::Error),
    #[error("failed to parse config: {0}")]
    Parse(#[from] serde_json::Error),
}

pub fn parse_config(path: &Path) -> Result<Config, ConfigError> {
    let content = fs::read_to_string(path)?;
    let config = serde_json::from_str(&content)?;
    Ok(config)
}
3. 构建器模式
// BAD - Constructor with many parameters
impl Server {
    pub fn new(
        host: String,
        port: u16,
        max_connections: usize,
        timeout: Duration,
        tls_config: Option<TlsConfig>,
    ) -> Self { ... }
}

// GOOD - Builder pattern
#[derive(Default)]
pub struct ServerBuilder {
    host: String,
    port: u16,
    max_connections: usize,
    timeout: Duration,
    tls_config: Option<TlsConfig>,
}

impl ServerBuilder {
    pub fn host(mut self, host: impl Into<String>) -> Self {
        self.host = host.into();
        self
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }

    pub fn build(self) -> Result<Server, BuildError> {
        // Validate and build
    }
}

// Usage
let server = Server::builder()
    .host("localhost")
    .port(8080)
    .build()?;
4. Newtype 模式
// BAD - Primitive obsession
fn create_user(email: String, name: String, age: u32) { ... }

// GOOD - Newtypes for validation
#[derive(Debug, Clone)]
pub struct Email(String);

impl Email {
    pub fn new(value: impl Into<String>) -> Result<Self, ValidationError> {
        let value = value.into();
        if !value.contains('@') {
            return Err(ValidationError::InvalidEmail);
        }
        Ok(Self(value))
    }

    pub fn as_str(&self) -> &str {
        &self.0
    }
}

fn create_user(email: Email, name: Name, age: Age) { ... }
5. 避免滥用 clone()
// BAD - Cloning everywhere
fn process(data: &Vec<Item>) {
    let owned = data.clone();
    for item in owned {
        // process
    }
}

// GOOD - Borrow when possible
fn process(data: &[Item]) {
    for item in data {
        // process
    }
}

// GOOD - Take ownership when needed
fn process(data: Vec<Item>) {
    for item in data {
        // consume item
    }
}

Pre-commit 设置

.pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: cargo-fmt
        name: cargo fmt
        entry: cargo fmt --
        language: system
        types: [rust]

      - id: cargo-clippy
        name: cargo clippy
        entry: cargo clippy --all-targets --all-features -- -D warnings
        language: system
        types: [rust]
        pass_filenames: false

      - id: cargo-test
        name: cargo test
        entry: cargo test
        language: system
        types: [rust]
        pass_filenames: false

Makefile

.PHONY: fmt lint test check quality

fmt:
	cargo fmt

lint:
	cargo clippy --all-targets --all-features -- -D warnings

test:
	cargo test

check:
	cargo check --all-targets --all-features

quality: fmt check lint test

VS Code 设置

// .vscode/settings.json
{
  "[rust]": {
    "editor.defaultFormatter": "rust-lang.rust-analyzer",
    "editor.formatOnSave": true
  },
  "rust-analyzer.check.command": "clippy",
  "rust-analyzer.check.extraArgs": ["--all-targets", "--all-features"],
  "rust-analyzer.diagnostics.disabled": [],
  "rust-analyzer.lens.run.enable": true,
  "rust-analyzer.lens.debug.enable": true
}

质量指标目标

指标目标工具
认知复杂度< 15Clippy
函数行数< 50Clippy
参数数量< 5Clippy
unsafe 代码块尽量减少Clippy
测试覆盖率> 80%cargo-tarpaulin

CI/CD 集成

GitHub Actions
name: Quality
on: [push, pull_request]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - name: Cache cargo
        uses: Swatinem/rust-cache@v2

      - name: Check formatting
        run: cargo fmt -- --check

      - name: Clippy
        run: cargo clippy --all-targets --all-features -- -D warnings

      - name: Run tests
        run: cargo test --all-features

      - name: Build docs
        run: cargo doc --no-deps
        env:
          RUSTDOCFLAGS: -D warnings

反模式

反模式不良影响正确做法
在库代码中使用 unwrap()恐慌会向上传播使用 ? 运算符
过度使用 clone()造成性能开销尽可能借用
#[allow(clippy::all)]隐藏所有问题允许特定检查项
unsafe 未附注释安全性不明确记录不变量
所有内容都用字符串表示缺乏类型安全使用枚举或 newtype
函数过于庞大难以测试和维护拆分为更小的函数

快速故障排除

问题可能原因解决方案
Clippy 误报边缘情况或有意为之使用 #[allow(clippy::lint)] 并添加注释
rustfmt 修改代码格式偏好不同配置 rustfmt.toml
检查项冲突Pedantic 与 nursery 冲突在 Cargo.toml 中设置优先级
编译缓慢依赖项过多使用 cargo-chef 进行缓存
死代码警告未使用的导出项添加 #[cfg(test)] 或删除

相关技能

评论

支持 Markdown