NoVerify Documentation

repository·master·Indexed 20 days ago

https://github.com/vkcom/noverify

A high-performance PHP linter and static analyzer written in Go for PHP 7 and 8. NoVerify detects bugs, unreachable code, and style violations with deep semantic understanding. It features incremental analysis, a baseline mode to suppress existing errors, and support for custom rules written in PHP or Go. The toolset also includes phpgrep, a syntax-aware structural search tool for PHP code, and integrates with VSCode, Sublime Text, and PhpStorm.

Tokens
30.4K
Snippets
100
Records
140
Agent score
71%

What's inside NoVerify

  1. Overview of NoVerify Checkers

    master

    NoVerify includes a comprehensive suite of 119 checkers designed to analyze code for errors, style, and best practices.

    By default, most checkers are enabled (102 out of 119), while 17 are disabled to prevent noise. Additionally, 15 of the available checkers support autofixing, allowing the tool to automatically correct certain code patterns.

  2. What is NoVerify

    master

    NoVerify is a high-performance PHP linter designed to find possible bugs and style violations in PHP code. It aims to provide deep code understanding comparable to PHPStorm.

    Key characteristics:

    • No configuration required: Any issue reported in your PHPDoc or PHP code is considered a violation that must be fixed.
    • High Performance: Capable of analyzing approximately 100k lines of code (LOC) per second on a Core i7.
    • Incremental Analysis: Can analyze git changes to show only new reports, with indexing speeds around 1M LOC/s.
    • Language Support: Supports PHP 7 and PHP 8.
    • Modes: Supports Diff and Baseline modes, and provides auto-fixes for certain warnings.
  3. Use PHP variables in PPL patterns

    master

    You can use PHP variable syntax ($<id>) to match specific nodes in the AST.

    • Exact Matching: If you use the same <id> multiple times in a pattern, both instances must match the exact same AST node.
    • Wildcard/Anonymous Matching: Use the special variable $_ to match any node without needing to assign it a specific name or enforcing identity constraints between multiple uses.

    Examples:

    • $x = $y; matches any assignment where the left and right sides are different nodes.
    • $x = $x; matches only self-assignments.
    • $_ = $_ matches any assignment because $_ is a special wildcard.
    $x = $y; // Matches any assignment
    $x = $x; // Matches only self-assignments
    $_ = $_; // Matches any assignment
  4. Understand NoVerify Dynamic Rules

    master

    NoVerify uses Dynamic Rules to perform PHP code inspections. A Rule consists of a PHPDoc comment containing inspection metadata and a phpgrep pattern that defines the syntax to match.

    A Rule file is a valid PHP file containing a sequence of PHP functions or statements. Each function or statement is interpreted as a phpgrep pattern, and the PHPDoc comments provide the necessary metadata to turn those patterns into actionable inspections.

    Because rule files are valid PHP, you can use IDEs like PhpStorm to work with them. To use them in NoVerify, pass the file or directory to the --rules command-line argument.

    Key Terminology:

    • Rule: A pattern + PHPDoc metadata.
    • Rule file: A collection of rules (PHP functions/statements).
    • Rule group: A PHP function that acts as a container for multiple rules. The function name becomes the check name.
    # Run analysis with a specific rule file
    noverify --rules path/to/rules.php
    
    # Run analysis with a folder of rule files (non-recursive)
    noverify --rules path/to/rules_folder/
  5. Use advanced NoVerify modes (Baseline, Diff, Dynamic Rules)

    master

    For large codebases, use these advanced strategies:

    • Baseline Mode: Ignore existing errors and only report new ones (see docs/baseline.md).
    • Git Diff Mode: Run the linter only on changes compared to a previous commit or the master branch (see docs/diff.md).
    • Dynamic Rules: Add custom checks written in PHP without modifying the Go source (see docs/dynamic_rules.md).
  6. Create Rule Groups in Dynamic Rules

    master

    A rule file is organized into Rule groups. Each group is a PHP function. The function name serves as the prefix for the diagnostic names within that group. If the function is inside a namespace, the check name will include the namespace (e.g., namespace api_rules; function check() {} results in api_rules/check).

    You can add metadata to a group using these PHPDoc attributes:

    • @comment: A short description of the checks in the group.
    • @before: An example of code that triggers a warning.
    • @after: An example of fixed code that should not trigger a warning.

    Example of a minimal group:

    /**
     * @comment Description of rules.
     * @before  code with error
     * @after   code without error
     */
    function nameOfCheck() {
    
    }
  7. Understand the phpgrep pattern language (PPL) syntax

    master
    The phpgrep pattern language (PPL) is 100% compatible with PHP syntax. It uses PHP's syntax to describe the Abstract Syntax Tree (AST) structures you want to match. Because it follows PHP syntax, PPL patterns can be parsed by any standard PHP parser. In PPL, whitespace is treated the same as in PHP (it generally doesn't matter where it is placed unless it's syntactically significant).
  8. Understand phpgrep patterns and matchers

    master

    phpgrep uses a pattern language to perform structural searches.

    Key Concepts

    • Variable Matchers: You can specify types for variables within a pattern, such as ${"x:int"} for an integer or ${"x:var"} for a variable name.
    • Wildcard Matcher: The ${"*"} matcher can be used to represent any element in a sequence. This is useful when the position of a specific argument is unknown (e.g., in variadic functions).
    • Filters: Filters are passed as additional arguments after the pattern to apply constraints (e.g., 'x!=20' or 'x~.*_id$').

    Example: Matching null arguments in variadic functions

    To match all foo function calls that have a null argument at any position:

    phpgrep target 'foo(${"*"}, null, ${"*"})'
  9. Use strict-mixed mode for type safety

    master

    In default mode, calling methods on mixed or object types does not trigger warnings for undefined methods/properties. Enabling --strict-mixed forces NoVerify to report these as errors.

    // With --strict-mixed
    function f1($a) {
      $a->foo(); // error: undefined method 'foo'
      $a->boo;   // error: undefined property 'boo'
    }
  10. How Diff mode works

    master

    Diff mode is used to analyze only new or changed code rather than the entire project. It relies on git capabilities to compare the current state of your branch against the state of the master branch from which the branch was created.

    The workflow is as follows:

    1. The linter analyzes the master branch at the point where the feature branch was originally created (the merge base) and collects all reports.
    2. The linter analyzes the current state of your feature branch and collects all reports.
    3. It identifies and displays only the reports that exist in the branch but were not present in the master baseline.

    This ensures that you only see linting errors introduced by your specific changes.

  11. What are Dynamic Rules in NoVerify

    master

    Dynamic rules allow you to create custom NoVerify inspections without writing or recompiling Go code. They work by describing new inspections using phpgrep-like patterns.

    This mechanism is ideal for:

    • Restricting function or method calls (forbidden functions, specific argument combinations, or type constraints).
    • Restricting operators based on types or values (e.g., discouraging < or > for array comparisons).
    • Detecting unwanted language constructions (e.g., unset cast or using require instead of require_once).

    If a check can be expressed via syntax patterns and filters, it can be implemented as a dynamic rule.