Fixes linter that detects missing .value

Fixes #4079

#3216 introduced a linter that checks against missing `.value`, but the tree only checked for `Ident`. This doesn't work because in reality the symbols of build.sbt are transformed to `$somehash.npmInstallTask` where `somehash` is the wrapper object we create. Similarly for the built-in keys, they are presented as `sbt.Keys.compile`.

With this change unused task will fail to load the build with the following message:

```
/sbt-4079/build.sbt:26: error: The key `compile` is not being invoked inside the task definition.

Problem: Keys missing `.value` are not initialized and their dependency is not registered.

Solution: Replace `compile` by `compile.value` or remove it if unused.

  compile
  ^
/sbt-4079/build.sbt:27: error: The key `npmInstallTask` is not being invoked inside the task definition.

Problem: Keys missing `.value` are not initialized and their dependency is not registered.

Solution: Replace `npmInstallTask` by `npmInstallTask.value` or remove it if unused.

  npmInstallTask
  ^
```
This commit is contained in:
Eugene Yokota 2018-04-11 01:31:38 -04:00
parent 54a6262f7f
commit 190dc23f70
1 changed files with 15 additions and 5 deletions

View File

@ -27,6 +27,7 @@ abstract class BaseTaskLinterDSL extends LinterDSL {
private val taskKeyType = typeOf[sbt.TaskKey[_]]
private val settingKeyType = typeOf[sbt.SettingKey[_]]
private val inputKeyType = typeOf[sbt.InputKey[_]]
private val initializeType = typeOf[sbt.Def.Initialize[_]]
private val uncheckedWrappers = MutableSet.empty[Tree]
var insideIf: Boolean = false
var insideAnon: Boolean = false
@ -57,7 +58,7 @@ abstract class BaseTaskLinterDSL extends LinterDSL {
}
@inline def isKey(tpe: Type): Boolean =
tpe <:< taskKeyType || tpe <:< settingKeyType || tpe <:< inputKeyType
tpe <:< initializeType || tpe <:< taskKeyType || tpe <:< settingKeyType || tpe <:< inputKeyType
def detectAndErrorOnKeyMissingValue(i: Ident): Unit = {
if (isKey(i.tpe)) {
@ -66,6 +67,13 @@ abstract class BaseTaskLinterDSL extends LinterDSL {
} else ()
}
def detectAndErrorOnKeyMissingValue(s: Select): Unit = {
if (isKey(s.tpe)) {
val keyName = s.name.decodedName.toString
ctx.error(s.pos, TaskLinterDSLFeedback.missingValueForKey(keyName))
} else ()
}
override def traverse(tree: ctx.universe.Tree): Unit = {
tree match {
case ap @ Apply(TypeApply(Select(_, nme), tpe :: Nil), qual :: Nil) =>
@ -118,11 +126,13 @@ abstract class BaseTaskLinterDSL extends LinterDSL {
// TODO: Consider using unused names analysis to be able to report on more cases
case ValDef(_, valName, _, rhs) if valName == termNames.WILDCARD =>
rhs match {
case i: Ident => detectAndErrorOnKeyMissingValue(i)
case _ => ()
case i: Ident => detectAndErrorOnKeyMissingValue(i)
case s: Select => detectAndErrorOnKeyMissingValue(s)
case _ => ()
}
case i: Ident => detectAndErrorOnKeyMissingValue(i)
case _ => ()
case i: Ident => detectAndErrorOnKeyMissingValue(i)
case s: Select => detectAndErrorOnKeyMissingValue(s)
case t => ()
}
}
traverseTrees(stmts)