From 2103dbc5230ddf2a369389f179f4ef70eae344f2 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 22 May 2014 09:02:18 -0700 Subject: SI-8610 -Xlint is multichoice option Make -Xlint a "multichoice" option for purposes of option parsing. This allows turning on "lint with these warnings" instead of only "turn off these warnings but enable other lint warnings". ``` $ scalac -Xlint:warn-adapted-args linty.scala # lint plus a warning $ scalac -Xlint warn-adapted-args linty.scala # same $ scalac -Xlint linty.scala # same as now $ scalac -Xlint -- linty.scala # ok, not necessary $ scalac -Xlint _ -- linty.scala # another funky underscore ``` This would also enable Xlint options that are not standalone options, although that is not implemented in this commit. For example, `-Xlint:no-missing-interpolator` could be used to disable that warning. (There is no `-Xoption:flavor=off` syntax.) (`no-` switches would not be enabled by `_`.) --- .../tools/nsc/settings/AbsScalaSettings.scala | 2 +- .../scala/tools/nsc/settings/MutableSettings.scala | 48 ++++++++++++++-------- .../scala/tools/nsc/settings/Warnings.scala | 22 +++++++++- 3 files changed, 52 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala index 38a7525862..ef9695a594 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala @@ -29,7 +29,7 @@ trait AbsScalaSettings { def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting - def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String]): MultiChoiceSetting + def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: () => Unit): MultiChoiceSetting def OutputSetting(outputDirs: OutputDirs, default: String): OutputSetting def PathSetting(name: String, descr: String, default: String): PathSetting def PhasesSetting(name: String, descr: String, default: String): PhasesSetting diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index 54e444decf..5b5c80c514 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -211,10 +211,10 @@ class MutableSettings(val errorFn: String => Unit) add(new ChoiceSetting(name, helpArg, descr, choices, default)) def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser)) def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr)) - def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String]): MultiChoiceSetting = { + def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: () => Unit = () => ()): MultiChoiceSetting = { val fullChoix = choices.mkString(": ", ",", ".") val fullDescr = s"$descr$fullChoix" - add(new MultiChoiceSetting(name, helpArg, fullDescr, choices)) + add(new MultiChoiceSetting(name, helpArg, fullDescr, choices, default)) } def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default)) def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default)) @@ -553,12 +553,18 @@ class MutableSettings(val errorFn: String => Unit) } } + /** A setting that receives any combination of enumerated values, + * including "_" to mean all values. + * In non-colonated mode, stops consuming args at the first + * non-value, instead of at the next option, as for a multi-string. + */ class MultiChoiceSetting private[nsc]( name: String, arg: String, descr: String, - override val choices: List[String]) - extends MultiStringSetting(name, arg, descr) + override val choices: List[String], + override val default: () => Unit + ) extends MultiStringSetting(name, arg, descr) /** A setting that accumulates all strings supplied to it, * until it encounters one starting with a '-'. @@ -570,24 +576,34 @@ class MutableSettings(val errorFn: String => Unit) extends Setting(name, descr) with Clearable { type T = List[String] protected var v: T = Nil + val default: () => Unit = () => () // no natural default def appendToValue(str: String) { value ++= List(str) } def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'") - def tryToSet(args: List[String]) = { - val (strings, rest) = args span (x => !x.startsWith("-")) - strings foreach { - case "_" if choices.nonEmpty => choices foreach appendToValue + private def tts(args: List[String], verify: Boolean) = { + def tryArg(arg: String) = arg match { + case "_" if choices.nonEmpty => choices foreach appendToValue case s if choices.isEmpty || (choices contains s) => appendToValue(s) - case s => badChoice(s, name) + case s => badChoice(s, name) } + def loop(args: List[String]): List[String] = args match { + case Nil => Nil + case arg :: _ + if (arg startsWith "-") || (!verify && choices.nonEmpty && !(choices contains arg)) + => args + case arg :: rest => tryArg(arg) ; loop(rest) + } + val rest = loop(args) + if (rest.size == args.size) default() // if no arg consumed, trigger default action Some(rest) } - override def tryToSetColon(args: List[String]) = tryToSet(args) + def tryToSet(args: List[String]) = tts(args, verify = false) + override def tryToSetColon(args: List[String]) = tts(args, verify = true) override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide - def clear(): Unit = (v = Nil) - def unparse: List[String] = value map (name + ":" + _) - def contains(s: String) = value contains s + def clear(): Unit = (v = Nil) + def unparse: List[String] = value map (name + ":" + _) + def contains(s: String) = value contains s withHelpSyntax(name + ":<" + arg + ">") } @@ -606,10 +622,8 @@ class MutableSettings(val errorFn: String => Unit) protected var v: T = default def indexOfChoice: Int = choices indexOf value - private def usageErrorMessage = { - "Usage: %s:<%s>\n where <%s> choices are %s (default: %s)\n".format( - name, helpArg, helpArg, choices mkString ", ", default) - } + private def usageErrorMessage = f"Usage: $name:<$helpArg>%n where <$helpArg> choices are ${choices mkString ", "} (default: $default)%n" + def tryToSet(args: List[String]) = errorAndValue(usageErrorMessage, None) override def tryToSetColon(args: List[String]) = args match { diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 1509ad13b8..ae2696accf 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -50,8 +50,26 @@ trait Warnings { val warnUnused = BooleanSetting ("-Ywarn-unused", "Warn when local and private vals, vars, defs, and types are are unused") val warnUnusedImport = BooleanSetting ("-Ywarn-unused-import", "Warn when imports are unused") - // Warning groups. - val lint = BooleanSetting("-Xlint", "Enable recommended additional warnings.") enablingIfNotSetByUser lintWarnings + // Warning groups. + val lint = { + // Boolean setting for testing if lint is on; not "added" to option processing + val xlint = new BooleanSetting("-Xlint", "Enable recommended additional warnings.") + val lintables = (lintWarnings map (_.name drop 2)).sorted + def propagate(ss: List[String]): Unit = ss match { + case w :: rest => lintWarnings find (_.name == s"-Y$w") foreach (_.value = true) ; propagate(rest) + case Nil => () + } + def enableAll(): Unit = { // enable lint and the group + xlint.value = true + for (s <- lintWarnings if !s.isSetByUser) s.value = true + } + // The command option + MultiChoiceSetting("-Xlint", "warning", "Enable recommended additional warnings", lintables, enableAll) withPostSetHook { x => + propagate(x.value) // enabling the selections (on each append to value) + xlint.value = true // only enables lint, not the group + } + xlint + } // Backward compatibility. @deprecated("Use fatalWarnings", "2.11.0") def Xwarnfatal = fatalWarnings // used by sbt -- cgit v1.2.3