Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

More Decks by Brooklyn Swift Developers Meetup

Other Decks in Technology

Transcript

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

    as! Movie { print(“5 rotten tomatoes”) } } Rule: Don’t Allow Force Unwrapping
  2. 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.
  3. Let’s explore linting by:
 • Investigating the Swift Compiler
 •

    Seeing how SwiftLint uses it
 • Answering the question, ‘Why Lint?’
  4. Before building, where do Xcode errors in Swift code come

    from? SourceKit, using an instance of the Swift Compiler
  5. // 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
  6. // 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
  7. What information do we need to display this? Error location

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

    messages to SourceKit.
 SourceKit responds with some info.
  9. 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" } ]
  10. 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
  11. Three Rule Protocols Rule, ParameterizedRule, & ASTRule Each includes a

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


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

    path: String? public var contents: String public var lines: [Line]
  14. 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
  15. 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
  16. 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.
  17. What do you think would be a great collaboration tool

    for your team?
 
 You should build it!
  18. 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