NEAL

NEAL (Not Exactly A Linter) is a language-independent code analysis tool that aims to enable more people to write quality enforcement rules.

Example

One of the simplest rules we have at Uber is to restrict the use of Forced-Values in Swift. (This post explains some of the risks of abusing forced-values.)

A forced-value consists of any expression that results in an optional value followed by the forced-unwrapping operator (!). Here’s a contrived example that would result in a runtime crash.

// test.swift
(nil as Int?)!

NEAL doesn’t have any rules built-in, so we have to write a new rule to detect this pattern:

// test.rules
rule NoForcedValues {
  Swift::ForcedValueExpression {
    fail("No forced unwrapping allowed")
  }
}

Now if you run NEAL you should see something like the following:

$ neal --rules test.rules test.swift

[1 of 1]: Analysing test.swift
On file test.swift: (NoForcedValues)

  1 | (nil as Int?)!
  ~ |              ^

error: No forced unwrapping allowed

Alternatively, you can create a minimal configuration file called neal.json:

{
  "rules": [ "test.rules" ]
}

After that you can get the same result by simply running:

$ neal .

For a more comprehensive guide to writing your own rules check out Writing a new rule.

Installation

The recommended way of installing NEAL is through Homebrew, using the following command:

$ brew install neal

Installing from source

To build and install NEAL from source, make sure you have OPAM installed and that you’re using OCaml 4.04 or later.

$ brew install opam
$ opam init
$ opam switch 4.04.2
$ eval "$(opam config env)"

After you have setup OPAM and OCaml, you can setup, build and install NEAL using make.

$ NATIVE=1 make setup build install

Basic usage

NEAL has builtin support for Python and Swift, but it’s highly extensible, and can be used with any language.

$ neal [options] [path to files or directories]

For a list of CLI options, runtime options and configuration attributes see the Configuration guide.