Skip to content

Ignore count of parameters in init methods#841

Closed
delebedev wants to merge 3 commits intorealm:masterfrom
delebedev:ignore-parameters-count-init
Closed

Ignore count of parameters in init methods#841
delebedev wants to merge 3 commits intorealm:masterfrom
delebedev:ignore-parameters-count-init

Conversation

@delebedev
Copy link
Copy Markdown
Contributor

Fixes #544
As was mentioned deleting FunctionConstructor from the list does not really work.

My solution looks pretty dumb, but those two tests prove that it works. I've decided to test for init( instead of init to cut at least some of false positives (such as initProperties) but arguably it is not really necessary.

@codecov-io
Copy link
Copy Markdown

codecov-io commented Oct 15, 2016

Current coverage is 83.26% (diff: 100%)

Merging #841 into master will increase coverage by 0.02%

@@             master       #841   diff @@
==========================================
  Files           114        114          
  Lines          5136       5144     +8   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits           4275       4283     +8   
  Misses          861        861          
  Partials          0          0          

Powered by Codecov. Last update f243e0e...d6cdd3c

@norio-nomura
Copy link
Copy Markdown
Contributor

norio-nomura commented Oct 15, 2016

As far as I tested, value of "key.name" has prefix init( whether it is init() or init?() on both of Swift 2.3 and 3.0.
If checking name.hasPrefix("init("), I guess that false positive scenario would happen only when using following:

func `init`() {}

Output of sourcekitten structure …:

$ TOOLCHAINS=com.apple.dt.toolchain.XcodeDefault sourcekitten structure --text '
struct S { init() {}; init?() { return nil }; func `init`(_: Int) {} }
class C { init() {}; init?() { return nil }; func `init`(_: Int) {} }
enum E { case c; init() { return c }; init?() { return nil }; func `init`(_: Int) {} }
'
{
  "key.substructure" : [
    {
      "key.kind" : "source.lang.swift.decl.struct",
      "key.offset" : 1,
      "key.nameoffset" : 8,
      "key.namelength" : 1,
      "key.bodyoffset" : 11,
      "key.bodylength" : 59,
      "key.accessibility" : "source.lang.swift.accessibility.internal",
      "key.substructure" : [
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 12,
          "key.nameoffset" : 12,
          "key.namelength" : 6,
          "key.bodyoffset" : 20,
          "key.bodylength" : 0,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.length" : 9,
          "key.name" : "init()"
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 23,
          "key.nameoffset" : 23,
          "key.namelength" : 7,
          "key.bodyoffset" : 32,
          "key.bodylength" : 12,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.length" : 22,
          "key.name" : "init()"
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 47,
          "key.nameoffset" : 52,
          "key.namelength" : 14,
          "key.bodyoffset" : 68,
          "key.bodylength" : 0,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.substructure" : [
            {
              "key.kind" : "source.lang.swift.decl.var.parameter",
              "key.offset" : 59,
              "key.typename" : "Int",
              "key.nameoffset" : 0,
              "key.namelength" : 0,
              "key.length" : 6
            }
          ],
          "key.name" : "init(_:)",
          "key.length" : 22
        }
      ],
      "key.name" : "S",
      "key.length" : 70
    },
    {
      "key.kind" : "source.lang.swift.decl.class",
      "key.offset" : 72,
      "key.nameoffset" : 78,
      "key.namelength" : 1,
      "key.bodyoffset" : 81,
      "key.bodylength" : 59,
      "key.accessibility" : "source.lang.swift.accessibility.internal",
      "key.substructure" : [
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 82,
          "key.nameoffset" : 82,
          "key.namelength" : 6,
          "key.bodyoffset" : 90,
          "key.bodylength" : 0,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.length" : 9,
          "key.name" : "init()"
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 93,
          "key.nameoffset" : 93,
          "key.namelength" : 7,
          "key.bodyoffset" : 102,
          "key.bodylength" : 12,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.length" : 22,
          "key.name" : "init()"
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 117,
          "key.nameoffset" : 122,
          "key.namelength" : 14,
          "key.bodyoffset" : 138,
          "key.bodylength" : 0,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.substructure" : [
            {
              "key.kind" : "source.lang.swift.decl.var.parameter",
              "key.offset" : 129,
              "key.typename" : "Int",
              "key.nameoffset" : 0,
              "key.namelength" : 0,
              "key.length" : 6
            }
          ],
          "key.name" : "init(_:)",
          "key.length" : 22
        }
      ],
      "key.name" : "C",
      "key.runtime_name" : "_TtC8__main__1C",
      "key.length" : 69
    },
    {
      "key.kind" : "source.lang.swift.decl.enum",
      "key.offset" : 142,
      "key.nameoffset" : 147,
      "key.namelength" : 1,
      "key.bodyoffset" : 150,
      "key.bodylength" : 77,
      "key.accessibility" : "source.lang.swift.accessibility.internal",
      "key.substructure" : [
        {
          "key.substructure" : [
            {
              "key.kind" : "source.lang.swift.decl.enumelement",
              "key.offset" : 156,
              "key.nameoffset" : 156,
              "key.namelength" : 1,
              "key.length" : 1,
              "key.accessibility" : "source.lang.swift.accessibility.internal",
              "key.name" : "c"
            }
          ],
          "key.kind" : "source.lang.swift.decl.enumcase",
          "key.offset" : 151,
          "key.nameoffset" : 0,
          "key.namelength" : 0,
          "key.length" : 6
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 159,
          "key.nameoffset" : 159,
          "key.namelength" : 6,
          "key.bodyoffset" : 167,
          "key.bodylength" : 10,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.length" : 19,
          "key.name" : "init()"
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 180,
          "key.nameoffset" : 180,
          "key.namelength" : 7,
          "key.bodyoffset" : 189,
          "key.bodylength" : 12,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.length" : 22,
          "key.name" : "init()"
        },
        {
          "key.kind" : "source.lang.swift.decl.function.method.instance",
          "key.offset" : 204,
          "key.nameoffset" : 209,
          "key.namelength" : 14,
          "key.bodyoffset" : 225,
          "key.bodylength" : 0,
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.substructure" : [
            {
              "key.kind" : "source.lang.swift.decl.var.parameter",
              "key.offset" : 216,
              "key.typename" : "Int",
              "key.nameoffset" : 0,
              "key.namelength" : 0,
              "key.length" : 6
            }
          ],
          "key.name" : "init(_:)",
          "key.length" : 22
        }
      ],
      "key.name" : "E",
      "key.length" : 86
    }
  ],
  "key.offset" : 0,
  "key.diagnostic_stage" : "source.diagnostic.stage.swift.parse",
  "key.length" : 229
}

