Merge pull request #5186 from unisonweb/lsp/unused-binding-detection

This commit is contained in:
Arya Irani 2024-07-05 19:25:39 -04:00 committed by GitHub
commit 0331d2287c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 1 deletions

View File

@ -49,3 +49,10 @@ annToRange = \case
Ann.External -> Nothing
Ann.GeneratedFrom a -> annToRange a
Ann.Ann start end -> Just $ Range (uToLspPos start) (uToLspPos end)
annToURange :: Ann.Ann -> Maybe Range.Range
annToURange = \case
Ann.Intrinsic -> Nothing
Ann.External -> Nothing
Ann.GeneratedFrom a -> annToURange a
Ann.Ann start end -> Just $ Range.Range start end

View File

@ -35,6 +35,7 @@ import Unison.KindInference.Error qualified as KindInference
import Unison.LSP.Conversions
import Unison.LSP.Conversions qualified as Cv
import Unison.LSP.Diagnostics (DiagnosticSeverity (..), mkDiagnostic, reportDiagnostics)
import Unison.LSP.FileAnalysis.UnusedBindings qualified as UnusedBindings
import Unison.LSP.Orphans ()
import Unison.LSP.Types
import Unison.LSP.VFS qualified as VFS
@ -111,12 +112,13 @@ checkFile doc = runMaybeT do
& toRangeMap
let typeSignatureHints = fromMaybe mempty (mkTypeSignatureHints <$> parsedFile <*> typecheckedFile)
let fileSummary = FileSummary.mkFileSummary parsedFile typecheckedFile
let unusedBindingDiagnostics = fileSummary ^.. _Just . to termsBySymbol . folded . folding (\(topLevelAnn, _refId, trm, _type) -> UnusedBindings.analyseTerm fileUri topLevelAnn trm)
let tokenMap = getTokenMap tokens
conflictWarningDiagnostics <-
fold <$> for fileSummary \fs ->
lift $ computeConflictWarningDiagnostics fileUri fs
let diagnosticRanges =
(errDiagnostics <> conflictWarningDiagnostics)
(errDiagnostics <> conflictWarningDiagnostics <> unusedBindingDiagnostics)
& fmap (\d -> (d ^. range, d))
& toRangeMap
let fileAnalysis = FileAnalysis {diagnostics = diagnosticRanges, codeActions = codeActionRanges, fileSummary, typeSignatureHints, ..}

View File

@ -0,0 +1,47 @@
module Unison.LSP.FileAnalysis.UnusedBindings where
import Data.Foldable qualified as Foldable
import Data.Map qualified as Map
import Data.Set qualified as Set
import Data.Text qualified as Text
import Language.LSP.Protocol.Types (Diagnostic)
import Language.LSP.Protocol.Types qualified as Lsp
import U.Core.ABT (ABT (..))
import U.Core.ABT qualified as ABT
import Unison.LSP.Conversions qualified as Cv
import Unison.LSP.Diagnostics qualified as Diagnostic
import Unison.Lexer.Pos qualified as Pos
import Unison.Parser.Ann (Ann)
import Unison.Prelude
import Unison.Symbol (Symbol (..))
import Unison.Term (Term)
import Unison.Util.Range qualified as Range
import Unison.Var qualified as Var
analyseTerm :: Lsp.Uri -> Ann -> Term Symbol Ann -> [Diagnostic]
analyseTerm fileUri topLevelTermAnn tm =
let (unusedVars, _) = ABT.cata alg tm
in Map.toList unusedVars & mapMaybe \(v, _ann) -> do
name <- getRelevantVarName v
-- Unfortunately we don't capture the annotation of the actual binding when parsing :'(, for now the least
-- annoying thing to do is just highlight the top of the binding.
urange <- Cv.annToURange topLevelTermAnn <&> (\(Range.Range start@(Pos.Pos line _col) _end) -> Range.Range start (Pos.Pos line 9999))
let lspRange = Cv.uToLspRange urange
pure $ Diagnostic.mkDiagnostic fileUri lspRange Diagnostic.DiagnosticSeverity_Warning ("Unused binding " <> tShow name <> " inside this term.\nUse the binding, or prefix it with an _ to dismiss this warning.") []
where
getRelevantVarName :: Symbol -> Maybe Text
getRelevantVarName = \case
-- We only care about user bindings which don't start with an underscore
Symbol _ (Var.User n) -> do
guard (not (Text.isPrefixOf "_" n))
pure n
_ -> Nothing
alg :: (Foldable f, Ord v) => Ann -> ABT f v (Map v Ann, Set v) -> (Map v Ann, Set v)
alg ann abt = case abt of
Var v -> (mempty, Set.singleton v)
Cycle x -> x
Abs v (unusedBindings, usedVars) ->
if v `Set.member` usedVars
then (unusedBindings, Set.delete v usedVars)
else (Map.insert v ann unusedBindings, usedVars)
Tm fx -> Foldable.fold fx

View File

@ -130,6 +130,7 @@ library
Unison.LSP.Conversions
Unison.LSP.Diagnostics
Unison.LSP.FileAnalysis
Unison.LSP.FileAnalysis.UnusedBindings
Unison.LSP.FoldingRange
Unison.LSP.Formatting
Unison.LSP.HandlerUtils