hlint-3.8: Source code suggestions

Safe Haskell | None
Language | Haskell2010

Language.Haskell.HLint

Contents

- Generate hints
- Idea data type
- Settings
- Hints
- Modules
- Parse flags

Description

This module provides a way to apply HLint hints. If you want to just run `hlint` in-process and collect the results see `hlint`.

If you want to approximate the `hlint` experience with a more structured API try:

    (flags, classify, hint) <- autoSettings
    Right m <- parseModuleEx flags "MyFile.hs" Nothing
    print $ applyHints classify hint [m]

Synopsis

- hlint :: [String] -> IO [Idea]
- applyHints :: [Classify] -> Hint -> [ModuleEx] -> [Idea]
- data Idea = Idea {
  - ideaModule :: [String]
  - ideaDecl :: [String]
  - ideaSeverity :: Severity
  - ideaHint :: String
  - ideaSpan :: SrcSpan
  - ideaFrom :: String
  - ideaTo :: Maybe String
  - ideaNote :: [Note]
  - ideaRefactoring :: [Refactoring SrcSpan]
  }
- data Severity
  - = Ignore
  - | Suggestion
  - | Warning
  - | Error
- data Note
  - = IncreasesLaziness
  - | DecreasesLaziness
  - | RemovesError String
  - | ValidInstance String String
  - | RequiresExtension String
  - | Note String
- unpackSrcSpan :: SrcSpan -> Maybe (FilePath, (Int, Int), (Int, Int))
- showIdeaANSI :: Idea -> String
- data Classify = Classify {
  - classifySeverity :: Severity
  - classifyHint :: String
  - classifyModule :: String
  - classifyDecl :: String
  }
- getHLintDataDir :: IO FilePath
- autoSettings :: IO (ParseFlags, [Classify], Hint)
- argsSettings :: [String] -> IO (ParseFlags, [Classify], Hint)
- findSettings :: (String -> IO (FilePath, Maybe String)) -> Maybe String -> IO ([FixityInfo], [Classify], Hint)
- readSettingsFile :: Maybe FilePath -> String -> IO (FilePath, Maybe String)
- data Hint
- data ModuleEx
- parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError ModuleEx)
- createModuleEx :: Located (HsModule GhcPs) -> ModuleEx
- createModuleExWithFixities :: [(String, Fixity)] -> Located (HsModule GhcPs) -> ModuleEx
- data ParseError = ParseError {
  - parseErrorLocation :: SrcSpan
  - parseErrorMessage :: String
  - parseErrorContents :: String
  }
- defaultParseFlags :: ParseFlags
- data ParseFlags = ParseFlags {
  - cppFlags :: CppFlags
  - baseLanguage :: Maybe Language
  - enabledExtensions :: [Extension]
  - disabledExtensions :: [Extension]
  - fixities :: [FixityInfo]
  }
- data CppFlags
  - = CppSimple
  - | Cpphs CpphsOptions
- type FixityInfo = (String, Associativity, Int)
- parseFlagsAddFixities :: [FixityInfo] -> ParseFlags -> ParseFlags

# Generate hints

hlint :: [String] -> IO [Idea] #

This function takes a list of command line arguments, and returns the given hints. To see a list of arguments type `hlint --help` at the console. This function writes to the stdout/stderr streams, unless `--quiet` is specified.

As an example:

    do hints <- hlint ["src", "--ignore=Use map","--quiet"]
       when (length hints > 3) $ error "Too many hints!"

Warning: The flags provided by HLint are relatively stable, but do not have the same API stability guarantees as the rest of the strongly-typed API. Do not run this function on your server with untrusted input.

applyHints :: [Classify] -> Hint -> [ModuleEx] -> [Idea] #

Given a way of classifying results, and a `Hint`, apply to a set of modules generating a list of `Idea`s. The `Idea` values will be ordered within a file.

Given a set of modules, it may be faster to pass each to `applyHints` in a singleton list. When given multiple modules at once this function attempts to find hints between modules, which is slower and often pointless (by default HLint passes modules singularly, using `--cross` to pass all modules together).

