Skip to content

feat: Add nolint directive support to errstklint#4

Merged
tomoemon merged 1 commit into
mainfrom
fix-exclude-pattern-matching
Nov 9, 2025
Merged

feat: Add nolint directive support to errstklint#4
tomoemon merged 1 commit into
mainfrom
fix-exclude-pattern-matching

Conversation

@tomoemon

@tomoemon tomoemon commented Nov 9, 2025

Copy link
Copy Markdown
Owner

Summary

Added support for golangci-lint compatible nolint directives to allow excluding specific functions or files from linting.

Supported Directives

Function-level exclusion

//nolint:errstklint
func HelperFunction() (err error) {
    // No defer required - excluded from linting
    return nil
}

// Alternative format (staticcheck style)
//lint:ignore errstklint reason for exclusion
func FastPath() (err error) {
    return nil
}

// Multiple linters
//nolint:errstklint,unused,staticcheck
func TemporaryCode() (err error) {
    return nil
}

File-level exclusion

//nolint:errstklint
package testhelpers

// All functions in this file are excluded

// Alternative format
//lint:file-ignore errstklint generated code
package generated

Features

  • golangci-lint compatible: Follows standard //nolint directive format
  • staticcheck compatible: Supports //lint:ignore format
  • Function-level exclusion: Exclude individual functions
  • File-level exclusion: Exclude entire files
  • Multiple linter support: //nolint:errstklint,other
  • No line-level support: Not needed for this linter's use case

Implementation

Changes to analyzer.go

  1. Added directive parsing:

    • parseNolintDirectives() - Parses comments for nolint/lint:ignore directives
    • shouldIgnoreLinter() - Checks if errstklint is in the linter list
    • createIgnoredRange() - Creates line ranges for ignored code
    • isPositionIgnored() - Checks if a position falls within ignored range
  2. Regex patterns:

    • nolintPattern: ^nolint(?::([\w,]+))?(?:\s|$)
    • lintIgnorePattern: ^lint:(ignore|file-ignore)\s+(\S+)(?:\s+(.+))?$
  3. Integration: Modified run() function to parse directives and check before reporting

Test Coverage

Created comprehensive test cases in testdata/src/c/:

nolint.go - Function-level directives:

  • //nolint:errstklint
  • //nolint:all
  • //nolint:errstklint,unused
  • //lint:ignore errstklint reason
  • Negative test for wrong linter name

file_nolint.go - File-level //nolint:errstklint

file_lint_ignore.go - File-level //lint:file-ignore errstklint

All tests pass:

$ go test -v ./errstklint
=== RUN   TestAnalyzer
--- PASS: TestAnalyzer (0.13s)
=== RUN   TestAnalyzerWithNolint
--- PASS: TestAnalyzerWithNolint (0.02s)
=== RUN   TestShouldExclude
--- PASS: TestShouldExclude (0.00s)
=== RUN   TestMatchDoubleStarPattern
--- PASS: TestMatchDoubleStarPattern (0.00s)
PASS

Documentation Updates

Updated Files

  1. analyzer.go Doc string: Added examples of all directive formats
  2. errstklint/README.md:
    • Added "Excluding Specific Functions or Files" section
    • Examples of all directive formats
    • Corrected golangci-lint exclusion rules format (linters.exclusions.rules)
  3. README.md: Added quick examples of nolint usage

golangci-lint Integration

Users can combine nolint directives with golangci-lint exclusion rules:

linters:
  exclusions:
    rules:
      # Disable for test files
      - path: '(.+)_test\.go'
        linters:
          - errstklint

Note: Exclusion rules are handled by golangci-lint core automatically.

Design Decisions

Why no line-level nolint support?

errstklint detects missing defer errstk.Wrap(&err) which is a function-level issue, not a line-specific issue. Line-level exclusion doesn't make semantic sense for this linter.

Why both nolint and lint:ignore?

  • //nolint:errstklint - golangci-lint standard (most common)
  • //lint:ignore errstklint - staticcheck standard (requires reason)
  • Supporting both maximizes compatibility

Examples

Before (no exclusion possible)

func TestHelper() (err error) {
    // Want: no error reported for test helper
    // Got: "function TestHelper returns error but missing defer errstk.Wrap(&err)"
    return nil
}

After (with nolint)

//nolint:errstklint
func TestHelper() (err error) {
    // No error reported - excluded by directive
    return nil
}

Related Issues

This PR addresses the need for fine-grained control over linting without modifying source code structure or using file-level exclude patterns.

🤖 Generated with Claude Code

Added support for golangci-lint compatible nolint directives to allow
excluding specific functions or files from linting.

Supported directives:
- //nolint:errstklint (function-level)
- //nolint:all (all linters)
- //nolint:errstklint,other (multiple linters)
- //lint:ignore errstklint reason (staticcheck style)
- //lint:file-ignore errstklint reason (file-level)

Features:
- Function-level exclusion with //nolint before function
- File-level exclusion with //nolint before package
- Compatible with golangci-lint standards
- Supports both nolint and lint:ignore formats
- No support for line-level nolint (not needed for this linter)

Changes:
- Added nolint directive parsing to analyzer.go
- Added ignoredRange tracking for excluded code
- Added comprehensive test cases for all directive types
- Updated documentation (README.md, errstklint/README.md)
- Added examples of exclude-rules in golangci-lint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@tomoemon
tomoemon merged commit d07f106 into main Nov 9, 2025
1 check passed
@tomoemon
tomoemon deleted the fix-exclude-pattern-matching branch November 9, 2025 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant