Skip to content

Software Quality

Linters

A linter is a tool that scans source a file at a time, matching it against a rule set of suspicious patterns and reporting likely bugs. It is the cheap, high-volume end of static analysis, fast enough to run on every save and every diff and tuned to keep false positives low. Only the logical rules do verification work; a linter's stylistic and formatting rules are hygiene.

What it catches

  • Common defect patterns. Rules flag an off-by-one, a missing await, inconsistent equality and a suspicious type cast.
  • API misuse. Rules flag calling a deprecated function, passing the wrong type, ignoring a required return value and misusing a standard-library contract.

Several defect classes have their own static-analysis page even where a lint rule is what ships the check. Taint and regular-expression denial of service (ReDoS) are on deep static analysis, and committed secrets on secret scanning. Every kind of dead code is on dead-code detection. Memory-safety and concurrency depth is on memory safety and concurrency.

Tools

JavaScript / TypeScript

  • ESLint with the typescript-eslint logical subset enabled; the stylistic and formatting subsets go to Prettier.
  • Biome — an alternative to ESLint plus Prettier that runs faster.

Python

  • Ruff — fast, covers a broad rule set, replacing flake8 + many plugins.
  • pylint — does more type inference than Ruff, such as checking a call's argument count; slower and harder to configure.
  • Bandit — security-focused rules.

Rust

  • Clippy — built into the Rust toolchain. A study running Clippy over crates.io found ~21 warnings per thousand lines of code on average (Li et al. 2024)1.

Java / Kotlin

  • SpotBugs — bug-pattern detector for Java bytecode.
  • Error Prone (Google) — runs as a compiler plugin.

C / C++

  • clang-tidy — free, ships with LLVM.
  • Cppcheck — free; targets undefined behavior and dangerous coding constructs.

Go

  • go vet in the standard toolchain.
  • staticcheck — finds bugs and performance issues, offers simplifications, and enforces style rules.
  • golangci-lint runs many linters in one pass.

When to use, when not

Use:

  • At diff time, with a small high-confidence ruleset expanded over time.
  • With logical rules only; hand formatting and style to a formatter so the signal is bugs, not whitespace.

Don't:

  • Gate the build on a complexity metric. Cyclomatic and cognitive complexity are advisory refactoring signals, not verification. A duplicate-branch or identical-condition rule flags an actual likely bug; a complexity threshold flags only "this is large."

Evidence

  • Clippy in the wild. A survey of Rust developers who use Clippy named two concerns above the rest: false positives among its warnings, and the absence of auto-fix for most of them (Li et al. 2024)1.
  • Complexity metrics are weak gates. Cyclomatic complexity (McCabe 1976)2 rests on contested theoretical foundations and in practice largely tracks lines of code, adding little independent predictive value (Shepperd 1988)3. SonarSource's Cognitive Complexity (Campbell 2018)4 reformulates it to target human understandability; a meta-analysis of ten understandability studies found it correlates with comprehension time and subjective ratings, but with mixed results for task correctness — capturing "at least some aspects" of understandability (Muñoz Barón et al. 2020)5.

Classification

  • Quality dimensions: Functionality, Maintainability.
  • Area: General code quality and common defect patterns; per-language tooling run at diff time; API-misuse and suspicious-construct rules.
  • Guarantee: Empirical — depends on rule precision and recall; a high-confidence signal, not a proof.

Referenced by

References


  1. Li, Chunmiao, Yijun Yu, Haitao Wu, Luca Carlig, Shijie Nie, and Lingxiao Jiang. 2024. "Unleashing the Power of Clippy in Real-World Rust Projects." Proceedings of the 2024 IEEE/ACM 46th International Conference on Software Engineering: Companion Proceedings, 318–19. https://doi.org/10.1145/3639478.3643096. ↩↩

  2. McCabe, Thomas J. 1976. "A Complexity Measure." IEEE Transactions on Software Engineering SE-2 (4): 308–20. https://doi.org/10.1109/TSE.1976.233837. ↩

  3. Shepperd, Martin. 1988. "A Critique of Cyclomatic Complexity as a Software Metric." Software Engineering Journal 3 (2): 30–36. https://doi.org/10.1049/sej.1988.0003. ↩

  4. Campbell, G. Ann. 2018. "Cognitive Complexity: An Overview and Evaluation." Proceedings of the 2018 International Conference on Technical Debt (TechDebt '18), 57–58. https://doi.org/10.1145/3194164.3194186. ↩

  5. Muñoz Barón, Marvin, Marvin Wyrich, and Stefan Wagner. 2020. "An Empirical Validation of Cognitive Complexity as a Measure of Source Code Understandability." Proceedings of the 14th ACM/IEEE International Symposium on Empirical Software Engineering and Measurement (ESEM '20), 1–12. https://doi.org/10.1145/3382494.3410636. ↩