Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add coverage statistics #5907

Open
wants to merge 62 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
6798fef
Initial implementation
mildm8nnered Dec 22, 2024
0e9c089
Improved rule counts
mildm8nnered Dec 22, 2024
573a4fa
Started to add tests
mildm8nnered Dec 22, 2024
e80cff0
Added report_coverage configuration file option
mildm8nnered Dec 22, 2024
4a413f9
Added unit tests
mildm8nnered Dec 22, 2024
1ea4e59
SwiftLint fixes
mildm8nnered Dec 22, 2024
ce65b6b
Unit test fixes
mildm8nnered Dec 22, 2024
593b876
More tidyup
mildm8nnered Dec 23, 2024
5f8c05d
Try and account for custom rules as well
mildm8nnered Dec 23, 2024
79f41a4
Added disable all step
mildm8nnered Dec 23, 2024
30e31b5
Added documentation
mildm8nnered Dec 23, 2024
86f9a20
tweak
mildm8nnered Dec 23, 2024
a617b6c
Tweaks
mildm8nnered Dec 23, 2024
c3b9384
Use the linters rules, not the top level configuration
mildm8nnered Dec 23, 2024
7eb28ae
Improved custom rule coverage
mildm8nnered Dec 23, 2024
0e31f40
Always enable coverage (so we can use the CI speed benchmarks)
mildm8nnered Dec 23, 2024
ed10d67
Linter fixes
mildm8nnered Dec 23, 2024
37e0b32
Improvements
mildm8nnered Dec 23, 2024
6d2ae01
Disable region caching
mildm8nnered Dec 23, 2024
51688af
Remove cached regions temporarily
mildm8nnered Dec 23, 2024
258c114
Tidyup
mildm8nnered Dec 24, 2024
918a209
Tweaks
mildm8nnered Dec 24, 2024
00afc9f
Refactor
mildm8nnered Dec 24, 2024
293cd1b
Cleanup
mildm8nnered Dec 24, 2024
8ae4e3a
Sigh
mildm8nnered Dec 24, 2024
093c611
Improved custom_rules handling
mildm8nnered Dec 24, 2024
1bb20a4
Removed old caching
mildm8nnered Dec 24, 2024
cd7ae54
Added regionsCaching
mildm8nnered Dec 24, 2024
3a6692c
Refactoring
mildm8nnered Dec 24, 2024
f90c3e5
refactor
mildm8nnered Dec 24, 2024
533a319
That was a struggle
mildm8nnered Dec 24, 2024
e115ccb
Refactoring
mildm8nnered Dec 24, 2024
737391f
Tweaked tests more
mildm8nnered Dec 24, 2024
277eadd
More cleanup
mildm8nnered Dec 24, 2024
70acf94
Refactored
mildm8nnered Dec 24, 2024
48a9282
Refactor
mildm8nnered Dec 24, 2024
96b624c
More refactoring
mildm8nnered Dec 24, 2024
cf8ebea
More tweaking
mildm8nnered Dec 24, 2024
0de76d9
Refactoring
mildm8nnered Dec 24, 2024
37b7aea
Refactored tests
mildm8nnered Dec 25, 2024
126c09a
Refactored tests
mildm8nnered Dec 25, 2024
881d8fe
Handle special case where multiple identifiers are specified for a si…
mildm8nnered Dec 25, 2024
080fec5
But broken
mildm8nnered Dec 25, 2024
9b3b2cb
More refactoring
mildm8nnered Dec 25, 2024
7c58d29
Fixed some more cases
mildm8nnered Dec 25, 2024
8e7c09c
Refactor
mildm8nnered Dec 25, 2024
81e2d5a
Rewrote the documentation
mildm8nnered Dec 26, 2024
a97edf1
Removed some blank lines
mildm8nnered Dec 26, 2024
7fa58d5
added report_coverage
mildm8nnered Dec 26, 2024
548f1cb
Added more docs
mildm8nnered Dec 26, 2024
97f31ae
More unit test refactoring
mildm8nnered Dec 26, 2024
c694fd0
Autocorrects
mildm8nnered Dec 26, 2024
51bc94f
More refactoring
mildm8nnered Dec 26, 2024
4d4a49b
Renaming
mildm8nnered Dec 26, 2024
3b242c7
Use default values
mildm8nnered Dec 26, 2024
68639f1
More test refactoring
mildm8nnered Dec 26, 2024
3ed0645
Linter fixes
mildm8nnered Dec 26, 2024
99af4ca
Fixed nesting test
mildm8nnered Dec 26, 2024
35173b7
blank -> empty
mildm8nnered Dec 27, 2024
9ab0c1b
added
mildm8nnered Dec 27, 2024
460c0b6
Slight refactor
mildm8nnered Dec 27, 2024
60257b8
tweaked
mildm8nnered Dec 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@

