hlint-2.0.9: Source code suggestions

Safe Haskell | None
Language | Haskell2010

Language.Haskell.HLint3

Contents

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

Description

WARNING: This module represents the evolving second version of the HLint API. It will be renamed to drop the "3" in the next major version.

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 -> [(Module_, [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)
- argsSettings :: [String] -> IO (ParseFlags, [Classify], Hint)
- findSettings :: (String -> IO (FilePath, Maybe String)) -> Maybe String -> IO ([Fixity], [Classify], [Either HintBuiltin HintRule])
- readSettingsFile :: Maybe FilePath -> String -> IO (FilePath, Maybe String)
- data HintBuiltin
  - = HintList
  - | HintListRec
  - | HintMonad
  - | HintLambda
  - | HintBracket
  - | HintNaming
  - | HintPattern
  - | HintImport
  - | HintExport
  - | HintPragma
  - | HintExtensions
  - | HintUnsafe
  - | HintDuplicate
  - | HintRestrict
  - | HintComment
  - | HintNewType
- data HintRule = HintRule {
  - hintRuleSeverity :: Severity
  - hintRuleName :: String
  - hintRuleScope :: Scope
  - hintRuleLHS :: Exp_
  - hintRuleRHS :: Exp_
  - hintRuleSide :: Maybe Exp_
  - hintRuleNotes :: [Note]
  }
- data Hint = Hint {
  - hintModules :: [Setting] -> [(Scope, Module_)] -> [Idea]
  - hintModule :: [Setting] -> Scope -> Module_ -> [Idea]
  - hintDecl :: [Setting] -> Scope -> Module_ -> Decl_ -> [Idea]
  - hintComment :: [Setting] -> Comment -> [Idea]
  }
- resolveHints :: [Either HintBuiltin HintRule] -> Hint
- data Scope
- scopeCreate :: Module_ -> Scope
- scopeMatch :: (Scope, QName S) -> (Scope, QName S) -> Bool
- scopeMove :: (Scope, QName S) -> Scope -> QName S
- parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module_, [Comment]))
- defaultParseFlags :: ParseFlags
- parseFlagsAddFixities :: [Fixity] -> ParseFlags -> ParseFlags
- data ParseError = ParseError {
  - parseErrorLocation :: SrcLoc
  - parseErrorMessage :: String
  - parseErrorContents :: String
  }
- data ParseFlags = ParseFlags {
  - cppFlags :: CppFlags
  - hseFlags :: ParseMode
  }
- data CppFlags
  - = NoCpp
  - | CppSimple
  - | Cpphs CpphsOptions

# Documentation

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 a your server with untrusted input.

