SwiftLint icon indicating copy to clipboard operation
SwiftLint copied to clipboard

Unneeded Synthesized Initializer removes needed initializers with property wrappers

Open NachoSoto opened this issue 2 years ago • 3 comments

New Issue Checklist

Describe the bug

This new rule correct actually needed initializers. Example:

private struct Data {
    @PropertyWrapper<E> var e: E

    init(e: E) {
        self.e = e
    }
}

SwiftLint removes that constructor, but it is required to be able to initialize it with a value of type E instead of @PropertyWrapper<E>

Environment

  • SwiftLint version: 0.52.4

NachoSoto avatar Aug 02 '23 20:08 NachoSoto

To add to this, it also removes initializers that just apply property wrappers to the arguments (it does not seem to trigger the rule in the linting digest?)

struct Title {
        let text: String
        let color: Color
        let font: Font

        init(
            @Localised text: String, // 👈 some property wrapper that alters the input
            color: Color,
            font: Font
        ) {
            self.text = text
            self.color = color
            self.font = font
        }
    }

weirder still, it will produce a "Superfluous Disable Command Violation" warning if disabled

        // swiftlint:disable:next unneeded_synthesized_initializer // 👈 stops the removal but produces a superfluous warning
        init(
            @Localised text: String,

swiftlint version: 0.55.1

aclima93 avatar May 17 '24 10:05 aclima93

To add to this, it also removes initializers that just apply property wrappers to the arguments (it does not seem to trigger the rule in the linting digest?)

struct Title {
        let text: String
        let color: Color
        let font: Font

        init(
            @Localised text: String, // 👈 some property wrapper that alters the input
            color: Color,
            font: Font
        ) {
            self.text = text
            self.color = color
            self.font = font
        }
    }

This is addressed by #5594.

weirder still, it will produce a "Superfluous Disable Command Violation" warning if disabled

        // swiftlint:disable:next unneeded_synthesized_initializer // 👈 stops the removal but produces a superfluous warning
        init(
            @Localised text: String,

I'm unable to reproduce this. The disable command works as expected in my little test setup.

SimplyDanny avatar May 17 '24 20:05 SimplyDanny

@NachoSoto: Taking a look at your initially reported example, I wonder why e would be initialized as @PropertyWrapper<E> without the explicit initializer. In a little example, the compiler seems to be happy without the initializer. Could you provide a complete example that shows the issue?

SimplyDanny avatar May 17 '24 21:05 SimplyDanny

@NachoSoto, @aclima93: Are these still issues for you?

SimplyDanny avatar Jul 03 '24 21:07 SimplyDanny

... it also removes initializers that just apply property wrappers to the arguments

This is still happening,

struct Title {
    let text: String

    init(@Localised text: String) {
        self.text = text
    }
}

gets re-written as

struct Title {
    let text: String
}

unless I disable it with unneeded_synthesized_initializer

    // swiftlint:disable:next unneeded_synthesized_initializer
    init(@Localised text: String) {

weirder still, it will produce a "Superfluous Disable Command Violation" warning if disabled

I can no longer reproduce this part.

installed via homebrew and executed as /opt/homebrew/bin/swiftlint --fix && /opt/homebrew/bin/swiftlint

image

aclima93 avatar Jul 04 '24 09:07 aclima93

... it also removes initializers that just apply property wrappers to the arguments

This is still happening,

struct Title {
    let text: String

    init(@Localised text: String) {
        self.text = text
    }
}

gets re-written as

struct Title {
    let text: String
}

unless I disable it with unneeded_synthesized_initializer

    // swiftlint:disable:next unneeded_synthesized_initializer
    init(@Localised text: String) {

Yeah, this got fixed after the 0.55.1 release only.

SimplyDanny avatar Jul 04 '24 20:07 SimplyDanny

@SimplyDanny will your fix also address the scenario when the initializer is marked @usableFromInline and is required in an @inlinable call chain?

bradhowes avatar Aug 15 '24 10:08 bradhowes

@SimplyDanny will your fix also address the scenario when the initializer is marked @usableFromInline and is required in an @inlinable call chain?

Ah - I thought I saw an issue relating to this recently in the periphery codebase

mildm8nnered avatar Aug 16 '24 15:08 mildm8nnered

@SimplyDanny will your fix also address the scenario when the initializer is marked @usableFromInline and is required in an @inlinable call chain?

It doesn't. I wonder if initializers with any type of attribute should be excluded.

SimplyDanny avatar Aug 18 '24 13:08 SimplyDanny