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
15f87bf
Initial implementation
mildm8nnered Dec 22, 2024
d9b42ac
Improved rule counts
mildm8nnered Dec 22, 2024
b5615e6
Started to add tests
mildm8nnered Dec 22, 2024
105ed1c
Added report_coverage configuration file option
mildm8nnered Dec 22, 2024
1ac8388
Added unit tests
mildm8nnered Dec 22, 2024
4cb7fae
SwiftLint fixes
mildm8nnered Dec 22, 2024
474fe65
Unit test fixes
mildm8nnered Dec 22, 2024
c093b5f
More tidyup
mildm8nnered Dec 23, 2024
69cbf22
Try and account for custom rules as well
mildm8nnered Dec 23, 2024
cf7ef27
Added disable all step
mildm8nnered Dec 23, 2024
f300ec2
Added documentation
mildm8nnered Dec 23, 2024
ade1054
tweak
mildm8nnered Dec 23, 2024
18640f5
Tweaks
mildm8nnered Dec 23, 2024
8b4f45f
Use the linters rules, not the top level configuration
mildm8nnered Dec 23, 2024
f377747
Improved custom rule coverage
mildm8nnered Dec 23, 2024
b8d1663
Always enable coverage (so we can use the CI speed benchmarks)
mildm8nnered Dec 23, 2024
8fd62cc
Linter fixes
mildm8nnered Dec 23, 2024
97024df
Improvements
mildm8nnered Dec 23, 2024
e9d9229
Disable region caching
mildm8nnered Dec 23, 2024
9f4b414
Remove cached regions temporarily
mildm8nnered Dec 23, 2024
79de455
Tidyup
mildm8nnered Dec 24, 2024
95010f2
Tweaks
mildm8nnered Dec 24, 2024
d9809c2
Refactor
mildm8nnered Dec 24, 2024
4c622de
Cleanup
mildm8nnered Dec 24, 2024
5a880d6
Sigh
mildm8nnered Dec 24, 2024
9611343
Improved custom_rules handling
mildm8nnered Dec 24, 2024
0158b96
Removed old caching
mildm8nnered Dec 24, 2024
e6b48b2
Added regionsCaching
mildm8nnered Dec 24, 2024
6831535
Refactoring
mildm8nnered Dec 24, 2024
3c30517
refactor
mildm8nnered Dec 24, 2024
cd4f236
That was a struggle
mildm8nnered Dec 24, 2024
95dd167
Refactoring
mildm8nnered Dec 24, 2024
60c9398
Tweaked tests more
mildm8nnered Dec 24, 2024
7d4c9a4
More cleanup
mildm8nnered Dec 24, 2024
aea1539
Refactored
mildm8nnered Dec 24, 2024
ed9a725
Refactor
mildm8nnered Dec 24, 2024
522748b
More refactoring
mildm8nnered Dec 24, 2024
d598382
More tweaking
mildm8nnered Dec 24, 2024
83e51bd
Refactoring
mildm8nnered Dec 24, 2024
b24f864
Refactored tests
mildm8nnered Dec 25, 2024
13a8257
Refactored tests
mildm8nnered Dec 25, 2024
22bfece
Handle special case where multiple identifiers are specified for a si…
mildm8nnered Dec 25, 2024
23df1f0
But broken
mildm8nnered Dec 25, 2024
ad9e6f5
More refactoring
mildm8nnered Dec 25, 2024
84b38e5
Fixed some more cases
mildm8nnered Dec 25, 2024
f7aa26a
Refactor
mildm8nnered Dec 25, 2024
67b2837
Rewrote the documentation
mildm8nnered Dec 26, 2024
d52c9db
Removed some blank lines
mildm8nnered Dec 26, 2024
438b1b3
added report_coverage
mildm8nnered Dec 26, 2024
d64b064
Added more docs
mildm8nnered Dec 26, 2024
022683a
More unit test refactoring
mildm8nnered Dec 26, 2024
fc0cb5a
Autocorrects
mildm8nnered Dec 26, 2024
f4bc1e4
More refactoring
mildm8nnered Dec 26, 2024
5fc691e
Renaming
mildm8nnered Dec 26, 2024
63fef64
Use default values
mildm8nnered Dec 26, 2024
d657308
More test refactoring
mildm8nnered Dec 26, 2024
8f1de07
Linter fixes
mildm8nnered Dec 26, 2024
55ace75
Fixed nesting test
mildm8nnered Dec 26, 2024
cfb1b8d
blank -> empty
mildm8nnered Dec 27, 2024
dc838a6
added
mildm8nnered Dec 27, 2024
ba28cd1
Slight refactor
mildm8nnered Dec 27, 2024
af5dccd
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 @@ -123,7 +123,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