diff --git a/Rules.md b/Rules.md index 111f03734..108061cb2 100644 --- a/Rules.md +++ b/Rules.md @@ -1300,7 +1300,11 @@ As per Apple's recommendation ## strongifiedSelf -Remove backticks around `self` in Optional unwrap expressions. +Standardize to use self when strongifying self. Remove backticks around `self`. + +Option | Description +--- | --- +`--strongselfids` | Comma-delimited list of ids that should be replaced with self
Examples diff --git a/Sources/Options.swift b/Sources/Options.swift index 4b6248fda..8932b4b17 100644 --- a/Sources/Options.swift +++ b/Sources/Options.swift @@ -263,6 +263,7 @@ public struct FormatOptions: CustomStringConvertible { public var tabWidth: Int public var maxWidth: Int public var noSpaceOperators: [String] + public var strongSelfIds: [String] // Deprecated public var indentComments: Bool @@ -314,6 +315,7 @@ public struct FormatOptions: CustomStringConvertible { tabWidth: Int = 0, maxWidth: Int = 0, noSpaceOperators: [String] = [], + strongSelfIds: [String] = [], // Doesn't really belong here, but hard to put elsewhere fragment: Bool = false, ignoreConflictMarkers: Bool = false, @@ -357,6 +359,7 @@ public struct FormatOptions: CustomStringConvertible { self.tabWidth = tabWidth self.maxWidth = maxWidth self.noSpaceOperators = noSpaceOperators + self.strongSelfIds = strongSelfIds // Doesn't really belong here, but hard to put elsewhere self.fragment = fragment self.ignoreConflictMarkers = ignoreConflictMarkers diff --git a/Sources/OptionsDescriptor.swift b/Sources/OptionsDescriptor.swift index 266fb8d9d..581f1aa58 100644 --- a/Sources/OptionsDescriptor.swift +++ b/Sources/OptionsDescriptor.swift @@ -252,6 +252,7 @@ extension FormatOptions.Descriptor { tabWidth, maxWidth, noSpaceOperators, + strongSelfIds, // Deprecated indentComments, @@ -577,6 +578,13 @@ extension FormatOptions.Descriptor { } } ) + static let strongSelfIds = FormatOptions.Descriptor( + argumentName: "strongselfids", + propertyName: "strongSelfIds", + displayName: "Strongified Self Identifiers", + help: "Comma-delimited list of ids that should be replaced with self", + keyPath: \FormatOptions.strongSelfIds + ) // MARK: - Internal diff --git a/Sources/Rules.swift b/Sources/Rules.swift index 52e372e38..45be446b3 100644 --- a/Sources/Rules.swift +++ b/Sources/Rules.swift @@ -3758,20 +3758,24 @@ public struct _FormatRules { } } - /// Removed backticks from `self` when strongifying + /// Standardize to use self when strongifying self public let strongifiedSelf = FormatRule( - help: "Remove backticks around `self` in Optional unwrap expressions." + help: "Standardize to use self when strongifying self. Remove backticks around `self`.", + options: ["strongselfids"] ) { formatter in guard formatter.options.swiftVersion >= "4.2" else { return } - formatter.forEach(.identifier("`self`")) { i, _ in - guard let equalIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: i, if: { - $0 == .operator("=", .infix) - }), formatter.next(.nonSpaceOrCommentOrLinebreak, after: equalIndex) == .identifier("self") else { - return + let strongSelfIds = formatter.options.strongSelfIds + ["`self`"] + strongSelfIds.forEach { idName in + formatter.forEach(.identifier(idName)) { i, _ in + guard let equalIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: i, if: { + $0 == .operator("=", .infix) + }), formatter.next(.nonSpaceOrCommentOrLinebreak, after: equalIndex) == .identifier("self") else { + return + } + formatter.replaceToken(at: i, with: .identifier("self")) } - formatter.replaceToken(at: i, with: .identifier("self")) } } diff --git a/Tests/ArgumentsTests.swift b/Tests/ArgumentsTests.swift index fe3448e05..b87cf1163 100644 --- a/Tests/ArgumentsTests.swift +++ b/Tests/ArgumentsTests.swift @@ -200,7 +200,7 @@ class ArgumentsTests: XCTestCase { } func testCommandLineArgumentsAreCorrect() { - let output = ["allman": "false", "wraparguments": "preserve", "stripunusedargs": "always", "self": "remove", "header": "ignore", "importgrouping": "alphabetized", "fractiongrouping": "disabled", "binarygrouping": "4,8", "octalgrouping": "4,8", "indentcase": "false", "trimwhitespace": "always", "decimalgrouping": "3,6", "exponentgrouping": "disabled", "patternlet": "hoist", "commas": "always", "wrapcollections": "preserve", "semicolons": "inline", "indent": "4", "exponentcase": "lowercase", "operatorfunc": "spaced", "symlinks": "ignore", "elseposition": "same-line", "empty": "void", "hexliteralcase": "uppercase", "linebreaks": "lf", "hexgrouping": "4,8", "ifdef": "indent", "closingparen": "balanced", "selfrequired": "", "trailingclosures": "", "xcodeindentation": "disabled", "fragment": "false", "conflictmarkers": "reject", "tabwidth": "unspecified", "maxwidth": "none", "nospaceoperators": ""] + let output = ["allman": "false", "wraparguments": "preserve", "stripunusedargs": "always", "self": "remove", "header": "ignore", "importgrouping": "alphabetized", "fractiongrouping": "disabled", "binarygrouping": "4,8", "octalgrouping": "4,8", "indentcase": "false", "trimwhitespace": "always", "decimalgrouping": "3,6", "exponentgrouping": "disabled", "patternlet": "hoist", "commas": "always", "wrapcollections": "preserve", "semicolons": "inline", "indent": "4", "exponentcase": "lowercase", "operatorfunc": "spaced", "symlinks": "ignore", "elseposition": "same-line", "empty": "void", "hexliteralcase": "uppercase", "linebreaks": "lf", "hexgrouping": "4,8", "ifdef": "indent", "closingparen": "balanced", "selfrequired": "", "trailingclosures": "", "xcodeindentation": "disabled", "fragment": "false", "conflictmarkers": "reject", "tabwidth": "unspecified", "maxwidth": "none", "nospaceoperators": "", "strongselfids": ""] XCTAssertEqual(argumentsFor(.default), output) } @@ -557,4 +557,9 @@ class ArgumentsTests: XCTestCase { let options = try Options(["nospaceoperators": "...,..<"], in: "") XCTAssertEqual(options.formatOptions?.noSpaceOperators, ["...", "..<"]) } + + func testParseStrongSelfIds() throws { + let options = try Options(["strongselfids": "ss,sSelf,strongSelf"], in: "") + XCTAssertEqual(options.formatOptions?.strongSelfIds, ["ss", "sSelf", "strongSelf"]) + } } diff --git a/Tests/RulesTests.swift b/Tests/RulesTests.swift index 5db07710b..58a146318 100644 --- a/Tests/RulesTests.swift +++ b/Tests/RulesTests.swift @@ -8450,6 +8450,31 @@ class RulesTests: XCTestCase { testFormatting(for: input, rule: FormatRules.strongifiedSelf) } + func testStrongSelfConvertedToSelfIfDefinedInOptions() { + let input = """ + { [weak self] in + guard let strongSelf = self else { return } + } + """ + let output = """ + { [weak self] in + guard let self = self else { return } + } + """ + let options = FormatOptions(strongSelfIds: ["strongSelf"], swiftVersion: "4.2") + testFormatting(for: input, output, rule: FormatRules.strongifiedSelf, options: options) + } + + func testStrongSelfNotConvertedToSelfIfNotDefinedInOptions() { + let input = """ + { [weak self] in + guard let strongSelf = self else { return } + } + """ + let options = FormatOptions(swiftVersion: "4.2") + testFormatting(for: input, rule: FormatRules.strongifiedSelf, options: options) + } + // MARK: redundantObjc func testRedundantObjcRemovedFromBeforeOutlet() { diff --git a/Tests/XCTestManifests.swift b/Tests/XCTestManifests.swift index 2f923e510..d1c4cb8b6 100644 --- a/Tests/XCTestManifests.swift +++ b/Tests/XCTestManifests.swift @@ -55,6 +55,7 @@ extension ArgumentsTests { ("testParseQuoteArguments", testParseQuoteArguments), ("testParseQuotedEscapedN", testParseQuotedEscapedN), ("testParseSimpleArguments", testParseSimpleArguments), + ("testParseStrongSelfIds", testParseStrongSelfIds), ("testParseUnexcludedURLsFileOption", testParseUnexcludedURLsFileOption), ("testParseUppercaseIgnoreFileHeader", testParseUppercaseIgnoreFileHeader), ("testPreprocessArguments", testPreprocessArguments), @@ -1470,6 +1471,8 @@ extension RulesTests { ("testStripHeader", testStripHeader), ("testStrippingSwiftNamespaceDoesNotStripPreviousSwiftNamespaceReferences", testStrippingSwiftNamespaceDoesNotStripPreviousSwiftNamespaceReferences), ("testStrippingSwiftNamespaceInOptionalTypeWhenConvertedToSugar", testStrippingSwiftNamespaceInOptionalTypeWhenConvertedToSugar), + ("testStrongSelfConvertedToSelfIfDefinedInOptions", testStrongSelfConvertedToSelfIfDefinedInOptions), + ("testStrongSelfNotConvertedToSelfIfNotDefinedInOptions", testStrongSelfNotConvertedToSelfIfNotDefinedInOptions), ("testsTupleNotUnwrapped", testsTupleNotUnwrapped), ("testsTupleOfClosuresNotUnwrapped", testsTupleOfClosuresNotUnwrapped), ("testSubscriptFunctionCallNotUnwrapped", testSubscriptFunctionCallNotUnwrapped),