{-# LANGUAGE NamedFieldPuns #-}
module Dhall.LSP.Backend.Linting
( Suggestion(..)
, suggest
, Lint.lint
)
where
import Control.Lens (universeOf)
import Data.Maybe (maybeToList)
import Data.Text (Text)
import Dhall.Core
( Binding (..)
, Expr (..)
, Import
, MultiLet (..)
)
import Dhall.LSP.Backend.Diagnostics
import Dhall.Parser (Src)
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Maybe as Maybe
import qualified Dhall.Core as Core
import qualified Dhall.Lint as Lint
data Suggestion = Suggestion {
range :: Range,
suggestion :: Text
}
diagLetInLet :: Expr Src a -> Maybe Suggestion
diagLetInLet (Note _ (Let b e)) = case Core.multiLet b e of
MultiLet _ (Note src (Let {})) ->
Just (Suggestion (rangeFromDhall src) "Superfluous 'in' before nested let binding")
_ -> Nothing
diagLetInLet _ = Nothing
unusedBindings :: Eq a => MultiLet s a -> [ (Text, Maybe s) ]
unusedBindings (MultiLet bindings d) =
let go bs@(Binding { variable = var, value } : _)
| Just _ <- Lint.removeUnusedBindings (Core.wrapInLets bs d) =
[ (var, maybeSrc) ]
where
maybeSrc = case value of
Note src _ -> Just src
_ -> Nothing
go _ = []
in foldMap go (NonEmpty.tails bindings)
diagUnusedBindings :: Eq a => Expr Src a -> [Suggestion]
diagUnusedBindings (Note src (Let b e)) =
map adapt (unusedBindings (Core.multiLet b e))
where
adapt (var, maybeSrc) =
Suggestion (rangeFromDhall finalSrc) ("Unused let binding '" <> var <> "'")
where
finalSrc = Maybe.fromMaybe src maybeSrc
diagUnusedBindings _ = []
suggest :: Expr Src Import -> [Suggestion]
suggest expr = concat [ maybeToList (diagLetInLet e) ++ diagUnusedBindings e
| e <- universeOf Core.subExpressions expr ]