Language.Haskell.HLint2

hlint-1.9.32: Source code suggestions

Safe Haskell | None
Language | Haskell98

Language.Haskell.HLint2

Contents

- Idea data type
- Settings
- Hints
- Scopes
- Haskell-src-exts
- File encodings

Description

WARNING: This module represents the evolving second version of the HLint API. It will be deleted in favour of Language.Haskell.HLint3 in the next major version.

This module provides a way to apply HLint hints. As an example of approximating the `hlint` experience:

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

Synopsis

- applyHints :: [Classify] -> Hint -> [(Module SrcSpanInfo, [Comment])] -> [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
  - | Note String
- data Classify = Classify {
  - classifySeverity :: Severity
  - classifyHint :: String
  - classifyModule :: String
  - classifyDecl :: String
  }
- getHLintDataDir :: IO FilePath
- autoSettings :: IO (ParseFlags, [Classify], Hint)
- autoSettings' :: FilePath -> IO (ParseFlags, [Classify], Hint)
- findSettings :: FilePath -> FilePath -> Maybe String -> IO ([String], [Module SrcSpanInfo])
- readSettings :: Module SrcSpanInfo -> ([Classify], [HintRule])
- data Hint = Hint {
  - hintModules :: [(Scope, Module SrcSpanInfo)] -> [Idea]
  - hintModule :: Scope -> Module SrcSpanInfo -> [Idea]
  - hintDecl :: Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea]
  - hintComment :: Comment -> [Idea]
  }
- builtinHints :: [(String, Hint)]
- data HintRule = HintRule {
  - hintRuleSeverity :: Severity
  - hintRuleName :: String
  - hintRuleScope :: Scope
  - hintRuleLHS :: Exp SrcSpanInfo
  - hintRuleRHS :: Exp SrcSpanInfo
  - hintRuleSide :: Maybe (Exp SrcSpanInfo)
  - hintRuleNotes :: [Note]
  }
- hintRules :: [HintRule] -> Hint
- data Scope
- scopeCreate :: Module SrcSpanInfo -> Scope
- scopeMatch :: (Scope, QName SrcSpanInfo) -> (Scope, QName SrcSpanInfo) -> Bool
- scopeMove :: (Scope, QName SrcSpanInfo) -> Scope -> QName SrcSpanInfo
- parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module SrcSpanInfo, [Comment]))
- defaultParseFlags :: ParseFlags
- data ParseError = ParseError {
  - parseErrorLocation :: SrcLoc
  - parseErrorMessage :: String
  - parseErrorContents :: String
  }
- data ParseFlags = ParseFlags {
  - encoding :: TextEncoding
  - cppFlags :: CppFlags
  - hseFlags :: ParseMode
  }
- data CppFlags
  - = NoCpp
  - | CppSimple
  - | Cpphs CpphsOptions
- type Encoding = TextEncoding
- defaultEncoding :: Encoding
- readEncoding :: String -> IO Encoding
- useEncoding :: Handle -> Encoding -> IO ()

# Documentation

