I've got some regular ol' XCTestCases using matchers from Nimble. The Nimble expect function uses an autoclosure to get its expect(foo) == bar style matchers. However, with the redundant self option on, SwiftFormat doesn't seem to realize that the reference to self is necessary to make the capture semantics explicit and removes it, resulting in code that no longer compiles.
In other words
class FooTests: XCTestCase {
let foo = 1
func testFoo() {
expect(self.foo) == 1
}
}
turns into
class FooTests: XCTestCase {
let foo = 1
func testFoo() {
expect(foo) == 1
}
}
Which results in the error Reference to property 'foo' in closure requires explicit 'self.' to make capture semantics explicit.
Hmm. I don't think there's any way I can detect that. Darn.
I'll see if I can think of a solution. In the meantime, you'll probably have to use --disable redundantSelf
Yeah, I was thinking about how difficult it would be to detect autoclosures. But you are a wizard 馃敭 so you never know. 馃槢
Disabling the redundant self is the current game plan. Either that or not using Nimble. Or using Quick instead of XCTestCase. I'll figure something out.
Anyway, feel free to close this if there's no good solution, just thought I'd throw the issue out there since I didn't see anything about it already. Thanks for you hard work! Love the tool. 鉂わ笍
I'm having a similar issue with "missing self" in this scenario:
DispatchQueue.main.async {
do {
value = try self.getValue()
completionClosure(value)
} catch let error as NSError {
...
}
}
turns into
DispatchQueue.main.async {
do {
value = try getValue()
completionClosure(value)
} catch let error as NSError {
...
}
}
Which gives me a Call to method 'getValue' in closure requires explicit 'self.' to make capture semantics explicit
So I will also disable the redundantSelf.
@Rerel that looks like a more straightforward bug - I should be able to fix it.
@Rerel are you using SwiftFormat 0.28.2? I'm having trouble reproducing your bug.
@nicklockwood Yes I'm using SwiftFormat 0.28.2.
My bad, I should have added a bit more code, try with something like:
func get(_ completionClosure: @escaping (_ s: String?, _ error: Error) -> Void) {
var value: String?
DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
do {
value = try self.getValue()
completionClosure(value, nil)
} catch let s as NSError {
completionClosure(nil, nil)
}
}
}
SwiftFormat 0.28.2 removes the self in my case :(
@Rerel fixed in 0.28.3
@jarsen This is fixed in 0.30.2. I've just added a special case for expect(), since the Nimble framework is the only place where this issue has arisen so far.
Did this issue creep back into the latest release (0.35.5)?
Formatting using swiftformat is now removing references to self, causing warnings for all variables.
import Foundation
class GameData: NSObject, NSCoding {
var easyDifficulty: Bool {
get {
return **self.**easyDifficulty
}
set(setEasyDifficulty) {
**self**.easyDifficulty = setEasyDifficulty
}
}
**(AFTER SWIFTFORMAT)**
var easyDifficulty: Bool {
get {
return easyDifficulty
}
set(setEasyDifficulty) {
easyDifficulty = setEasyDifficulty
}
}
Warning: Attempting to modify 'easyDifficulty' within its own setter
Version: swiftformat, version 0.35.5
XCode: v9.4.1
@little-bamboo I鈥檝e not encountered this particular scenario before so it鈥檚 possible it was never handled correctly. I鈥檇 be surprised if the bug was introduced in the latest release as that was just a bug fix for an unrelated issue.
I鈥檒l investigate a fix.
@little-bamboo in trying to replicate this I realized that the code example you provided creates an infinite loop and crashes if you try to set or get the property:
var easyDifficulty: Bool {
get {
return self.easyDifficulty
}
set(setEasyDifficulty) {
self.easyDifficulty = setEasyDifficulty
}
}
It seems like it might be a bug that it compiles at all, because calling the getter inside the getter and the setter inside the setter would always result in an infinite recursion (even if you use self).
I assume this wasn't your actual code - do you have a legitimate example?
My apologies. Once I initialized the variables the error went away, sorry for the confusion!
@little-bamboo no problem - I found another bug while investigating yours, so it was helpful after all 馃槉
This bug also appears in 0.47.8 when creating OSLogMessage messages with string interpolation using instance variables.
Example:
import os.log
class LogDemo {
let logger = Logger(subsystem: "sub", category: "cat")
let foo = "foo"
func log() {
// BUG: self should not be removed but it is removed
logger.debug("bug here: \(self.foo)")
}
}
@laszloagardi I believe you can solve this by adding --selfrequired debug to the SwiftFormat arguments. This tells SwiftFormat that the debug() function has autoclosure arguments and should not have self removed.
(ps, it's best to open a new issue when reporting a new bug, as it's easy for me to miss comments on closed issues.)