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

variable_name rule should extend to all identifiers #954

Merged
merged 20 commits into from
Feb 10, 2017
Merged

variable_name rule should extend to all identifiers #954

merged 20 commits into from
Feb 10, 2017

Conversation

marcelofabri
Copy link
Collaborator

Fixes #663

I haven't applied all the rules to functions because I didn't think it was a good idea as their limits probably should be different.

This is a breaking change, I'm not sure how we should handle this. Perhaps we should keep a variable_name rule to avoid breaking configs?

@codecov-io
Copy link

codecov-io commented Dec 9, 2016

Current coverage is 81.91% (diff: 74.31%)

Merging #954 into master will decrease coverage by <.01%

@@             master       #954   diff @@
==========================================
  Files           168        168          
  Lines          8344       8388    +44   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits           6835       6871    +36   
- Misses         1509       1517     +8   
  Partials          0          0          

Powered by Codecov. Last update d3693e1...c8e0818

@jpsim
Copy link
Collaborator

jpsim commented Dec 12, 2016

Can you please rebase this so we can confirm it builds and passes tests on Linux?

@@ -397,6 +397,7 @@ extension RulesTests {
// ("testForceUnwrapping", testForceUnwrapping),
("testFunctionBodyLength", testFunctionBodyLength),
("testFunctionParameterCountRule", testFunctionParameterCountRule),
// ("testIdentifierName", testIdentifierName),
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've commented it because testVariableName was commented too

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's fine for now. When we merge this, we should add this test to #966.

CHANGELOG.md Outdated
@@ -7,6 +7,11 @@
Guidelines but will shortly.
[JP Simard](https://github.com/jpsim),
[Norio Nomura](https://github.com/norio-nomura)

* `variable_name` rule is now `identifier_rule` as it validates other
Copy link
Collaborator

Choose a reason for hiding this comment

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

identifier_name. Also, it'd be nice to keep VariableNameRule around, logging a warning to the console if used in comment commands or the config file, proxying its implementation to IdentifierNameRule. Would lead to a nicer deprecation path.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But wouldn't it make the rule run twice?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Might have to think this through a bit more. Maybe having rule ID aliases is the right move there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've created #973 to track this

@marcelofabri marcelofabri changed the title variable_name rule should extend to all identifiers [WIP] variable_name rule should extend to all identifiers Dec 13, 2016
@marcelofabri
Copy link
Collaborator Author

I've changed this to WIP as we need to figure out the deprecation part. However, I have no clue why the tests are failing on Linux 😭

@marcelofabri
Copy link
Collaborator Author

marcelofabri commented Dec 16, 2016

I was able to reproduce the crash on a local docker instance. It can be reduced to this:

let name = "matchPattern(_:excludingSyntaxKinds:excludingPattern:exclusionMapping:)"
let nameCharacterSet = CharacterSet(charactersIn: name)

Stacktrace:

* thread #1: tid = 40, 0x0000000000000000, name = 'repl_swift', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
  * frame #0: 0x0000000000000000
    frame #1: 0x00007ffff427fa8a libFoundation.so`_CFCharacterSetInitWithCharactersInString + 266
    frame #2: 0x00007ffff43a5736 libFoundation.so`function signature specialization <Arg[0] = Owned To Guaranteed and Exploded> of Foundation.NSCharacterSet.init (charactersIn : Swift.String) -> Foundation.NSCharacterSet + 150
    frame #3: 0x00007ffff43a3ace libFoundation.so`Foundation.NSCharacterSet.__allocating_init (charactersIn : Swift.String) -> Foundation.NSCharacterSet + 78
    frame #4: 0x00007ffff46493e5 libFoundation.so`Foundation.CharacterSet.init (charactersIn : Swift.String) -> Foundation.CharacterSet + 53
    frame #5: 0x00007ffff7f6dddf $__lldb_expr7`main + 127
    frame #6: 0x00000000004009b0 repl_swift`swift_once + 16

There are already two tickets on Swift bug tracking: SR-3215 and SR-3282.

It seems that the crash happens with any string with more then 63 characters.

@jpsim
Copy link
Collaborator

jpsim commented Dec 16, 2016

Can you just not include those examples in the rule description when compiling on Linux?

@marcelofabri
Copy link
Collaborator Author

Not really, because it's failing to lint a real file in IntegrationTests.testSwiftLintLints 😓

@marcelofabri
Copy link
Collaborator Author

marcelofabri commented Dec 18, 2016

A note to future self and all others: you can run lldb on a binary built with swift test:

  1. Run docker interactively:
docker run --privileged -it -v \`pwd`:/SwiftLint norionomura/sourcekit:302
  1. Run cd /SwiftLint && swift test to see it crashing
  2. Run lldb .build/debug/SwiftLintPackageTests.xctest to start lldb
  3. In lldb, type r to start the tests. When they crash, you can get a stack trace with bt.

// CharacterSet+LinuxHack.swift
// SwiftLint
//
// Created by Marcelo Fabri on 17/12/16.
Copy link
Collaborator

Choose a reason for hiding this comment

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

mm/dd/yy 🔥 🇺🇸

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🤧

Copy link
Collaborator

@jpsim jpsim left a comment

Choose a reason for hiding this comment

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

I know this is still WIP (until we can handle the deprecation a bit better), but I have some comments in the meantime.

// workaround for https://bugs.swift.org/browse/SR-3215 and
// https://bugs.swift.org/browse/SR-3282
let sets = split(string, 63).map { CharacterSet(charactersIn: $0) }
let finalSet = sets.reduce(CharacterSet()) { (acc, set) -> CharacterSet in
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a minor suggestion, but:

-let finalSet = sets.reduce(CharacterSet()) { (acc, set) -> CharacterSet in
-    acc.union(set)
-}
-
-self = finalSet
+self = sets.reduce(CharacterSet()) { final, set in final.union(set) }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍

internal func validateVariableName(_ dictionary: [String: SourceKitRepresentable],
kind: SwiftDeclarationKind) -> (name: String, offset: Int)? {
internal func validateIdentifierName(_ dictionary: [String: SourceKitRepresentable],
kind: SwiftDeclarationKind) -> (name: String, offset: Int)? {
Copy link
Collaborator

Choose a reason for hiding this comment

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

indentation

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

that was probably intentional to avoid breaking the return 😅
either way, I've moved this to the rule itself, since IMO it's not related to File in any obvious way.

private func nameIsViolatingCase(_ name: String) -> Bool {
let secondIndex = name.characters.index(after: name.startIndex)
let firstCharacter = name.substring(to: secondIndex)
if firstCharacter.isUppercase() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This might benefit from using guards:

-if firstCharacter.isUppercase() {
-    if name.characters.count > 1 {
-        let range = secondIndex..<name.characters.index(after: secondIndex)
-        let secondCharacter = name.substring(with: range)
-        return secondCharacter.isLowercase()
-    }
-    return true
-}
-return false
+guard firstCharacter.isUppercase() else { return false }
+guard name.characters.count > 1 else { return true }
+let range = secondIndex..<name.characters.index(after: secondIndex)
+let secondCharacter = name.substring(with: range)
+return secondCharacter.isLowercase()


private func isOperator(name: String) -> Bool {
let operators = ["/", "=", "-", "+", "!", "*", "|", "^", "~", "?", ".", "%", "<", ">", "&"]
return !operators.filter { name.hasPrefix($0) }.isEmpty
Copy link
Collaborator

Choose a reason for hiding this comment

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

Prefer passing function references over simple closures:

-return !operators.filter { name.hasPrefix($0) }.isEmpty
+return !operators.filter(name.hasPrefix).isEmpty

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nice catch! 💯

@SwiftLintBot
Copy link

SwiftLintBot commented Dec 26, 2016

2 Warnings
⚠️ This PR introduced a violation in firefox-ios: /Client/Application/AppDelegate.swift#L288:13: warning: Switch Case on Newline Violation: Cases inside a switch should always be on a newline (switch_case_on_newline)
⚠️ This PR introduced a violation in firefox-ios: /Storage/Bookmarks/Trees.swift#L13:14: warning: Switch Case on Newline Violation: Cases inside a switch should always be on a newline (switch_case_on_newline)
12 Messages
📖 Linting WordPress-iOS with this PR took 18.39s vs 16.04s on master (14% slower)
📖 Linting swift with this PR took 14.41s vs 16.02s on master (10% faster)
📖 Linting Aerial with this PR took 0.53s vs 0.53s on master (0% slower)
📖 Linting SourceKitten with this PR took 1.55s vs 1.67s on master (7% faster)
📖 Linting Sourcery with this PR took 3.13s vs 3.32s on master (5% faster)
📖 Linting ios-oss with this PR took 21.73s vs 21.39s on master (1% slower)
📖 Linting Alamofire with this PR took 3.92s vs 4.65s on master (15% faster)
📖 Linting firefox-ios with this PR took 26.05s vs 23.29s on master (11% slower)
📖 Linting Nimble with this PR took 2.98s vs 2.37s on master (25% slower)
📖 Linting Quick with this PR took 1.0s vs 0.72s on master (38% slower)
📖 Linting realm-cocoa with this PR took 4.25s vs 3.69s on master (15% slower)
📖 Linting Moya with this PR took 0.57s vs 0.54s on master (5% slower)

Generated by 🚫 danger

private func validateName(_ dictionary: [String: SourceKitRepresentable],
kind: SwiftDeclarationKind) -> (name: String, offset: Int)? {
let kinds = SwiftDeclarationKind.variableKinds() +
SwiftDeclarationKind.functionKinds() + [.enumelement]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this probably should check the Swift version to add or not .enumelement

@marcelofabri marcelofabri changed the title [WIP] variable_name rule should extend to all identifiers variable_name rule should extend to all identifiers Jan 4, 2017
@jpsim
Copy link
Collaborator

jpsim commented Jan 5, 2017

Maybe this rule shouldn't apply to @available(*, unavailable, renamed: ...) declarations since if they're acting as migration helpers from Swift 2 naming to Swift 3, they'll report violations. For example (as caught by osscheck!):

// MARK: - migration support
extension Request {
    @available(*, unavailable, renamed: "editorOpen(file:)")
    public static func EditorOpen(_: File) -> Request { fatalError() }
    ...
}

@marcelofabri
Copy link
Collaborator Author

marcelofabri commented Jan 5, 2017

Maybe this rule shouldn't apply to @available(*, unavailable, renamed: ...) ...

While I agree that it would be useful, I'm not convinced that it's worth the extra complexity. There's no way to get the unavailable attribute from AST and the offsets we have don't contain the @available attribute.

In both Realm and SourceKitten it'd be pretty easy to just ignore the rule in these declarations since they're isolated inside extensions.

@jpsim
Copy link
Collaborator

jpsim commented Jan 25, 2017

@marcelofabri what's next for this? Is this just blocked on me reviewing? Are there certain high-level points I should consider when reviewing this?

@marcelofabri
Copy link
Collaborator Author

If you're cool with not verifying the @available(*, unavailable, renamed: ...) annotation, this is ready for review.

I don't remember any important points, this is basically renaming the rule and adding more types to it. Also, some violations are skipped for functions. And this also validates that enum cases are lowercase on Swift 3 (I think there was an issue about it somewhere).

CHANGELOG.md Outdated
@@ -939,7 +939,10 @@ This release has seen a phenomenal uptake in community contributions!

##### Enhancements

* None.
* `variable_name` rule is now `identifier_name` as it validates other
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is now in the wrong section

jpsim added 4 commits February 9, 2017 15:50
* master: (44 commits)
  make valid_docs rule opt-in
  update LineLengthConfiguration.consoleDescription after #1264
  small refactoring after #1264
  fix for_where violation in CompilerProtocolInitRule.swift
  Add for_where rule
  explicitly set podspec dependency versions
  Add changelog entry
  Fix existing violations
  Navigate substructure even for different kinds
  Small style changes
  Modified so that kinds(forByteOffset:) does not require a separate filter() setup of the results
  Changes from PR feedback. Long comments following code in a line will now trigger,  configuration will now fail if invalud value types are set for options
  Fix false positive on large_tuple when using generics inside a tuple
  fix wording in changelog
  disable docs rules in Swift 2.3 and later
  Fix deadlock when stderr fills up OS buffer
  small Danger/oss-check improvements
  Fix links
  Fix cleanup
  Always use Xcode reporter on oss-check
  ...
@jpsim
Copy link
Collaborator

jpsim commented Feb 10, 2017

This definitely has a sizable impact on lint times, but that's to be expected. Hopefully with caching, no one feels the pain from this too much...


On my MacBook Pro:

Linting Alamofire with this PR took 2.01s vs 1.98s on master (1% slower)
Linting swift with this PR took 8.43s vs 6.84s on master (23% slower)
Linting Aerial with this PR took 0.31s vs 0.31s on master (0% slower)
Linting SourceKitten with this PR took 0.87s vs 0.83s on master (4% slower)
Linting Sourcery with this PR took 1.78s vs 1.49s on master (19% slower)
Linting ios-oss with this PR took 10.54s vs 10.21s on master (3% slower)
Linting Moya with this PR took 0.33s vs 0.29s on master (13% slower)
Linting firefox-ios with this PR took 12.21s vs 11.14s on master (9% slower)
Linting Nimble with this PR took 1.13s vs 1.14s on master (0% faster)
Linting Quick with this PR took 0.4s vs 0.36s on master (11% slower)
Linting realm-cocoa with this PR took 1.96s vs 1.7s on master (15% slower)
Linting WordPress-iOS with this PR took 6.78s vs 3.3s on master (105% slower)

@jpsim jpsim merged commit 944a989 into realm:master Feb 10, 2017
@marcelofabri marcelofabri deleted the identifier-rule branch February 14, 2017 14:54
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.

4 participants