applyHints :: [Classify] -> Hint -> [(Module SrcSpanInfo, [Comment])] -> [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 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 module the idea applies to, may be `""` if the module cannot be determined or is a result of cross-module hints. ideaDecl :: String The declaration the idea applies to, 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

Eq Idea |
Ord Idea |
Show Idea |

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.

Instances

Bounded Severity |
Enum Severity |
Eq Severity |
Ord Severity |
Read Severity |
Show Severity |

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.
Note String | An arbitrary note.

Instances

Eq Note |
Ord Note |
Show Note |

# 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

Show Classify |

getHLintDataDir :: IO FilePath

Get the Cabal configured data directory of HLint

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

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

1. Use `findSettings` to find and load the HLint settings files.
2. Use `readSettings` to interpret the settings files, producing `HintRule` values (`LHS ==> RHS` replacements) and `Classify` values to assign `Severity` ratings to hints.
3. Use `builtinHints` and `hintRules` to generate a `Hint` value.
4. Take all fixities from the `findSettings` modules and put them in the `ParseFlags`.

autoSettings' :: FilePath -> IO (ParseFlags, [Classify], Hint)

findSettings :: FilePath -> FilePath -> Maybe String -> IO ([String], [Module SrcSpanInfo])

Given the data directory (where the `hlint` data files reside, see `getHLintDataDir`), and a filename to read, and optionally that file's contents, produce a pair containing:

1. Builtin hints to use, e.g. `List`, which should be resolved using `builtinHints`.
2. A list of modules containing hints, suitable for processing with `readSettings`.

Any parse failures will result in an exception.

readSettings :: Module SrcSpanInfo -> ([Classify], [HintRule])

Given a module containing HLint settings information return the `Classify` rules and the `HintRule` expressions. Any fixity declarations will be discarded, but any other unrecognised elements will result in an exception.

# Hints

data Hint

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

Constructors

Hint |
Fields hintModules :: [(Scope, Module SrcSpanInfo)] -> [Idea] Given a list of modules (and their scope information) generate some `Idea`s. hintModule :: Scope -> Module SrcSpanInfo -> [Idea] Given a single module and its scope information generate some `Idea`s. hintDecl :: Scope -> Module SrcSpanInfo -> Decl SrcSpanInfo -> [Idea] Given a declaration (with a module and scope) generate some `Idea`s. This function will be partially applied with one module/scope, then used on multiple `Decl` values. hintComment :: Comment -> [Idea] Given a comment generate some `Idea`s.

Instances

Monoid Hint |

builtinHints :: [(String, Hint)]

A list of builtin hints, currently including entries such as `"List"` and `"Bracket"`.

data HintRule

A `LHS ==> RHS` style hint rule.

Constructors

HintRule |
Fields hintRuleSeverity :: Severity Default severity for the hint. hintRuleName :: String Name for the hint. hintRuleScope :: Scope Module scope in which the hint operates. hintRuleLHS :: Exp SrcSpanInfo LHS hintRuleRHS :: Exp SrcSpanInfo RHS hintRuleSide :: Maybe (Exp SrcSpanInfo) Side condition, typically specified with `where _ = ...`. hintRuleNotes :: [Note] Notes about application of the hint.

Instances

Show HintRule |

hintRules :: [HintRule] -> Hint

# Scopes

data Scope

Data type representing the modules in scope within a module. Created with `scopeCreate` and queried with `scopeMatch` and `scopeMove`. Note that the `mempty` `Scope` is not equivalent to `scopeCreate` on an empty module, due to the implicit import of `Prelude`.

Instances

Show Scope |
Monoid Scope |

scopeCreate :: Module SrcSpanInfo -> Scope

Create a `Scope` value from a module, based on the modules imports.

scopeMatch :: (Scope, QName SrcSpanInfo) -> (Scope, QName SrcSpanInfo) -> Bool

Given a two names in scopes, could they possibly refer to the same thing. This property is reflexive.

scopeMove :: (Scope, QName SrcSpanInfo) -> Scope -> QName SrcSpanInfo

Given a name in a scope, and a new scope, create a name for the new scope that will refer to the same thing. If the resulting name is ambiguous, it picks a plausible candidate.

# Haskell-src-exts

parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module SrcSpanInfo, [Comment]))

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.

defaultParseFlags :: ParseFlags

Default value for `ParseFlags`.

data ParseError

A parse error from `parseModuleEx`.

Constructors

ParseError |
Fields parseErrorLocation :: SrcLoc 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.

data ParseFlags

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

Constructors

ParseFlags |
Fields encoding :: TextEncoding How the file is read in (defaults to `utf8`). cppFlags :: CppFlags How the file is preprocessed (defaults to `NoCpp`). hseFlags :: ParseMode How the file is parsed (defaults to all fixities in the `base` package and most non-conflicting extensions).

data CppFlags

What C pre processor should be used.

Constructors

NoCpp | No pre processing is done.
CppSimple | Lines prefixed with `#` are stripped.
Cpphs CpphsOptions | The `cpphs` library is used.

# File encodings

type Encoding = TextEncoding

An `Encoding` represents how characters are stored in a file. Created with `defaultEncoding` or `readEncoding` and used with `useEncoding`.

defaultEncoding :: Encoding

The system default encoding.

readEncoding :: String -> IO Encoding

Create an encoding from a string, or throw an error if the encoding is not known. Accepts many encodings including `locale`, `utf-8` and all those supported by the GHC `mkTextEncoding` function.

useEncoding :: Handle -> Encoding -> IO ()

Apply an encoding to a `Handle`.