applyHints :: [Classify] -> Hint -> [(Module_, [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 # |
Methods (==) :: Idea -> Idea -> Bool # (/=) :: Idea -> Idea -> Bool #
Ord Idea # |
Methods compare :: Idea -> Idea -> Ordering # (<) :: Idea -> Idea -> Bool # (<=) :: Idea -> Idea -> Bool # (>) :: Idea -> Idea -> Bool # (>=) :: Idea -> Idea -> Bool # max :: Idea -> Idea -> Idea # min :: Idea -> Idea -> Idea #
Show Idea # |
Methods showsPrec :: Int -> Idea -> ShowS # show :: Idea -> String # showList :: [Idea] -> ShowS #

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 # |
Methods minBound :: Severity # maxBound :: Severity #
Enum Severity # |
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] #
Eq Severity # |
Methods (==) :: Severity -> Severity -> Bool # (/=) :: Severity -> Severity -> Bool #
Ord Severity # |
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 #
Read Severity # |
Methods readsPrec :: Int -> ReadS Severity # readList :: ReadS [Severity] # readPrec :: ReadPrec Severity # readListPrec :: ReadPrec [Severity] #
Show Severity # |
Methods showsPrec :: Int -> Severity -> ShowS # show :: Severity -> String # showList :: [Severity] -> ShowS #

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 # |
Methods (==) :: Note -> Note -> Bool # (/=) :: Note -> Note -> Bool #
Ord Note # |
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 #
Show Note # |
Methods showsPrec :: Int -> Note -> ShowS # show :: Note -> String # showList :: [Note] -> ShowS #

# 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 # |
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 containg `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 ([Fixity], [Classify], [Either HintBuiltin HintRule]) #

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 HintBuiltin #

A list of the builtin hints wired into HLint. This list is likely to grow over time.

Constructors

HintList |
HintListRec |
HintMonad |
HintLambda |
HintBracket |
HintNaming |
HintPattern |
HintImport |
HintExport |
HintPragma |
HintExtensions |
HintUnsafe |
HintDuplicate |
HintRestrict |
HintComment |
HintNewType |

Instances

Bounded HintBuiltin # |
Methods minBound :: HintBuiltin # maxBound :: HintBuiltin #
Enum HintBuiltin # |
Methods succ :: HintBuiltin -> HintBuiltin # pred :: HintBuiltin -> HintBuiltin # toEnum :: Int -> HintBuiltin # fromEnum :: HintBuiltin -> Int # enumFrom :: HintBuiltin -> [HintBuiltin] # enumFromThen :: HintBuiltin -> HintBuiltin -> [HintBuiltin] # enumFromTo :: HintBuiltin -> HintBuiltin -> [HintBuiltin] # enumFromThenTo :: HintBuiltin -> HintBuiltin -> HintBuiltin -> [HintBuiltin] #
Eq HintBuiltin # |
Methods (==) :: HintBuiltin -> HintBuiltin -> Bool # (/=) :: HintBuiltin -> HintBuiltin -> Bool #
Ord HintBuiltin # |
Methods compare :: HintBuiltin -> HintBuiltin -> Ordering # (<) :: HintBuiltin -> HintBuiltin -> Bool # (<=) :: HintBuiltin -> HintBuiltin -> Bool # (>) :: HintBuiltin -> HintBuiltin -> Bool # (>=) :: HintBuiltin -> HintBuiltin -> Bool # max :: HintBuiltin -> HintBuiltin -> HintBuiltin # min :: HintBuiltin -> HintBuiltin -> HintBuiltin #
Show HintBuiltin # |
Methods showsPrec :: Int -> HintBuiltin -> ShowS # show :: HintBuiltin -> String # showList :: [HintBuiltin] -> ShowS #

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_ LHS hintRuleRHS :: Exp_ RHS hintRuleSide :: Maybe Exp_ Side condition, typically specified with `where _ = ...`. hintRuleNotes :: [Note] Notes about application of the hint.

Instances

Show HintRule # |
Methods showsPrec :: Int -> HintRule -> ShowS # show :: HintRule -> String # showList :: [HintRule] -> ShowS #

data Hint #

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

Constructors

Hint |
Fields hintModules :: [Setting] -> [(Scope, Module_)] -> [Idea] Given a list of modules (and their scope information) generate some `Idea`s. hintModule :: [Setting] -> Scope -> Module_ -> [Idea] Given a single module and its scope information generate some `Idea`s. hintDecl :: [Setting] -> Scope -> Module_ -> Decl_ -> [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 :: [Setting] -> Comment -> [Idea] Given a comment generate some `Idea`s.

Instances

Monoid Hint # |
Methods mempty :: Hint # mappend :: Hint -> Hint -> Hint # mconcat :: [Hint] -> Hint #

resolveHints :: [Either HintBuiltin HintRule] -> Hint #

Transform a list of `HintBuiltin` or `HintRule` into a `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 # |
Methods showsPrec :: Int -> Scope -> ShowS # show :: Scope -> String # showList :: [Scope] -> ShowS #
Monoid Scope # |
Methods mempty :: Scope # mappend :: Scope -> Scope -> Scope # mconcat :: [Scope] -> Scope #

scopeCreate :: Module_ -> Scope #

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

scopeMatch :: (Scope, QName S) -> (Scope, QName S) -> Bool #

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

scopeMove :: (Scope, QName S) -> Scope -> QName S #

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_, [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`.

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

Given some fixities, add them to the existing fixities in `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 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.