Tamar Nachmany - Linting in Swift

Tamar Nachmany - Linting in Swift

Linters define and enforce syntactical conventions across codebases. They enable teams of developers to convey shared values to one another, making new contributions easier and more fun to review, and existing code better to build off of. This talk will explore how Swift linting works, why it’s valuable, and whether linting can go beyond fixing syntax to analyze code for more complex shared patterns across iOS teams.

Recording from the December 2015 Brooklyn Swift Developers Meetup: meetup.com/Brooklyn-Swift-Developers/events/226935450/

Video: https://vimeo.com/152932872

Transcript

  1. Linting in Swift Tamar Nachmany

  2. Listing is analyzing code and enforcing custom stylistic rules What

    is linting?
  3. let greeting:String
 let greeting: String Rule: Leave space after colons

  4. for item in library { if let movie = item

    as! Movie { print(“5 rotten tomatoes”) } } Rule: Don’t Allow Force Unwrapping
  5. Why lint? Patterns & Onboarding
 Better code reviews
 Tooling

  6. Hi, I’m Tamar. 1. I’m an engineer on Tumblr’s core

    iOS team. 2. I’ve directed about seven plays and collaborated in other forms as well.
  7. Let’s explore linting by:
 • Investigating the Swift Compiler
 •

    Seeing how SwiftLint uses it
 • Answering the question, ‘Why Lint?’
  8. What do linters get us during the compilation process?

  9. What do linters get us during the compilation process? Extra

    errors.
  10. Where do Xcode errors come from?

  11. Before building, where do Xcode errors in Swift code come

    from? SourceKit, using an instance of the Swift Compiler
  12. The Swift compiler is now open source

  13. Basically

  14. Credit: Chris Lattner and Joe Groff Swift Compilation

  15. Credit: Chris Lattner and Joe Groff Swift Compilation

  16. // Make AST and return any errors.
 CompilerInstance TextCI; if

    (makeParserAST(IFaceGenCtx->Impl.TextCI, IFaceGenCtx- >Impl.Info.Text)) {
 ErrMsg = "Error during syntactic parsing"; return nullptr; 
 } SwiftEditorInterfaceGen
  17. // Perform semantic analysis
 
 CompilerInstance CI; CompilerInvocation Invocation; bool

    Failed = Lang.getASTManager().initCompilerInvocation( Invocation, Args, CI.getDiags(), InputFile- >getBufferIdentifier(), Error); if (Failed) { return false; } CI.performSema(); SwiftCompletion.cpp
  18. Let’s make an error: println(“yo”)

  19. None
  20. What information do we need to display this? Error location

    Error message Fix-it suggestion Whether it’s an error or warning
  21. When you enter new code into your project, Xcode sends

    messages to SourceKit.
 SourceKit responds with some info.
  22. SourceKit Response key.diagnostics: [ { key.line: 5, key.column: 9, key.filepath:

    "/Users/SourceKit-Logging.playground", key.severity: source.diagnostic.severity.error, key.description: "'println' has been renamed to 'print'", key.diagnostic_stage: source.diagnostic.stage.swift.sema, key.fixits: [ { key.offset: 0, key.length: 7, key.sourcetext: "print" } ]
  23. lib/Parse Response filename.swift:5:9: error: 'println' has been renamed to 'print'

    println("yo") ^~~~~~~ print
  24. None
  25. Let’s look at a linter

  26. SwiftLint by

  27. How does SwiftLint enforce new rules in SourceKit?

  28. How does SwiftLint enforce new rules in SourceKit? Let’s step

    back for a second.
  29. Why is this a hard problem?

  30. Why is this a hard problem? • Print stuff in

    Xcode, and other formats • Tap into compilation process • Establish rules • ‘Parse’ files and assess them 
 based on new rules
  31. Three Rule Protocols Rule, ParameterizedRule, & ASTRule

  32. Three Rule Protocols Rule, ParameterizedRule, & ASTRule Each includes a

    set of triggering examples and non-triggering examples, which is very effective documentation.
  33. validate(file: File) public func validateFile(file: File) -> [StyleViolation] {...}
 


    func validateFile(file: File, kind: SwiftDeclarationKind, dictionary: XPCDictionary) -> [StyleViolation] {...}
  34. validate(file: File) 
 public final class File { public let

    path: String? public var contents: String public var lines: [Line]
  35. public func validateFile(file: File) -> [StyleViolation] { let pattern =

    "(\\,[^\\s])|(\\s\\,)" let excludingKinds = SyntaxKind.commentAndStringKinds() return file.matchPattern(pattern, excludingSyntaxKinds: excludingKinds).map { StyleViolation(ruleDescription: self.dynamicType.description, location: Location(file: file, offset: $0.location)) } } CommaRule analyzes the file using regular expressions
  36. public func validateFile(file: File, kind: SwiftDeclarationKind, dictionary: XPCDictionary) -> [StyleViolation]

    { return file.validateVariableName(dictionary, kind: kind).map { name, offset in let charCount = name.characters.count for parameter in self.parameters.reverse() where charCount > parameter.value { return [StyleViolation(ruleDescription: self.dynamicType.description, severity: parameter.severity, location: Location(file: file, offset: offset), reason: "Variable name should be \(parameter.value) characters " + "or less: currently \(charCount) characters")] } return [] } ?? [] } VariableNameMaxLengthRule analyzes the file as an XPCDictionary
  37. SwiftLint uses SourceKit’s responses to generate an XPCDictionary for each

    file
  38. SwiftLint (Realm) SourceKit (Apple) SwiftKitten (Realm) Swift Compiler Instance (Apple)

  39. Works nicely in our app.

  40. Linting is about collaboration and effectively, passively sharing code patterns.

  41. I heard you like feedback, so I have some feedback

    on your feedback
  42. In theatre directing, the first thing you say matters.

  43. In code reviews, the content of your comments matters. Linting

    can help keep the collaboration between your team members pleasant and focused on important stuff.
  44. What do you think would be a great collaboration tool

    for your team?
 

  45. What do you think would be a great collaboration tool

    for your team?
 
 You should build it!
  46. @tamarshmallows Say hi

  47. Reading Materials Swift.org & Apple’s Github Repos SwiftLint, SourceKitten, and

    SwiftXPC
 
 JP Simard on Source Kit: http://www.jpsim.com/uncovering- sourcekit/ Chris Eidhof on the Objective-C Compiler: https://www.objc.io/ issues/6-build-tools/compiler Thinking In Swift Part II: Compiler: https:// www.accelebrate.com/blog/thinking-swift-part-ii/ OS X 10.10 Yosemite: The Ars Technica Review: http:// arstechnica.com/apple/2014/10/os-x-10-10/22/ 
 Hello SIL: http://swiftc.io/post/132002781944/hello-sil