#### Experimental

* None.
* Adds a new `--report-coverage` command line option for the `lint` and `analyze` subcommands, and an
equivalent `report_coverage` configuration file setting. Coverage is measured against enabled
rules (reflecting disablement of enabled rules via `swiftlint:disable`), and also against all linter
or analyzer rules (reflecting the actual usage of Swiftlint versus its potential).
[Martin Redington](https://github.com/mildm8nnered)
[#5907](https://github.com/realm/SwiftLint/issues/5907)

#### Enhancements

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,9 @@ write_baseline: Baseline.json
# If true, SwiftLint will check for updates after linting or analyzing.
check_for_updates: true

# If true, SwiftLint will report coverage statistics after linting or analyzing.
report_coverage: true

# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
Expand Down
7 changes: 7 additions & 0 deletions Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ private let commandsCache = Cache { file -> [Command] in
return CommandVisitor(locationConverter: file.locationConverter)
.walk(file: file, handler: \.commands)
}
private let regionsCache = Cache { file -> [Region] in
file.regions()
}
private let syntaxMapCache = Cache { file in
responseCache.get(file).map { SwiftLintSyntaxMap(value: SyntaxMap(sourceKitResponse: $0)) }
}
Expand Down Expand Up @@ -168,6 +171,8 @@ extension SwiftLintFile {

public var invalidCommands: [Command] { commandsCache.get(self).filter { !$0.isValid } }

public var regions: [Region] { regionsCache.get(self) }

public var syntaxTokensByLines: [[SwiftLintSyntaxToken]] {
guard let syntaxTokensByLines = syntaxTokensByLinesCache.get(self) else {
if let handler = assertHandler {
Expand Down Expand Up @@ -204,6 +209,7 @@ extension SwiftLintFile {
foldedSyntaxTreeCache.invalidate(self)
locationConverterCache.invalidate(self)
commandsCache.invalidate(self)
regionsCache.invalidate(self)
linesWithTokensCache.invalidate(self)
}

Expand All @@ -219,6 +225,7 @@ extension SwiftLintFile {
foldedSyntaxTreeCache.clear()
locationConverterCache.clear()
commandsCache.clear()
regionsCache.clear()
linesWithTokensCache.clear()
}
}
Expand Down
2 changes: 1 addition & 1 deletion Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ extension SwiftLintFile {
}

public func ruleEnabled(violatingRanges: [NSRange], for rule: some Rule) -> [NSRange] {
let fileRegions = regions()
let fileRegions = regions
if fileRegions.isEmpty { return violatingRanges }
return violatingRanges.filter { range in
let region = fileRegions.first {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public extension SwiftSyntaxCorrectableRule {
}

let locationConverter = file.locationConverter
let disabledRegions = file.regions()
let disabledRegions = file.regions
.filter { $0.areRulesDisabled(ruleIDs: Self.description.allIdentifiers) }
.compactMap { $0.toSourceRange(locationConverter: locationConverter) }

Expand Down Expand Up @@ -91,7 +91,7 @@ open class ViolationsSyntaxRewriter<Configuration: RuleConfiguration>: SyntaxRew
public lazy var locationConverter = file.locationConverter
/// The regions in the traversed file that are disabled by a command.
public lazy var disabledRegions = {
file.regions()
file.regions
.filter { $0.areRulesDisabled(ruleIDs: Configuration.Parent.description.allIdentifiers) }
.compactMap { $0.toSourceRange(locationConverter: locationConverter) }
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extension Configuration {
excludedPaths: mergedIncludedAndExcluded.excludedPaths,
indentation: childConfiguration.indentation,
warningThreshold: mergedWarningTreshold(with: childConfiguration),
reportCoverage: childConfiguration.reportCoverage,
reporter: reporter,
cachePath: cachePath,
allowZeroLintableFiles: childConfiguration.allowZeroLintableFiles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extension Configuration {
case excluded = "excluded"
case included = "included"
case optInRules = "opt_in_rules"
case reportCoverage = "report_coverage"
case reporter = "reporter"
case swiftlintVersion = "swiftlint_version"
case warningThreshold = "warning_threshold"
Expand Down Expand Up @@ -99,6 +100,7 @@ extension Configuration {
excludedPaths: defaultStringArray(dict[Key.excluded.rawValue]),
indentation: Self.getIndentationLogIfInvalid(from: dict),
warningThreshold: dict[Key.warningThreshold.rawValue] as? Int,
reportCoverage: dict[Key.reportCoverage.rawValue] as? Bool ?? false,
reporter: dict[Key.reporter.rawValue] as? String ?? XcodeReporter.identifier,
cachePath: cachePath ?? dict[Key.cachePath.rawValue] as? String,
pinnedVersion: dict[Key.swiftlintVersion.rawValue].map { ($0 as? String) ?? String(describing: $0) },
Expand Down
15 changes: 13 additions & 2 deletions Source/SwiftLintFramework/Configuration/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public struct Configuration {
/// The threshold for the number of warnings to tolerate before treating the lint as having failed.
public let warningThreshold: Int?

/// Report coverage statistics when linting or analyzing.
public let reportCoverage: Bool

/// The identifier for the `Reporter` to use to report style violations.
public let reporter: String?

Expand All @@ -47,7 +50,7 @@ public struct Configuration {
/// The path to write a baseline to.
public let writeBaseline: String?

/// Check for updates.
/// Check for updates after linting or analyzing.`
public let checkForUpdates: Bool

/// This value is `true` iff the `--config` parameter was used to specify (a) configuration file(s)
Expand Down Expand Up @@ -82,6 +85,7 @@ public struct Configuration {
excludedPaths: [String],
indentation: IndentationStyle,
warningThreshold: Int?,
reportCoverage: Bool,
reporter: String?,
cachePath: String?,
allowZeroLintableFiles: Bool,
Expand All @@ -97,6 +101,7 @@ public struct Configuration {
self.excludedPaths = excludedPaths
self.indentation = indentation
self.warningThreshold = warningThreshold
self.reportCoverage = reportCoverage
self.reporter = reporter
self.cachePath = cachePath
self.allowZeroLintableFiles = allowZeroLintableFiles
Expand All @@ -117,6 +122,7 @@ public struct Configuration {
excludedPaths = configuration.excludedPaths
indentation = configuration.indentation
warningThreshold = configuration.warningThreshold
reportCoverage = configuration.reportCoverage
reporter = configuration.reporter
basedOnCustomConfigurationFiles = configuration.basedOnCustomConfigurationFiles
cachePath = configuration.cachePath
Expand All @@ -143,6 +149,7 @@ public struct Configuration {
/// - parameter indentation: The style to use when indenting Swift source code.
/// - parameter warningThreshold: The threshold for the number of warnings to tolerate before treating the
/// lint as having failed.
/// - parameter reportCoverage: Report coverage data after linting or analyzing.
/// - parameter reporter: The identifier for the `Reporter` to use to report style violations.
/// - parameter cachePath: The location of the persisted cache to use with this configuration.
/// - parameter pinnedVersion: The SwiftLint version defined in this configuration.
Expand All @@ -152,7 +159,7 @@ public struct Configuration {
/// - parameter lenient: Treat errors as warnings.
/// - parameter baseline: The path to read a baseline from.
/// - parameter writeBaseline: The path to write a baseline to.
/// - parameter checkForUpdates: Check for updates to SwiftLint.
/// - parameter checkForUpdates: Check for updates to SwiftLint after linting or analyzing.
package init(
rulesMode: RulesMode = .defaultConfiguration(disabled: [], optIn: []),
allRulesWrapped: [ConfigurationRuleWrapper]? = nil,
Expand All @@ -162,6 +169,7 @@ public struct Configuration {
excludedPaths: [String] = [],
indentation: IndentationStyle = .default,
warningThreshold: Int? = nil,
reportCoverage: Bool = false,
reporter: String? = nil,
cachePath: String? = nil,
pinnedVersion: String? = nil,
Expand Down Expand Up @@ -193,6 +201,7 @@ public struct Configuration {
excludedPaths: excludedPaths,
indentation: indentation,
warningThreshold: warningThreshold,
reportCoverage: reportCoverage,
reporter: reporter,
cachePath: cachePath,
allowZeroLintableFiles: allowZeroLintableFiles,
Expand Down Expand Up @@ -310,6 +319,7 @@ extension Configuration: Hashable {
hasher.combine(excludedPaths)
hasher.combine(indentation)
hasher.combine(warningThreshold)
hasher.combine(reportCoverage)
hasher.combine(reporter)
hasher.combine(allowZeroLintableFiles)
hasher.combine(strict)
Expand All @@ -328,6 +338,7 @@ extension Configuration: Hashable {
lhs.excludedPaths == rhs.excludedPaths &&
lhs.indentation == rhs.indentation &&
lhs.warningThreshold == rhs.warningThreshold &&
lhs.reportCoverage == rhs.reportCoverage &&
lhs.reporter == rhs.reporter &&
lhs.basedOnCustomConfigurationFiles == rhs.basedOnCustomConfigurationFiles &&
lhs.cachePath == rhs.cachePath &&
Expand Down
Loading