@delebedev
Copy link
Copy Markdown
Contributor Author

@norio-nomura I've added the test case for scenario you've described and surprisingly it behaves as it should be.
Please check my latest commit, does to what you expect?

Copy link
Copy Markdown
Contributor

@norio-nomura norio-nomura left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my unclear meaning in last comment with.
Please check my reviews. 🙏

let length = Int(dictionary["key.namelength"] as? Int64 ?? 0)
let substructure = dictionary["key.substructure"] as? [SourceKitRepresentable] ?? []

if file.contents.substring(nameOffset, length: length).containsString("init(") {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • nameOffset is counted by byte based number.
    So, this make failing test with triggering example such as:
            "struct Foo {\n /* 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦 */" +
                "init(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}\n" +
                "func bar(a: b, c: Int, d: Int, e: Int, f: Int, g: Int) {}}"

Please use SourceKittenFrameworks's byte base API such as NSString.substringWithByteRange(start:length:) if getting substring from file.contents.

  • This also fails with init?(.

What I meant on my last comment were:

  • "key.name" already contains string what we need here.
    Most of offset conversion between byte and utf16 are relatively high cost operations. We want to avoid using that if we can.
  • And that has prefix init( whether initializer is failable or not

@jpsim
Copy link
Copy Markdown
Collaborator

jpsim commented Nov 25, 2016

@garnett thanks for your work on this. If you could address @norio-nomura's last comment, I think we could get this in! 💃

@jpsim
Copy link
Copy Markdown
Collaborator

jpsim commented Nov 25, 2016

Also a changelog entry could be helpful.

@delebedev
Copy link
Copy Markdown
Contributor Author

@jpsim I've rebased original PR and tried to resolve all comments.

}

fileprivate func functionIsInitializer(_ file: File, offset: Int, length: Int) -> Bool {
if let function = (file.contents as NSString)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this cast is not needed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understood correctly, @norio-nomura was explicit in his comment and suggested using NSString. If you search for (file.contents as NSString) in the project you'll see that sometimes this conversion is used even if redundant. But I can be wrong here.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might matter when we add Linux support, but the implicit bridging works fine for now and is cleaner, so let's stick with the cleaner approach.


fileprivate func functionIsInitializer(_ file: File, offset: Int, length: Int) -> Bool {
if let function = (file.contents as NSString)
.substringWithByteRange(start: offset, length: length), function.contains("init") {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe check hasPrefix instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good spot, fixed

@jpsim
Copy link
Copy Markdown
Collaborator

jpsim commented Dec 8, 2016

Continued in #942. Thanks for your sustained effort and work on this @garnett!

@jpsim jpsim closed this Dec 8, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants