Skip to content

Add coverage statistics #5907

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

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
f734a91
Initial implementation
mildm8nnered Dec 22, 2024
ad7a508
Improved rule counts
mildm8nnered Dec 22, 2024
e33d77b
Started to add tests
mildm8nnered Dec 22, 2024
0a373d6
Added report_coverage configuration file option
mildm8nnered Dec 22, 2024
22b879d
Added unit tests
mildm8nnered Dec 22, 2024
fe03919
SwiftLint fixes
mildm8nnered Dec 22, 2024
0449e89
Unit test fixes
mildm8nnered Dec 22, 2024
84a6c10
More tidyup
mildm8nnered Dec 23, 2024
e2260d2
Try and account for custom rules as well
mildm8nnered Dec 23, 2024
3c55a64
Added disable all step
mildm8nnered Dec 23, 2024
3aea230
Added documentation
mildm8nnered Dec 23, 2024
a4e8839
tweak
mildm8nnered Dec 23, 2024
c458209
Tweaks
mildm8nnered Dec 23, 2024
ecfa42b
Use the linters rules, not the top level configuration
mildm8nnered Dec 23, 2024
8e79660
Improved custom rule coverage
mildm8nnered Dec 23, 2024
379b286
Always enable coverage (so we can use the CI speed benchmarks)
mildm8nnered Dec 23, 2024
1da3c6e
Linter fixes
mildm8nnered Dec 23, 2024
18256a5
Improvements
mildm8nnered Dec 23, 2024
dd6d00b
Disable region caching
mildm8nnered Dec 23, 2024
5944045
Remove cached regions temporarily
mildm8nnered Dec 23, 2024
49184d0
Tidyup
mildm8nnered Dec 24, 2024
ae4f9b6
Tweaks
mildm8nnered Dec 24, 2024
86250d9
Refactor
mildm8nnered Dec 24, 2024
5ada08f
Cleanup
mildm8nnered Dec 24, 2024
cd9837e
Sigh
mildm8nnered Dec 24, 2024
cf7b24e
Improved custom_rules handling
mildm8nnered Dec 24, 2024
3086923
Removed old caching
mildm8nnered Dec 24, 2024
bd7d779
Added regionsCaching
mildm8nnered Dec 24, 2024
bb8e9f3
Refactoring
mildm8nnered Dec 24, 2024
c44f436
refactor
mildm8nnered Dec 24, 2024
57abe52
That was a struggle
mildm8nnered Dec 24, 2024
319c069
Refactoring
mildm8nnered Dec 24, 2024
62cce45
Tweaked tests more
mildm8nnered Dec 24, 2024
e2d4c32
More cleanup
mildm8nnered Dec 24, 2024
3ee4f92
Refactored
mildm8nnered Dec 24, 2024
c9bb0a4
Refactor
mildm8nnered Dec 24, 2024
2512e25
More refactoring
mildm8nnered Dec 24, 2024
b7a1b98
More tweaking
mildm8nnered Dec 24, 2024
968aebe
Refactoring
mildm8nnered Dec 24, 2024
2f13035
Refactored tests
mildm8nnered Dec 25, 2024
a2ac9b3
Refactored tests
mildm8nnered Dec 25, 2024
ac5605d
Handle special case where multiple identifiers are specified for a si…
mildm8nnered Dec 25, 2024
1105824
But broken
mildm8nnered Dec 25, 2024
f98a4e3
More refactoring
mildm8nnered Dec 25, 2024
4645cf4
Fixed some more cases
mildm8nnered Dec 25, 2024
ceb5891
Refactor
mildm8nnered Dec 25, 2024
21ee341
Rewrote the documentation
mildm8nnered Dec 26, 2024
31d465d
Removed some blank lines
mildm8nnered Dec 26, 2024
29d2c21
added report_coverage
mildm8nnered Dec 26, 2024
c1eddd8
Added more docs
mildm8nnered Dec 26, 2024
28e8ae9
More unit test refactoring
mildm8nnered Dec 26, 2024
6c97cf7
Autocorrects
mildm8nnered Dec 26, 2024
5867d87
More refactoring
mildm8nnered Dec 26, 2024
3c22b85
Renaming
mildm8nnered Dec 26, 2024
af0a734
Use default values
mildm8nnered Dec 26, 2024
dc2b670
More test refactoring
mildm8nnered Dec 26, 2024
b31c475
Linter fixes
mildm8nnered Dec 26, 2024
cd42eb6
Fixed nesting test
mildm8nnered Dec 26, 2024
f3e243e
blank -> empty
mildm8nnered Dec 27, 2024
276ad09
added
mildm8nnered Dec 27, 2024
5ea3b9f
Slight refactor
mildm8nnered Dec 27, 2024
d686e77
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 @@ -216,7 +216,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 @@ -35,7 +35,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 @@ -76,7 +76,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