# Idea data type

data Idea #

An idea suggest by a `Hint`.

Constructors

Idea |

Fields

- ideaModule :: [String]

  The modules the idea is for, usually a singleton.

- ideaDecl :: [String]

  The declarations the idea is for, usually a singleton, typically the function name, but may be a type name.

- ideaSeverity :: Severity

  The severity of the idea, e.g. `Warning`.

- ideaHint :: String

  The name of the hint that generated the idea, e.g. `"Use reverse"`.

- ideaSpan :: SrcSpan

  The source code the idea relates to.

- ideaFrom :: String

  The contents of the source code the idea relates to.

- ideaTo :: Maybe String

  The suggested replacement, or `Nothing` for no replacement (e.g. on parse errors).

- ideaNote :: [Note]

  Notes about the effect of applying the replacement.

- ideaRefactoring :: [Refactoring SrcSpan]

  How to perform this idea

#### Instances

Instances details

Show Idea # |
Instance details Defined in Idea Methods showsPrec :: Int -> Idea -> ShowS # show :: Idea -> String # showList :: [Idea] -> ShowS #
Eq Idea # |
Instance details Defined in Idea Methods (==) :: Idea -> Idea -> Bool # (/=) :: Idea -> Idea -> Bool #

data Severity #

How severe an issue is.

Constructors

Ignore | The issue has been explicitly ignored and will usually be hidden (pass `--show` on the command line to see ignored ideas).
Suggestion | Suggestions are things that some people may consider improvements, but some may not.
Warning | Warnings are suggestions that are nearly always a good idea to apply.
Error | Available as a setting for the user. Only parse errors have this setting by default.

#### Instances

Instances details

ToJSON Severity # |
Instance details Defined in Config.Type Methods toJSON :: Severity -> Value # toEncoding :: Severity -> Encoding # toJSONList :: [Severity] -> Value # toEncodingList :: [Severity] -> Encoding # omitField :: Severity -> Bool #
Data Severity # |

Instance details

Defined in Config.Type

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Severity -> c Severity #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Severity #

toConstr :: Severity -> Constr #

dataTypeOf :: Severity -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Severity) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Severity) #

gmapT :: (forall b. Data b => b -> b) -> Severity -> Severity #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Severity -> r #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Severity -> r #

gmapQ :: (forall d. Data d => d -> u) -> Severity -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Severity -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Severity -> m Severity #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Severity -> m Severity #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Severity -> m Severity #

Bounded Severity # |
Instance details Defined in Config.Type Methods minBound :: Severity # maxBound :: Severity #
Enum Severity # |
Instance details Defined in Config.Type Methods succ :: Severity -> Severity # pred :: Severity -> Severity # toEnum :: Int -> Severity # fromEnum :: Severity -> Int # enumFrom :: Severity -> [Severity] # enumFromThen :: Severity -> Severity -> [Severity] # enumFromTo :: Severity -> Severity -> [Severity] # enumFromThenTo :: Severity -> Severity -> Severity -> [Severity] #
Generic Severity # |

Instance details

Defined in Config.Type

Associated Types

type Rep Severity |

Instance details

Defined in Config.Type

