diff --git a/main/define/src/mill/define/BaseModuleTree.scala b/main/define/src/mill/define/BaseModuleTree.scala index f78e0af4dfa..95faf0bdbb8 100644 --- a/main/define/src/mill/define/BaseModuleTree.scala +++ b/main/define/src/mill/define/BaseModuleTree.scala @@ -31,6 +31,10 @@ class BaseModuleTree(value: Seq[(Seq[String], BaseModule)]) { val targetNamesByClass = value .flatMap{ case (segs, base) => base.millDiscover.value.mapValues(_._1.toSet) } .toMap + + val commandNamesByClass = value + .flatMap{ case (segs, base) => base.millDiscover.value.mapValues(_._2.toSet.map[String](_.defaultName)) } + .toMap } object BaseModuleTree { diff --git a/main/resolve/src/mill/resolve/Resolve.scala b/main/resolve/src/mill/resolve/Resolve.scala index 2f28cac6026..e1768215da2 100644 --- a/main/resolve/src/mill/resolve/Resolve.scala +++ b/main/resolve/src/mill/resolve/Resolve.scala @@ -137,9 +137,9 @@ object Resolve { rest: Seq[String], nullCommandDefaults: Boolean ): Iterable[Either[String, Command[_]]] = for { - ep <- ResolveCore.findParent( + ep <- ResolveCore.findFromParents( target.getClass, - discover.value.get(_).flatMap(_._2.find(_.name == name)) + discover.value.get(_).flatMap(_._2.find(_.name == name)).toSeq ) } yield { def withNullDefault(a: mainargs.ArgSig): mainargs.ArgSig = { diff --git a/main/resolve/src/mill/resolve/ResolveCore.scala b/main/resolve/src/mill/resolve/ResolveCore.scala index dd69849922e..2636353305a 100644 --- a/main/resolve/src/mill/resolve/ResolveCore.scala +++ b/main/resolve/src/mill/resolve/ResolveCore.scala @@ -434,46 +434,31 @@ private object ResolveCore { } - val targets = Reflect - .reflect( - cls, - classOf[Task[_]], - x => - namePred(x) && - findParent( - cls, - c => Option.when(baseModules.targetNamesByClass.getOrElse(c, Set()).contains(x))(()) - ).nonEmpty, - noParams = true - ) - .map { m => - Resolved.Target(Segments.labels(decode(m.getName))) -> - None - } + val targets = findFromParents( + cls, + c => baseModules.targetNamesByClass.getOrElse(c, Set()).filter(namePred).toSeq + ).map { name => Resolved.Target(Segments.labels(name)) -> None } - val commands = Reflect - .reflect(cls, classOf[Command[_]], namePred, noParams = false) - .map(m => decode(m.getName)) - .map { name => Resolved.Command(Segments.labels(name)) -> None } + val commands = findFromParents( + cls, + c => baseModules.commandNamesByClass.getOrElse(c, Set()).filter(namePred).toSeq + ).map { name => Resolved.Command(Segments.labels(name)) -> None } modulesOrErr.map(_ ++ targets ++ commands) } - def findParent[T](c: Class[_], - target: Class[_] => Option[T], - seen: collection.mutable.Set[Class[_]] = collection.mutable.Set()): Option[T] = { - target(c) match{ - case Some(v) => Some(v) - case None => - if (seen(c)) None - else { - seen.add(c) - (Option(c.getSuperclass).iterator ++ c.getInterfaces) - .flatMap(findParent(_, target, seen)) - .nextOption() - } + def findFromParents[T](c: Class[_], + target: Class[_] => Seq[T], + seen: collection.mutable.Set[Class[_]] = collection.mutable.Set()): Seq[T] = { + if (seen(c)) Nil + else { + seen.add(c) + + target(c) ++ + (Option(c.getSuperclass).iterator ++ c.getInterfaces) + .flatMap(findFromParents(_, target, seen)) + .toSeq } - } def notFoundResult( diff --git a/main/resolve/test/src/mill/main/ResolveTests.scala b/main/resolve/test/src/mill/main/ResolveTests.scala index 39bdd8f10c3..d9c198fb985 100644 --- a/main/resolve/test/src/mill/main/ResolveTests.scala +++ b/main/resolve/test/src/mill/main/ResolveTests.scala @@ -120,7 +120,7 @@ object ResolveTests extends TestSuite { ) "neg5" - check( "invisible", - Left("Cannot resolve invisible. Try `mill resolve _` or `mill resolve __.invisible&` to see what's available.") + Left("Cannot resolve invisible. Did you mean invisible&?") ) "negBadParse" - check( "invisible&",