nicklockwood / SwiftFormat

A command-line tool and Xcode Extension for formatting Swift code
MIT License
7.63k stars 623 forks source link

Update preferInferredTypes rule to also support converting from inferred types to explicit types, fix bugs #1658

Closed calda closed 3 months ago

calda commented 3 months ago

This PR renames the preferInferredTypes rule to propertyType, and makes the rule support both directions of conversions. It now fully respects the --redundantType inferred/explicit/infer-locals-only option, and can convert freely between

let foo: Foo = .init()

and

let foo = Foo()
  // --redundantType inferred
- let foo: Foo = .init()
+ let foo = Foo()

- let bar: Bar = .defaultValue
+ let bar = Bar.defaultValue

  // --redundantType explicit
- let foo = Foo()
+ let foo: Foo = .init()

- let bar = Bar.defaultValue
+ let bar: Bar = .defaultValue

  // --redundantType prefer-locals-only
  class Foo {
-     let foo = Foo()
+     let foo: Foo = .init()

      func bar() {
-         let bar: Bar = .defaultValue
+         let bar = Bar.defaultValue
      }
  }

That being said each option has various edge cases that may require manual fixes. When I ran these on Airbnb's app codebase:

I'd be fine with leaving the rule as-is (preferInferredTypes only supporting inferred rather than explicit or infer-locals-only) if you think the infer-locals-only and explicit options are too unreliable. I find inferred and infer-locals-only definitely reliably enough for use in Airbnb's codebase / style guide.


This PR also fixes other issues where the existing code would cause build failures:

For example, this compiles:

extension String {
  static let foo = "Foo"
}

let foo: String? = .foo

but this doesn't:

extension String {
  static let foo = "Foo"
}

// error: type 'String?' has no member 'foo'
let foo = String?.foo

I would have posted the two changes as separate PRs, but the propertyType rewrite depended on the bugfixes.

codecov[bot] commented 3 months ago

Codecov Report

Attention: Patch coverage is 98.30508% with 4 lines in your changes are missing coverage. Please review.

Project coverage is 95.17%. Comparing base (ca70962) to head (532eab8).

Files Patch % Lines
Sources/Rules.swift 98.31% 3 Missing :warning:
Sources/ParsingHelpers.swift 97.95% 1 Missing :warning:
Additional details and impacted files ```diff @@ Coverage Diff @@ ## develop #1658 +/- ## =========================================== + Coverage 95.13% 95.17% +0.03% =========================================== Files 20 20 Lines 22707 22880 +173 =========================================== + Hits 21603 21775 +172 - Misses 1104 1105 +1 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

calda commented 3 months ago

@nicklockwood, I updated the rule implementation to support both prefer-locals-only and explicit rather than just inferred like it did before. This PR also includes a bunch of bug fixes. I added some context and commentary to the PR description, let me know what you think.

calda commented 3 months ago

We may also want to rename the --redundantType option to --propertyType and then have both the redundantType and propertyType rule respect it. It's slightly weird for the propertyType rule to use the --redundantType option, but I agree your thinking that we do want them to be configured using the same option rather than two separate options (so there's never a conflict). I'm also fine with leaving it as-is.

nicklockwood commented 3 months ago

@calda thanks so much for these features and fixes, I really appreciate it. Sorry I've not had very much bandwidth to discuss the design. I'm not certain yet what the best approach is with respect to naming. I'll try to collate my thoughts and get back to you in the next few days.

calda commented 3 months ago

Thanks, no worries :) appreciate the merges, we can iterate on develop