This PR adds a `register_linter_set` command for declaring linter sets. The `getLinterValue` function now checks if the present linter is contained in a set that has been enabled (using the `set_option` command or on the command line). The implementation stores linter set membership in an environment extension. As a consequence, we need to pass more data to `getLinterValue`: the argument of ype `Options` has been replaced with a `LinterOptions`, which you can access by writing `getLinterOptions` instead of `getOptions`. (The alternative I considered is to modify the `Options` structure. The current approach seems a bit higher-level and lower-impact.) The logic for checking whether a linter should be enabled now goes in four steps: 1. If the linter has been explicitly en/disabled, return that. 2. If `linter.all` has been explicitly set, return that. 3. If the linter is in any set that has been enabled, return true. 4. Return the default setting for the linter. Reasoning: * The linter's explicit setting should take precedence. * We want to be able to disable all but the explicitly enabled linters with `linter.all`, so it should take precedence over linter sets. * We want to progressively enable more linters as they become available, so the check over sets should be *any*. * Falling back to the default value last, ensures compatibility with the current way we define linters. The public-facing API currently does not allow modifying sets: all linters have to be added when the set is declared. This way, there is one place where all the contents of the set are listed. Linter sets can be declared to contain linters that have not been declared (yet): this allows declaring linter sets low down in the import hierarchy when not all the requested linters are defined yet. --------- Co-authored-by: grunweg <rothgami@math.hu-berlin.de>
58 lines
2.3 KiB
Text
58 lines
2.3 KiB
Text
/-
|
|
Copyright (c) 2022 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import Lean.Linter.Basic
|
|
import Lean.Attributes
|
|
import Lean.Elab.InfoTree.Main
|
|
|
|
namespace Lean.Linter
|
|
|
|
register_builtin_option linter.deprecated : Bool := {
|
|
defValue := true
|
|
descr := "if true, generate deprecation warnings"
|
|
}
|
|
|
|
structure DeprecationEntry where
|
|
newName? : Option Name := none
|
|
text? : Option String := none
|
|
since? : Option String := none
|
|
deriving Inhabited
|
|
|
|
builtin_initialize deprecatedAttr : ParametricAttribute DeprecationEntry ←
|
|
registerParametricAttribute {
|
|
name := `deprecated
|
|
descr := "mark declaration as deprecated",
|
|
getParam := fun _ stx => do
|
|
let `(attr| deprecated $[$id?]? $[$text?]? $[(since := $since?)]?) := stx
|
|
| throwError "invalid `[deprecated]` attribute"
|
|
let newName? ← id?.mapM Elab.realizeGlobalConstNoOverloadWithInfo
|
|
let text? := text?.map TSyntax.getString
|
|
let since? := since?.map TSyntax.getString
|
|
if id?.isNone && text?.isNone then
|
|
logWarning "`[deprecated]` attribute should specify either a new name or a deprecation message"
|
|
if since?.isNone then
|
|
logWarning "`[deprecated]` attribute should specify the date or library version at which the deprecation was introduced, using `(since := \"...\")`"
|
|
return { newName?, text?, since? }
|
|
}
|
|
|
|
def isDeprecated (env : Environment) (declName : Name) : Bool :=
|
|
Option.isSome <| deprecatedAttr.getParam? env declName
|
|
|
|
def _root_.Lean.MessageData.isDeprecationWarning (msg : MessageData) : Bool :=
|
|
msg.hasTag (· == ``deprecatedAttr)
|
|
|
|
def getDeprecatedNewName (env : Environment) (declName : Name) : Option Name := do
|
|
(← deprecatedAttr.getParam? env declName).newName?
|
|
|
|
def checkDeprecated [Monad m] [MonadEnv m] [MonadLog m] [AddMessageContext m] [MonadOptions m] (declName : Name) : m Unit := do
|
|
if getLinterValue linter.deprecated (← getLinterOptions) then
|
|
let some attr := deprecatedAttr.getParam? (← getEnv) declName | pure ()
|
|
logWarning <| .tagged ``deprecatedAttr <|
|
|
m!"`{.ofConstName declName true}` has been deprecated" ++ match attr.text? with
|
|
| some text => s!": {text}"
|
|
| none => match attr.newName? with
|
|
| some newName => m!": use `{.ofConstName newName true}` instead"
|
|
| none => ""
|