type Rep Severity = D1 ('MetaData "Severity" "Config.Type" "hlint-3.8-lxkPI7ssc1HTkrWtUEZ75" 'False) ((C1 ('MetaCons "Ignore" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Suggestion" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Warning" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Error" 'PrefixI 'False) (U1 :: Type -> Type)))

Methods

from :: Severity -> Rep Severity x #

to :: Rep Severity x -> Severity #

Read Severity # |
Instance details Defined in Config.Type Methods readsPrec :: Int -> ReadS Severity # readList :: ReadS [Severity] # readPrec :: ReadPrec Severity # readListPrec :: ReadPrec [Severity] #
Show Severity # |
Instance details Defined in Config.Type Methods showsPrec :: Int -> Severity -> ShowS # show :: Severity -> String # showList :: [Severity] -> ShowS #
Eq Severity # |
Instance details Defined in Config.Type Methods (==) :: Severity -> Severity -> Bool # (/=) :: Severity -> Severity -> Bool #
Ord Severity # |
Instance details Defined in Config.Type Methods compare :: Severity -> Severity -> Ordering # (<) :: Severity -> Severity -> Bool # (<=) :: Severity -> Severity -> Bool # (>) :: Severity -> Severity -> Bool # (>=) :: Severity -> Severity -> Bool # max :: Severity -> Severity -> Severity # min :: Severity -> Severity -> Severity #
type Rep Severity # |

Instance details

Defined in Config.Type

type Rep Severity = D1 ('MetaData "Severity" "Config.Type" "hlint-3.8-lxkPI7ssc1HTkrWtUEZ75" 'False) ((C1 ('MetaCons "Ignore" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Suggestion" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Warning" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Error" 'PrefixI 'False) (U1 :: Type -> Type)))

data Note #

A note describing the impact of the replacement.

Constructors

IncreasesLaziness | The replacement is increases laziness, for example replacing `reverse (reverse x)` with `x` makes the code lazier.
DecreasesLaziness | The replacement is decreases laziness, for example replacing `(fst x, snd x)` with `x` makes the code stricter.
RemovesError String | The replacement removes errors, for example replacing `foldr1 (+)` with `sum` removes an error on `[]`, and might contain the text `"on []"`.
ValidInstance String String | The replacement assumes standard type class lemmas, a hint with the note `ValidInstance "Eq" "x"` might only be valid if the `x` variable has a reflexive `Eq` instance.
RequiresExtension String | The replacement requires this extension to be available.
Note String | An arbitrary note.

#### Instances

Instances details

Show Note # |
Instance details Defined in Config.Type Methods showsPrec :: Int -> Note -> ShowS # show :: Note -> String # showList :: [Note] -> ShowS #
Eq Note # |
Instance details Defined in Config.Type Methods (==) :: Note -> Note -> Bool # (/=) :: Note -> Note -> Bool #
Ord Note # |
Instance details Defined in Config.Type Methods compare :: Note -> Note -> Ordering # (<) :: Note -> Note -> Bool # (<=) :: Note -> Note -> Bool # (>) :: Note -> Note -> Bool # (>=) :: Note -> Note -> Bool # max :: Note -> Note -> Note # min :: Note -> Note -> Note #

unpackSrcSpan :: SrcSpan -> Maybe (FilePath, (Int, Int), (Int, Int)) #

Unpack a `SrcSpan` value. Useful to allow using the `Idea` information without adding a dependency on `ghc` or `ghc-lib-parser`. Unpacking gives:

    (filename, (startLine, startCol), (endLine, endCol))

Following the GHC API, end column is the column after the end of the error. Lines and columns are 1-based. Returns `Nothing` if there is no helpful location information.

showIdeaANSI :: Idea -> String #

Show an `Idea` with ANSI color codes to give syntax coloring to the Haskell code.

# Settings

data Classify #

How to classify an `Idea`. If any matching field is `""` then it matches everything.

Constructors

Classify |

Fields

- classifySeverity :: Severity

  Severity to set the `Idea` to.

- classifyHint :: String

  Match on `Idea` field `ideaHint`.

- classifyModule :: String

  Match on `Idea` field `ideaModule`.

- classifyDecl :: String

  Match on `Idea` field `ideaDecl`.

#### Instances

Instances details

Show Classify # |
Instance details Defined in Config.Type Methods showsPrec :: Int -> Classify -> ShowS # show :: Classify -> String # showList :: [Classify] -> ShowS #

getHLintDataDir :: IO FilePath #

Get the Cabal configured data directory of HLint.

autoSettings :: IO (ParseFlags, [Classify], Hint) #

The function produces a tuple containing `ParseFlags` (for `parseModuleEx`), and `Classify` and `Hint` for `applyHints`. It approximates the normal HLint configuration steps, roughly:

1. Use `findSettings` with `readSettingsFile` to find and load the HLint settings files.
2. Use `parseFlagsAddFixities` and `resolveHints` to transform the outputs of `findSettings`.

If you want to do anything custom (e.g. using a different data directory, storing intermediate outputs, loading hints from a database) you are expected to copy and paste this function, then change it to your needs.

argsSettings :: [String] -> IO (ParseFlags, [Classify], Hint) #

A version of `autoSettings` which respects some of the arguments supported by HLint. If arguments unrecognised by HLint are used it will result in an error. Arguments which have no representation in the return type are silently ignored.

findSettings :: (String -> IO (FilePath, Maybe String)) -> Maybe String -> IO ([FixityInfo], [Classify], Hint) #

Given a function to load a module (typically `readSettingsFile`), and a module to start from (defaults to `hlint.yaml`) find the information from all settings files.

readSettingsFile :: Maybe FilePath -> String -> IO (FilePath, Maybe String) #

Given a directory (or `Nothing` to imply `getHLintDataDir`), and a module name (e.g. `HLint.Default`), find the settings file associated with it, returning the name of the file, and (optionally) the contents.

This function looks for all settings files starting with `HLint.` in the directory argument, and all other files relative to the current directory.

# Hints

data Hint #

Functions to generate hints, combined using the `Monoid` instance.

#### Instances

Instances details

Monoid Hint # |
Instance details Defined in Hint.Type Methods mempty :: Hint # mappend :: Hint -> Hint -> Hint # mconcat :: [Hint] -> Hint #
Semigroup Hint # |
Instance details Defined in Hint.Type Methods (<>) :: Hint -> Hint -> Hint # sconcat :: NonEmpty Hint -> Hint # stimes :: Integral b => b -> Hint -> Hint #

# Modules

data ModuleEx #

Result of `parseModuleEx`, representing a parsed module.

parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError ModuleEx) #

Parse a Haskell module. Applies the C pre processor, and uses best-guess fixity resolution if there are ambiguities. The filename `-` is treated as `stdin`. Requires some flags (often `defaultParseFlags`), the filename, and optionally the contents of that file.

Note that certain programs, e.g. `main = do` successfully parse with GHC, but then fail with an error in the renamer. These programs will return a successful parse.

createModuleEx :: Located (HsModule GhcPs) -> ModuleEx #

Create a `ModuleEx` from a GHC module. It is assumed the incoming parsed module has not been adjusted to account for operator fixities (it uses the HLint default fixities).

createModuleExWithFixities :: [(String, Fixity)] -> Located (HsModule GhcPs) -> ModuleEx #

data ParseError #

A parse error.

Constructors

ParseError |

Fields

- parseErrorLocation :: SrcSpan

  Location of the error.

- parseErrorMessage :: String

  Message about the cause of the error.

- parseErrorContents :: String

  Snippet of several lines (typically 5) including a `>` character pointing at the faulty line.

# Parse flags

defaultParseFlags :: ParseFlags #

Default value for `ParseFlags`.

data ParseFlags #

Created with `defaultParseFlags`, used by `parseModuleEx`.

Constructors

ParseFlags |

Fields

- cppFlags :: CppFlags

  How the file is preprocessed (defaults to `NoCpp`).

- baseLanguage :: Maybe Language

  Base language (e.g. Haskell98, Haskell2010), defaults to `Nothing`.

- enabledExtensions :: [Extension]

  List of extensions enabled for parsing, defaults to many non-conflicting extensions.

- disabledExtensions :: [Extension]

  List of extensions disabled for parsing, usually empty.

- fixities :: [FixityInfo]

  List of fixities to be aware of, defaults to those defined in `base`.

data CppFlags #

What C pre processor should be used.

Constructors

CppSimple | Lines prefixed with `#` are stripped.
Cpphs CpphsOptions | The `cpphs` library is used.

type FixityInfo = (String, Associativity, Int) #

A Fixity definition, comprising the name the fixity applies to, the direction and the precedence. As an example, a source file containing:

    infixr 3 `foo`

would create `("foo", RightAssociative, 3)`.

parseFlagsAddFixities :: [FixityInfo] -> ParseFlags -> ParseFlags #

Given some fixities, add them to the existing fixities in `ParseFlags`.