Document lintUnused limitation for .all(ScopeFilter).value per review; revert dynamic-deps implementation

This commit is contained in:
bitloi 2026-02-09 20:11:51 +01:00
parent 84b79b99a2
commit f5887c1f8f
5 changed files with 7 additions and 66 deletions

View File

@ -701,7 +701,9 @@ object Keys {
@deprecated("No longer used", "1.3.0")
private[sbt] val executeProgress = settingKey[State => TaskProgress]("Experimental task execution listener.").withRank(DTask)
val commandProgress = settingKey[Seq[ExecuteProgress2]]("Command progress listeners receive events when commands start and end, in addition to task progress events.")
val lintUnused = inputKey[Unit]("Check for keys unused by other settings and tasks.")
val lintUnused = inputKey[Unit](
"Check for keys unused by other settings and tasks. Keys that are only used via key.all(ScopeFilter).value may still be reported as unused."
)
val lintIncludeFilter = settingKey[String => Boolean]("Filters key names that should be included in the lint check.")
val lintExcludeFilter = settingKey[String => Boolean]("Filters key names that should be excluded in the lint check.")
val excludeLintKeys = settingKey[Set[Def.KeyedInitialize[?]]]("Keys excluded from lintUnused task")

View File

@ -97,12 +97,8 @@ object ScopeFilter {
* static inspections will not show them.
*/
def all(sfilter: => ScopeFilter): Initialize[Seq[A]] =
val inner = Def.flatMap(getData): data =>
Def.flatMap(getData): data =>
sfilter(data).toSeq.map(s => Project.inScope(s, i)).join
val dynamicDeps = i match
case k: Def.KeyedInitialize[?] => Seq((k.scopedKey.key, sfilter))
case _ => Nil
Def.withDynamicDependencies(inner, dynamicDeps)
final class TaskKeyAll[A] private[sbt] (i: Initialize[Task[A]]):
/**
@ -110,13 +106,9 @@ object ScopeFilter {
* static inspections will not show them.
*/
def all(sfilter: => ScopeFilter): Initialize[Task[Seq[A]]] =
val inner = Def.flatMap(getData): data =>
Def.flatMap(getData): data =>
import std.TaskExtra.*
sfilter(data).toSeq.map(s => Project.inScope(s, i)).join(_.join)
val dynamicDeps = i match
case k: Def.KeyedInitialize[?] => Seq((k.scopedKey.key, sfilter))
case _ => Nil
Def.withDynamicDependencies(inner, dynamicDeps)
private[sbt] val Make = new Make {}
trait Make {
@ -245,21 +237,6 @@ object ScopeFilter {
.toMap
new Data(units, resolve, new AllScopes(scopes, grouped))
def expandDynamicDeps(deps: Seq[Any], structure: BuildStructure): Set[
Def.ScopedKey[?]
] =
if deps.isEmpty then Set.empty
else
val data = dataFromStructure(structure)
val result = scala.collection.mutable.Set.empty[Def.ScopedKey[?]]
for dep <- deps do
dep match
case (key: AttributeKey[?], filter: ScopeFilter) =>
try filter(data).foreach(scope => result += Def.ScopedKey(scope, key))
catch case _: Exception => ()
case _ =>
result.toSet
private[sbt] val allScopes: Initialize[AllScopes] = Def.setting {
val scopes = Def.StaticScopes.value
val grouped: ScopeMap =

View File

@ -135,11 +135,7 @@ object LintUnused {
val display = Def.showShortKey(None) // extracted.showKey
val comp = structure.compiledMap
val cMap = Def.flattenLocals(comp)
val staticUsed: Set[ScopedKey[?]] = cMap.values.flatMap(_.dependencies).toSet
val dynamicDeps =
comp.values.flatMap(_.settings).flatMap(s => s.init.dynamicDependencies).toSeq
val dynamicUsed = ScopeFilter.expandDynamicDeps(dynamicDeps, structure)
val used: Set[ScopedKey[?]] = staticUsed ++ dynamicUsed
val used: Set[ScopedKey[?]] = cMap.values.flatMap(_.dependencies).toSet
val unused: Seq[ScopedKey[?]] = cMap.keys.filter(!used.contains(_)).toSeq
val withDefinedAts: Seq[UnusedKey] = unused.map: u =>
val data = Project.scopedKeyData(structure, u)

View File

@ -54,8 +54,7 @@ class EvaluateSettings[I <: Init](
o.a match
case None => constant(() => o.f(None))
case Some(i) => single[s, A](transform(i), x => o.f(Some(x)))
case d: DynamicDepsInitialize[A] => transform(d.inner)
case StaticScopes => strictConstant(allScopes)
case StaticScopes => strictConstant(allScopes)
private lazy val roots: Seq[INode[?]] = compiledSettings.flatMap { cs =>
(cs.settings map { s =>

View File

@ -631,9 +631,6 @@ trait Init:
sealed trait Initialize[A1]:
def dependencies: Seq[ScopedKey[?]]
/** Dynamic dependencies (e.g. from .all(ScopeFilter)) not visible in the static graph. */
private[sbt] def dynamicDependencies: Seq[Any] = Nil
def apply[A2](g: A1 => A2): Initialize[A2]
private[sbt] def mapReferenced(g: MapScoped): Initialize[A1]
@ -890,7 +887,6 @@ trait Init:
private[sbt] final class Bind[S, A1](val f: S => Initialize[A1], val in: Initialize[S])
extends Initialize[A1]:
override def dependencies: Seq[ScopedKey[?]] = in.dependencies
override def dynamicDependencies: Seq[Any] = in.dynamicDependencies
override def apply[A2](g: A1 => A2): Initialize[A2] = Bind[S, A2](s => f(s)(g), in)
override def evaluate(ss: Settings): A1 = f(in.evaluate(ss)).evaluate(ss)
override def mapReferenced(g: MapScoped) =
@ -911,7 +907,6 @@ trait Init:
private[sbt] final class Optional[S, A1](val a: Option[Initialize[S]], val f: Option[S] => A1)
extends Initialize[A1]:
override def dependencies: Seq[ScopedKey[?]] = deps(a.toList)
override def dynamicDependencies: Seq[Any] = a.toList.flatMap(_.dynamicDependencies)
override def apply[A2](g: A1 => A2): Initialize[A2] = new Optional[S, A2](a, g compose f)
override def mapReferenced(g: MapScoped): Initialize[A1] =
@ -961,7 +956,6 @@ trait Init:
private[sbt] final class Uniform[A1, A2](val f: Seq[A1] => A2, val inputs: List[Initialize[A1]])
extends Initialize[A2]:
override def dependencies: Seq[ScopedKey[?]] = deps(inputs)
override def dynamicDependencies: Seq[Any] = inputs.flatMap(_.dynamicDependencies)
override def mapReferenced(g: MapScoped): Initialize[A2] =
Uniform(f, inputs.map(_.mapReferenced(g)))
override def mapConstant(g: MapConstant): Initialize[A2] =
@ -986,7 +980,6 @@ trait Init:
import sbt.internal.util.TupleMapExtension.*
override def dependencies: Seq[ScopedKey[?]] = deps(inputs.toList0)
override def dynamicDependencies: Seq[Any] = inputs.toList0.flatMap(_.dynamicDependencies)
override def mapReferenced(g: MapScoped): Initialize[A1] =
Apply(f, inputs.transform(mapReferencedK(g)))
override def mapConstant(g: MapConstant): Initialize[A1] =
@ -1007,32 +1000,6 @@ trait Init:
inputs.toList0.foldLeft(init) { (v, i) => i.processAttributes(v)(f) }
end Apply
private[sbt] final class DynamicDepsInitialize[A1](
val inner: Initialize[A1],
val dynamicDeps: Seq[Any]
) extends Initialize[A1]:
override def dependencies: Seq[ScopedKey[?]] = inner.dependencies
override def dynamicDependencies: Seq[Any] = dynamicDeps
override def apply[A2](g: A1 => A2): Initialize[A2] =
DynamicDepsInitialize(inner.apply(g), dynamicDeps)
override def mapReferenced(g: MapScoped): Initialize[A1] =
DynamicDepsInitialize(inner.mapReferenced(g), dynamicDeps)
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] =
inner.validateKeyReferenced(g).map(DynamicDepsInitialize(_, dynamicDeps))
override def mapConstant(g: MapConstant): Initialize[A1] =
DynamicDepsInitialize(inner.mapConstant(g), dynamicDeps)
override def evaluate(ss: Settings): A1 = inner.evaluate(ss)
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
inner.processAttributes(init)(f)
end DynamicDepsInitialize
private[sbt] object DynamicDepsInitialize:
def apply[A1](inner: Initialize[A1], deps: Seq[Any]): Initialize[A1] =
if deps.isEmpty then inner else new DynamicDepsInitialize(inner, deps)
def withDynamicDependencies[A1](init: Initialize[A1], deps: Seq[Any]): Initialize[A1] =
DynamicDepsInitialize(init, deps)
private def remove[A](s: Seq[A], v: A) = s.filterNot(_ == v)
final class Undefined private[sbt] (val defining: Setting[?], val referencedKey: ScopedKey[?])