Use this package when you want ready-made lint rules for Swift packages, to run with swift-linter or another runner built on swift-lint. Start from Lint.Rule.Bundle.universal to enable the whole set, or depend on one Linter Rule product and enable its rules by ID. To write rules of your own, use swift-lint. To run rules over a package, use swift-linter.
- Rules read syntax only, with no type checking, and most see one file at a time. A conformance, class or associated type declared in another file is not seen. The rules "conflicting dependency url" and "undeclared module import" are the exceptions: they read other files of the package on disk.
Lint.Rule.Bundle.universalenables every rule in this package except "comment". Some rules are enabled at a higher severity than their own default.- "blocking call in async" skips files whose path starts with
Tests/. It counts a call as async when it sits in an async function, initializer or accessor, in a closure marked async, in a closure passed toTaskorTask.detached, or in a closure that contains an await. Any other closure is synchronous, even inside an async function, so work handed to a thread pool in a plain closure is not flagged. An awaited call is never flagged, and@concurrentdoes not exempt a function. - "mock factory zero collision" applies only to files whose path contains
/Tests/. - "extension noncopyable constraint" skips a file whose path contains " where ", an extension on a type written without generic arguments or a where clause, an extension on one of a fixed list of standard library types such as
ArrayandOptional, an extension that uses a parameter pack, and one that requiresCopyableexplicitly. - "sendable struct with class member" knows a type is a class only when the class is declared in the same file or is one of a few well-known system classes. Computed and observed properties are ignored.
- "unchecked sendable noncopyable" flags every noncopyable struct that conforms to
@unchecked Sendable, without looking at its stored properties. - "usable from inline internal import" considers only imports written with
internal. It flags such an import when any identifier inside a@usableFromInlinedeclaration in the file is the module's name. - "redundant refinement" compares the last component of each type name against a fixed table of standard library refinements, so a qualified name matches by its leaf.
- "conflicting dependency url" runs only on a
Package.swift. It reads thePackage.resolvedbeside it, in format 1, 2 or 3, and the manifests under.build/checkouts, whose directories are matched case-insensitively. Two locations are the same when they agree after lowercasing and dropping the scheme, the user,.gitand trailing slashes, with an scp-stylehost:pathread ashost/path. A checkout's spelling counts only when a target one of its products reaches uses it with the traits the graph enables. Without aPackage.resolved, or for an unpinned identity, nothing is reported. A conflict found in a checkout is reported at the root manifest's own spelling of that package. - "undeclared module import" runs only on the package manifest. It checks imports in
SourcesandTests, skipping nested packages, and only module names that contain an underscore and don't start with one. Each module is reported once, at thePackagecall. - "comment" flags every comment, documentation comments included. It admits only
// swift-linter:directives, the// swift-tools-version:line, and one// REASON:line directly under a disable directive. - "malformed suppression directive" accepts exactly
// swift-linter:disable:nextor// swift-linter:disable:linefollowed by a rule ID. Any other line comment that starts withswift-linter:is flagged. Documentation comments are not scanned. Lint.Scope.Index.of(_:)reads every Swift file under the package root once per process and caches the result by root. Changes on disk after that are not seen. Folders such as.build,.gitandcheckouts, and.docccatalogs, are skipped.Lint.License.Header.recognize(in:)looks only at comment blocks before the first line of code. A block counts as a license header when it mentions both "copyright" and "licensed under". A block that mentions a license without both is refused, and so is a license marker in a comment after the code starts.