Slide 1

Slide 1 text

Linting in Swift Tamar Nachmany

Slide 2

Slide 2 text

Listing is analyzing code and enforcing custom stylistic rules What is linting?

Slide 3

Slide 3 text

let greeting:String
 let greeting: String Rule: Leave space after colons

Slide 4

Slide 4 text

for item in library { if let movie = item as! Movie { print(“5 rotten tomatoes”) } } Rule: Don’t Allow Force Unwrapping

Slide 5

Slide 5 text

Why lint? Patterns & Onboarding
 Better code reviews
 Tooling

Slide 6

Slide 6 text

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.

Slide 7

Slide 7 text

Let’s explore linting by:
 • Investigating the Swift Compiler
 • Seeing how SwiftLint uses it
 • Answering the question, ‘Why Lint?’

Slide 8

Slide 8 text

What do linters get us during the compilation process?

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Where do Xcode errors come from?

Slide 11

Slide 11 text

Before building, where do Xcode errors in Swift code come from? SourceKit, using an instance of the Swift Compiler

Slide 12

Slide 12 text

The Swift compiler is now open source

Slide 13

Slide 13 text

Basically

Slide 14

Slide 14 text

Credit: Chris Lattner and Joe Groff Swift Compilation

Slide 15

Slide 15 text

Credit: Chris Lattner and Joe Groff Swift Compilation

Slide 16

Slide 16 text

// 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

Slide 17

Slide 17 text

// 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

Slide 18

Slide 18 text

Let’s make an error: println(“yo”)

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

What information do we need to display this? Error location Error message Fix-it suggestion Whether it’s an error or warning

Slide 21

Slide 21 text

When you enter new code into your project, Xcode sends messages to SourceKit.
 SourceKit responds with some info.

Slide 22

Slide 22 text

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" } ]

Slide 23

Slide 23 text

lib/Parse Response filename.swift:5:9: error: 'println' has been renamed to 'print' println("yo") ^~~~~~~ print

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

Let’s look at a linter

Slide 26

Slide 26 text

SwiftLint by

Slide 27

Slide 27 text

How does SwiftLint enforce new rules in SourceKit?

Slide 28

Slide 28 text

How does SwiftLint enforce new rules in SourceKit? Let’s step back for a second.

Slide 29

Slide 29 text

Why is this a hard problem?

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Three Rule Protocols Rule, ParameterizedRule, & ASTRule

Slide 32

Slide 32 text

Three Rule Protocols Rule, ParameterizedRule, & ASTRule Each includes a set of triggering examples and non-triggering examples, which is very effective documentation.

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

validate(file: File) 
 public final class File { public let path: String? public var contents: String public var lines: [Line]

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

SwiftLint uses SourceKit’s responses to generate an XPCDictionary for each file

Slide 38

Slide 38 text

SwiftLint (Realm) SourceKit (Apple) SwiftKitten (Realm) Swift Compiler Instance (Apple)

Slide 39

Slide 39 text

Works nicely in our app.

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

I heard you like feedback, so I have some feedback on your feedback

Slide 42

Slide 42 text

In theatre directing, the first thing you say matters.

Slide 43

Slide 43 text

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.

Slide 44

Slide 44 text

What do you think would be a great collaboration tool for your team?
 


Slide 45

Slide 45 text

What do you think would be a great collaboration tool for your team?
 
 You should build it!

Slide 46

Slide 46 text

@tamarshmallows Say hi

Slide 47

Slide 47 text

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