From c1650e691861eac949ebc6414f726bfe677a74df Mon Sep 17 00:00:00 2001 From: Marcelo Fabri Date: Sat, 3 Sep 2022 22:11:57 -0700 Subject: [PATCH] Add `excludes_trivial_init` for `missing_docs (#4152) Fixes #4107 --- CHANGELOG.md | 5 ++- .../Rules/Lint/MissingDocsRule.swift | 33 ++++++++++++++++--- .../MissingDocsRuleConfiguration.swift | 21 +++++++++--- .../MissingDocsRuleTests.swift | 30 +++++++++++++---- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b6d5f5693..f68c365742 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,10 @@ #### Enhancements -* None. +* Add new `excludes_trivial_init` configuration for `missing_docs` rule + to exclude initializers without any parameters. + [Marcelo Fabri](https://github.com/marcelofabri) + [#4107](https://github.com/realm/SwiftLint/issues/4107) #### Bug Fixes diff --git a/Source/SwiftLintFramework/Rules/Lint/MissingDocsRule.swift b/Source/SwiftLintFramework/Rules/Lint/MissingDocsRule.swift index 88a3de494e..882433d562 100644 --- a/Source/SwiftLintFramework/Rules/Lint/MissingDocsRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/MissingDocsRule.swift @@ -4,7 +4,8 @@ private extension SwiftLintFile { func missingDocOffsets(in dictionary: SourceKittenDictionary, acls: [AccessControlLevel], excludesExtensions: Bool, - excludesInheritedTypes: Bool) -> [(ByteCount, AccessControlLevel)] { + excludesInheritedTypes: Bool, + excludesTrivialInit: Bool) -> [(ByteCount, AccessControlLevel)] { if dictionary.enclosedSwiftAttributes.contains(.override) || (dictionary.inheritedTypes.isNotEmpty && excludesInheritedTypes) { return [] @@ -14,9 +15,18 @@ private extension SwiftLintFile { in: $0, acls: acls, excludesExtensions: excludesExtensions, - excludesInheritedTypes: excludesInheritedTypes + excludesInheritedTypes: excludesInheritedTypes, + excludesTrivialInit: excludesTrivialInit ) } + + let isTrivialInit = dictionary.declarationKind == .functionMethodInstance && + dictionary.name == "init()" && + dictionary.enclosedVarParameters.isEmpty + if isTrivialInit && excludesTrivialInit { + return substructureOffsets + } + guard let kind = dictionary.declarationKind, (!SwiftDeclarationKind.extensionKinds.contains(kind) || !excludesExtensions), case let isDeinit = kind == .functionMethodInstance && dictionary.name == "deinit", @@ -73,7 +83,13 @@ public struct MissingDocsRule: OptInRule, ConfigurationProviderRule { """), Example(""" public extension A {} - """) + """), + Example(""" + /// docs + public class A { + public init() {} + } + """, configuration: ["excludes_trivial_init": true]) ], triggeringExamples: [ // public, undocumented @@ -93,7 +109,13 @@ public struct MissingDocsRule: OptInRule, ConfigurationProviderRule { public let b: Int } - """) + """), + Example(""" + /// docs + public class A { + public init(argument: String) {} + } + """, configuration: ["excludes_trivial_init": true]) ] ) @@ -104,7 +126,8 @@ public struct MissingDocsRule: OptInRule, ConfigurationProviderRule { in: dict, acls: acls, excludesExtensions: configuration.excludesExtensions, - excludesInheritedTypes: configuration.excludesInheritedTypes + excludesInheritedTypes: configuration.excludesInheritedTypes, + excludesTrivialInit: configuration.excludesTrivialInit ).map { offset, acl in StyleViolation(ruleDescription: Self.description, severity: configuration.parameters.first { $0.value == acl }?.severity ?? .warning, diff --git a/Source/SwiftLintFramework/Rules/RuleConfigurations/MissingDocsRuleConfiguration.swift b/Source/SwiftLintFramework/Rules/RuleConfigurations/MissingDocsRuleConfiguration.swift index 499b64c6cc..cdbcd884dd 100644 --- a/Source/SwiftLintFramework/Rules/RuleConfigurations/MissingDocsRuleConfiguration.swift +++ b/Source/SwiftLintFramework/Rules/RuleConfigurations/MissingDocsRuleConfiguration.swift @@ -5,6 +5,7 @@ public struct MissingDocsRuleConfiguration: RuleConfiguration, Equatable { ] private(set) var excludesExtensions = true private(set) var excludesInheritedTypes = true + private(set) var excludesTrivialInit = false public var consoleDescription: String { let parametersDescription = parameters.group { $0.severity }.sorted { $0.key.rawValue < $1.key.rawValue }.map { @@ -14,14 +15,16 @@ public struct MissingDocsRuleConfiguration: RuleConfiguration, Equatable { if parametersDescription.isEmpty { return [ "excludes_extensions: \(excludesExtensions)", - "excludes_inherited_types: \(excludesInheritedTypes)" + "excludes_inherited_types: \(excludesInheritedTypes)", + "excludes_trivial_init: \(excludesTrivialInit)" ] .joined(separator: ", ") } else { return [ parametersDescription, "excludes_extensions: \(excludesExtensions)", - "excludes_inherited_types: \(excludesInheritedTypes)" + "excludes_inherited_types: \(excludesInheritedTypes)", + "excludes_trivial_init: \(excludesTrivialInit)" ] .joined(separator: ", ") } @@ -40,6 +43,16 @@ public struct MissingDocsRuleConfiguration: RuleConfiguration, Equatable { excludesInheritedTypes = shouldExcludeInheritedTypes } + if let excludesTrivialInit = dict["excludes_trivial_init"] as? Bool { + self.excludesTrivialInit = excludesTrivialInit + } + + if let parameters = try parameters(from: dict) { + self.parameters = parameters + } + } + + private func parameters(from dict: [String: Any]) throws -> [RuleParameter]? { var parameters: [RuleParameter] = [] for (key, value) in dict { @@ -68,8 +81,6 @@ public struct MissingDocsRuleConfiguration: RuleConfiguration, Equatable { throw ConfigurationError.unknownConfiguration } - if parameters.isNotEmpty { - self.parameters = parameters - } + return parameters.isNotEmpty ? parameters : nil } } diff --git a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift index 6063c71332..c8bc63be16 100644 --- a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift @@ -6,7 +6,8 @@ class MissingDocsRuleTests: XCTestCase { let configuration = MissingDocsRuleConfiguration() XCTAssertEqual( configuration.consoleDescription, - "warning: open, public, excludes_extensions: true, excludes_inherited_types: true" + "warning: open, public, excludes_extensions: true, " + + "excludes_inherited_types: true, excludes_trivial_init: false" ) } @@ -14,7 +15,8 @@ class MissingDocsRuleTests: XCTestCase { let configuration = MissingDocsRuleConfiguration(excludesExtensions: false, excludesInheritedTypes: false) XCTAssertEqual( configuration.consoleDescription, - "warning: open, public, excludes_extensions: false, excludes_inherited_types: false" + "warning: open, public, excludes_extensions: false, " + + "excludes_inherited_types: false, excludes_trivial_init: false" ) } @@ -22,7 +24,8 @@ class MissingDocsRuleTests: XCTestCase { let configuration = MissingDocsRuleConfiguration(excludesExtensions: false, excludesInheritedTypes: true) XCTAssertEqual( configuration.consoleDescription, - "warning: open, public, excludes_extensions: false, excludes_inherited_types: true" + "warning: open, public, excludes_extensions: false, " + + "excludes_inherited_types: true, excludes_trivial_init: false" ) } @@ -30,7 +33,8 @@ class MissingDocsRuleTests: XCTestCase { let configuration = MissingDocsRuleConfiguration(excludesExtensions: true, excludesInheritedTypes: false) XCTAssertEqual( configuration.consoleDescription, - "warning: open, public, excludes_extensions: true, excludes_inherited_types: false" + "warning: open, public, excludes_extensions: true, " + + "excludes_inherited_types: false, excludes_trivial_init: false" ) } @@ -39,7 +43,8 @@ class MissingDocsRuleTests: XCTestCase { parameters: [RuleParameter(severity: .error, value: .open)]) XCTAssertEqual( configuration.consoleDescription, - "error: open, excludes_extensions: true, excludes_inherited_types: true" + "error: open, excludes_extensions: true, " + + "excludes_inherited_types: true, excludes_trivial_init: false" ) } @@ -49,7 +54,8 @@ class MissingDocsRuleTests: XCTestCase { RuleParameter(severity: .warning, value: .public)]) XCTAssertEqual( configuration.consoleDescription, - "error: open, warning: public, excludes_extensions: true, excludes_inherited_types: true" + "error: open, warning: public, excludes_extensions: true, " + + "excludes_inherited_types: true, excludes_trivial_init: false" ) } @@ -59,7 +65,17 @@ class MissingDocsRuleTests: XCTestCase { RuleParameter(severity: .warning, value: .public)]) XCTAssertEqual( configuration.consoleDescription, - "warning: open, public, excludes_extensions: true, excludes_inherited_types: true" + "warning: open, public, excludes_extensions: true, " + + "excludes_inherited_types: true, excludes_trivial_init: false" + ) + } + + func testDescriptionExcludesTrivialInitTrue() { + let configuration = MissingDocsRuleConfiguration(excludesTrivialInit: true) + XCTAssertEqual( + configuration.consoleDescription, + "warning: open, public, excludes_extensions: true, " + + "excludes_inherited_types: true, excludes_trivial_init: true" ) }