Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autocorrect for "colon" corrupts file when preprocessor macros are present #2099

Closed
2 tasks done
jszumski opened this issue Mar 16, 2018 · 3 comments
Closed
2 tasks done
Labels

Comments

@jszumski
Copy link
Contributor

New Issue Checklist

Bug Report

Complete output when running SwiftLint, including the stack trace and command used
$ swiftlint autocorrect --path Foo.swift
Correcting Swift files at path Foo.swift
Correcting 'Foo.swift' (1/1)
Foo.swift:4:21 Corrected Colon
Foo.swift:4:21 Corrected Colon
Done correcting 1 files!

Environment

whitelist_rules:
  - colon
  • Are you using nested configurations? If so, paste their relative paths and respective contents. no
  • Which Xcode version are you using (check xcode-select -p)? 9.2

Steps to Reproduce

Source File

class Foo {
    #if false
    #else
    let bar = ["key"   : "value"]
    #endif
}

Run autocorrect

$ swiftlint autocorrect --path Foo.swift
Correcting Swift files at path Foo.swift
Correcting 'Foo.swift' (1/1)
Foo.swift:4:21 Corrected Colon
Foo.swift:4:21 Corrected Colon
Done correcting 1 files!

Corrected File

The duplicate correction ends up truncating the dictionary such that it doesn't compile. The amount of truncation is always equal to the number of extra spaces between the end of the key and the colon.

class Foo {
    #if false
    #else
    let bar = ["key": lue"]
    #endif
}

Variations Attempted

The issue is only reproducible with a dictionary literal, replacing the 4th line with

let bar   :   String = ""

or

func bar(arg   :  String) {}

works as expected.

Removing the preprocessor macros entirely also fixes the issue, but this isn't possible in the real world case that uncovered this bug.


As best I can tell SourceKitten is getting confused by the preprocessor macros but only in the dictionary literal case. Examining file.structure in ColonRule.correctionRanges(in:) shows two identical entries, which causes swiftlint to emit two corrections at the same location.

structure output
{
  "key.diagnostic_stage" : "source.diagnostic.stage.swift.parse",
  "key.length" : 84,
  "key.offset" : 0,
  "key.substructure" : [
    {
      "key.accessibility" : "source.lang.swift.accessibility.internal",
      "key.bodylength" : 70,
      "key.bodyoffset" : 11,
      "key.kind" : "source.lang.swift.decl.class",
      "key.length" : 82,
      "key.name" : "Foo",
      "key.namelength" : 3,
      "key.nameoffset" : 6,
      "key.offset" : 0,
      "key.runtime_name" : "_TtC8__main__3Foo",
      "key.substructure" : [
        {
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.kind" : "source.lang.swift.decl.var.instance",
          "key.length" : 29,
          "key.name" : "bar",
          "key.namelength" : 3,
          "key.nameoffset" : 44,
          "key.offset" : 40
        },
        {
          "key.bodylength" : 17,
          "key.bodyoffset" : 51,
          "key.elements" : [
            {
              "key.kind" : "source.lang.swift.structure.elem.expr",
              "key.length" : 5,
              "key.offset" : 51
            },
            {
              "key.kind" : "source.lang.swift.structure.elem.expr",
              "key.length" : 7,
              "key.offset" : 61
            }
          ],
          "key.kind" : "source.lang.swift.expr.dictionary",
          "key.length" : 19,
          "key.namelength" : 0,
          "key.nameoffset" : 0,
          "key.offset" : 50
        },
        {
          "key.accessibility" : "source.lang.swift.accessibility.internal",
          "key.kind" : "source.lang.swift.decl.var.instance",
          "key.length" : 29,
          "key.name" : "bar",
          "key.namelength" : 3,
          "key.nameoffset" : 44,
          "key.offset" : 40
        },
        {
          "key.bodylength" : 17,
          "key.bodyoffset" : 51,
          "key.elements" : [
            {
              "key.kind" : "source.lang.swift.structure.elem.expr",
              "key.length" : 5,
              "key.offset" : 51
            },
            {
              "key.kind" : "source.lang.swift.structure.elem.expr",
              "key.length" : 7,
              "key.offset" : 61
            }
          ],
          "key.kind" : "source.lang.swift.expr.dictionary",
          "key.length" : 19,
          "key.namelength" : 0,
          "key.nameoffset" : 0,
          "key.offset" : 50
        }
      ]
    }
  ]
}
@marcelofabri
Copy link
Collaborator

@jszumski It looks like we can workaround this by uniquing the violations before correcting.

But SourceKit shouldn't return two identical entries as well. Can you please file a bug in Swift's JIRA?

@marcelofabri
Copy link
Collaborator

Actually, this looks fixed already on Swift 4.1, so no need to file a bug 💯

@jszumski
Copy link
Contributor Author

Thanks for the quick turn around!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants