From b562d965dc30bb1fdd9433a6675bfe8e38b8c667 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Fri, 22 Aug 2014 14:55:08 +0200 Subject: -Ystatistics accepts a list of phases, cleanups in MultiChoiceSetting MultiChoiceSetting and Xlint with its deprecated aliases is now a bit simpler, but there's still room for improvement, as noted in comments. --- src/compiler/scala/tools/nsc/Global.scala | 2 +- src/compiler/scala/tools/nsc/MainBench.scala | 2 +- .../scala/tools/nsc/backend/opt/Inliners.scala | 2 +- .../tools/nsc/settings/AbsScalaSettings.scala | 2 +- .../scala/tools/nsc/settings/MutableSettings.scala | 122 ++++++++++--- .../scala/tools/nsc/settings/ScalaSettings.scala | 25 ++- .../scala/tools/nsc/settings/Warnings.scala | 194 ++++++++------------- .../scala/tools/nsc/typechecker/Infer.scala | 2 +- .../scala/tools/nsc/util/StatisticsInfo.scala | 4 +- .../scala/tools/nsc/settings/SettingsTest.scala | 63 ++++++- 10 files changed, 254 insertions(+), 164 deletions(-) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 82ffb35c3f..452081cff1 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1372,7 +1372,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) runCheckers() // output collected statistics - if (settings.Ystatistics) + if (settings.YstatisticsEnabled) statistics.print(phase) advancePhase() diff --git a/src/compiler/scala/tools/nsc/MainBench.scala b/src/compiler/scala/tools/nsc/MainBench.scala index 03190a63f3..eb56c8a230 100644 --- a/src/compiler/scala/tools/nsc/MainBench.scala +++ b/src/compiler/scala/tools/nsc/MainBench.scala @@ -24,7 +24,7 @@ object MainBench extends Driver with EvalLoop { var start = System.nanoTime() for (i <- 0 until NIter) { if (i == NIter-1) { - theCompiler.settings.Ystatistics.value = true + theCompiler.settings.YstatisticsPhases.value = theCompiler.settings.YstatisticsPhases.default.get Statistics.enabled = true } process(args) diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 8df3969c49..351eb23c4c 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -283,7 +283,7 @@ abstract class Inliners extends SubComponent { } val tfa = new analysis.MTFAGrowable() - tfa.stat = global.settings.Ystatistics.value + tfa.stat = global.settings.YstatisticsEnabled val staleOut = new mutable.ListBuffer[BasicBlock] val splicedBlocks = mutable.Set.empty[BasicBlock] val staleIn = mutable.Set.empty[BasicBlock] diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala index d0b8fd70ed..cd2cb183b3 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], default: Option[() => Unit])(helper: MultiChoiceSetting => String): MultiChoiceSetting + def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], descriptions: List[String], default: Option[List[String]]): 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 f26192f88a..b9b9257d63 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -209,12 +209,11 @@ class MutableSettings(val errorFn: String => Unit) def BooleanSetting(name: String, descr: String) = add(new BooleanSetting(name, descr)) def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String) = 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 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], default: Option[() => Unit] = None)( - helper: MultiChoiceSetting => String = _ => choices.mkString(f"$descr:%n", f"%n ", f"%n") - ) = - add(new MultiChoiceSetting(name, helpArg, descr, choices, default, helper)) + def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], descriptions: List[String], default: Option[List[String]] = None) = + add(new MultiChoiceSetting(name, helpArg, descr, choices, descriptions, 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)) def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default)) @@ -553,57 +552,132 @@ class MutableSettings(val errorFn: String => Unit) } } - /** A setting that receives any combination of enumerated values, - * including "_" to mean all values and "help" for verbose info. - * In non-colonated mode, stops consuming args at the first - * non-value, instead of at the next option, as for a multi-string. + /** + * A setting that receives multiple values. There are two modes + * - choosing: the setting has a list of allowed chioces. + * - These choices can be positive or negative, for exmample "-option:positive,-negative" + * - If an option is both enabled positively and negatively, the positive wins + * - The choice "_" enables all choices that have not explicitly been disabled + * + * - !choosing: the setting accumulates all arguments. + * + * Arguments can be provided in colonated or non-colonated mode, i.e. "-option a b" or + * "-option:a,b". Note that arguments starting with a "-" can only be provided in colonated mode, + * otherwise they are interpreted as a new option. + * + * In colonated and choosing mode, the setting stops consuming arguments at the first non-choice, + * i.e. "-option a b c" only consumes "a" and "b" if "c" is not a valid choice. + * + * @param name command-line setting name, eg "-Xlint" + * @param arg description of the kind of arguments that need to be passed, eg "warning" + * @param descr description of the setting + * @param choices a list of allowed arguments. if empty, accepts any argument that doesn't start with "-" + * @param descriptions a description for each choice (for the help message), may be empty if no descriptions are necessary + * @param default default arguments, if none are provided */ class MultiChoiceSetting private[nsc]( name: String, arg: String, descr: String, override val choices: List[String], - val default: Option[() => Unit], - helper: MultiChoiceSetting => String + val descriptions: List[String], + val default: Option[List[String]] ) extends MultiStringSetting(name, s"_,$arg,-$arg", s"$descr: `_' for all, `$name:help' to list") { private def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'") - private def choosing = choices.nonEmpty + private def choosing = choices.nonEmpty // choices are known, error on invalid args private def isChoice(s: String) = (s == "_") || (choices contains (s stripPrefix "-")) private var sawHelp = false private var sawAll = false - private val adderAll = () => sawAll = true - private val noargs = () => errorFn(s"'$name' requires an option. See '$name:help'.") + + private def pos(s: String) = s stripPrefix "-" + + /** + * This override takes care of including all possible choices in case the "_" argument was + * passed. It adds the choices that have not explicitly been enabled or disabled. This ensures + * that "this contains x" is consistent with "this.value contains x". + * + * The explicitly enabled / disabled options are stored in the underlying value [[v]], disabled + * ones are stored as "-arg". + * + * The fact that value and v are not the same leaks in some cases. For example, you should never + * use "value += arg", because that expands to "value = value + arg". In case sawAll is true, + * this would propagate all choices enabled by sawAll into the underlying v. + * + * Instead of "value += arg", you should use "this.add(arg)". I haven't found a good way to + * enforce that. + */ + override def value: List[String] = { + if (!sawAll) v + else { + // add only those choices which have not explicitly been enabled or disabled. + val fromAll = choices.filterNot(c => v.exists(pos(_) == c)) + v ++ fromAll + } + } + + /** + * Add an argument to the list of values. + */ + def add(arg: String) = { + if (choosing && !isChoice(arg)) badChoice(arg, name) + if (arg == "_") { + sawAll = true + value = v // the value_= setter has side effects, make sure to execute them. + } else { + val posArg = pos(arg) + if (arg == posArg) { + // positive overrides existing negative. so we filter existing (pos or neg), and add the arg + value = v.filterNot(pos(_) == posArg) :+ arg + } else { + // negative arg is only added if the arg doesn't exist yet (pos or neg) + if (!v.exists(pos(_) == posArg)) value = v :+ arg // not value += arg, see doc of the "value" getter + } + } + } override protected def tts(args: List[String], halting: Boolean) = { val added = collection.mutable.ListBuffer.empty[String] + def tryArg(arg: String) = arg match { - case "_" if choosing => addAll() case "help" if choosing => sawHelp = true - case s if !choosing || isChoice(s) => added += s + case s if !choosing || isChoice(s) => added += s // this case also adds "_" case s => badChoice(s, name) } + + // if "halting" is true, the args were not specified as , separated after a : + // but space separated after a space. we stop consuming args when seeing + // - an arg starting with a "-", that is a new option + // - if the choices are known (choosing), on the first non-choice def stoppingAt(arg: String) = (arg startsWith "-") || (choosing && !isChoice(arg)) + def loop(args: List[String]): List[String] = args match { case arg :: _ if halting && stoppingAt(arg) => args case arg :: rest => tryArg(arg) ; loop(rest) case Nil => Nil } + val rest = loop(args) - if (rest.size == args.size) - (default getOrElse noargs)() // if no arg consumed, trigger default action or error - else - value ++= added.toList // update all new settings at once + if (rest.size == args.size) default match { // if no arg consumed, use defaults or error + case Some(defaults) => defaults foreach add + case None => errorFn(s"'$name' requires an option. See '$name:help'.") + } else { + added.toList foreach add + } + Some(rest) } def isHelping: Boolean = sawHelp - def help: String = helper(this) - def addAll(): Unit = (default getOrElse adderAll)() - // the semantics is: s is enabled, i.e., either s or (_ but not -s) - override def contains(s: String) = isChoice(s) && (value contains s) || (sawAll && !(value contains s"-$s")) + def help: String = { + val choiceLength = choices.map(_.length).max + 1 + val formatStr = s" %-${choiceLength}s %s" + choices.zipAll(descriptions, "", "").map { + case (arg, descr) => formatStr.format(arg, descr) + } mkString (f"$descr%n", f"%n", "") + } } /** A setting that accumulates all strings supplied to it, diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 8e69598614..1609aa5ff7 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -84,13 +84,9 @@ trait ScalaSettings extends AbsScalaSettings name = "-language", helpArg = "feature", descr = description, - choices = features map (_._1) - ) { s => - val helpline: ((String, String)) => String = { - case (name, text) => f" $name%-25s $text%n" - } - features map helpline mkString (f"$description:%n", "", f"%n") - } + choices = features map (_._1), + descriptions = features map (_._2) + ) } /* @@ -193,7 +189,6 @@ trait ScalaSettings extends AbsScalaSettings val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "") val Ygenasmp = StringSetting ("-Ygen-asmp", "dir", "Generate a parallel output directory of .asmp files (ie ASM Textifier output).", "") val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "") - val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (scala.reflect.internal.util.Statistics.enabled = _) val stopAfter = PhasesSetting ("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat val stopBefore = PhasesSetting ("-Ystop-before", "Stop before") val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.") @@ -217,6 +212,20 @@ trait ScalaSettings extends AbsScalaSettings private def removalIn212 = "This flag is scheduled for removal in 2.12. If you have a case where you need this flag then please report a bug." + val YstatisticsPhases = { + val phases = List("parser", "typer", "patmat", "erasure", "cleanup") + val description = "Print compiler statistics for specific phases" + MultiChoiceSetting( + name = "-Ystatistics", + helpArg = "phase", + descr = description, + choices = phases, + descriptions = Nil, + default = Some(List("_"))) withPostSetHook { _ => scala.reflect.internal.util.Statistics.enabled = true } + } + + def YstatisticsEnabled = YstatisticsPhases.value.nonEmpty + /** Area-specific debug output. */ val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.") diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 4c37633301..771543ec77 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -17,145 +17,93 @@ trait Warnings { // Warning semantics. val fatalWarnings = BooleanSetting("-Xfatal-warnings", "Fail the compilation if there are any warnings.") - // These additional warnings are all so noisy as to be useless in their - // present form, but have the potential to offer useful info. - protected def allWarnings = lintWarnings ++ List( - warnDeadCode, - warnValueDiscard, - warnNumericWiden, - warnUnused, // SI-7712, SI-7707 warnUnused not quite ready for prime-time - warnUnusedImport, // currently considered too noisy for general use - warnValueOverrides // currently turned off as experimental - ) - // These warnings should be pretty quiet unless you're doing - // something inadvisable. - protected def lintWarnings = List( - warnInaccessible, - warnNullaryOverride, - warnNullaryUnit, - warnAdaptedArgs, - warnInferAny, - warnMissingInterpolator, - warnDocDetached, - warnPrivateShadow, - warnTypeParameterShadow, - warnPolyImplicitOverload, - warnOptionImplicit, - warnDelayedInit, - warnByNameRightAssociative, - warnPackageObjectClasses, - warnUnsoundMatch - ) - - // Individual warnings. They can be set with -Ywarn. - private def nonlintflag(name: String, text: String): BooleanSetting = BooleanSetting(name, text) - - val warnDeadCode = nonlintflag("-Ywarn-dead-code", - "Warn when dead code is identified.") - val warnValueDiscard = nonlintflag("-Ywarn-value-discard", - "Warn when non-Unit expression results are unused.") - val warnNumericWiden = nonlintflag("-Ywarn-numeric-widen", - "Warn when numerics are widened.") - val warnUnused = nonlintflag("-Ywarn-unused", - "Warn when local and private vals, vars, defs, and types are are unused") - val warnUnusedImport = nonlintflag("-Ywarn-unused-import", - "Warn when imports are unused") - - // Lint warnings that have no -Y avatar, created with new instead of the autoregistering factory method. - // They evaluate true if set to true or else are unset but -Xlint is true - private def lintflag(name: String, text: String): BooleanSetting = - new BooleanSetting(name, text) { - override def value = if (isSetByUser) super.value else xlint - } + // Non-lint warnings - val warnAdaptedArgs = lintflag("adapted-args", - "Warn if an argument list is modified to match the receiver.") - val warnNullaryUnit = lintflag("nullary-unit", - "Warn when nullary methods return Unit.") - val warnInaccessible = lintflag("inaccessible", - "Warn about inaccessible types in method signatures.") - val warnNullaryOverride = lintflag("nullary-override", - "Warn when non-nullary `def f()' overrides nullary `def f'.") - val warnInferAny = lintflag("infer-any", - "Warn when a type argument is inferred to be `Any`.") - val warnMissingInterpolator = lintflag("missing-interpolator", - "A string literal appears to be missing an interpolator id.") - val warnDocDetached = lintflag("doc-detached", - "A ScalaDoc comment appears to be detached from its element.") - val warnPrivateShadow = lintflag("private-shadow", - "A private field (or class parameter) shadows a superclass field.") - val warnTypeParameterShadow = lintflag("type-parameter-shadow", - "A local type parameter shadows a type already in scope.") - val warnPolyImplicitOverload = lintflag("poly-implicit-overload", - "Parameterized overloaded implicit methods are not visible as view bounds") - val warnOptionImplicit = lintflag("option-implicit", - "Option.apply used implicit view.") - val warnDelayedInit = lintflag("delayedinit-select", - "Selecting member of DelayedInit") - val warnByNameRightAssociative = lintflag("by-name-right-associative", - "By-name parameter of right associative operator") - val warnPackageObjectClasses = lintflag("package-object-classes", - "Class or object defined in package object") - val warnUnsoundMatch = lintflag("unsound-match", - "Pattern match may not be typesafe") + val warnDeadCode = BooleanSetting("-Ywarn-dead-code", "Warn when dead code is identified.") + val warnValueDiscard = BooleanSetting("-Ywarn-value-discard", "Warn when non-Unit expression results are unused.") + val warnNumericWiden = BooleanSetting("-Ywarn-numeric-widen", "Warn when numerics are widened.") + // SI-7712, SI-7707 warnUnused not quite ready for prime-time + val warnUnused = BooleanSetting("-Ywarn-unused", "Warn when local and private vals, vars, defs, and types are are unused.") + // currently considered too noisy for general use + val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.") // Experimental lint warnings that are turned off, but which could be turned on programmatically. // These warnings are said to blind those who dare enable them. // They are not activated by -Xlint and can't be enabled on the command line. - val warnValueOverrides = { - val flag = lintflag("value-overrides", "Generated value class method overrides an implementation") + val warnValueOverrides = { // currently turned off as experimental. creaded using constructor (new BS), so not available on the command line. + val flag = new BooleanSetting("value-overrides", "Generated value class method overrides an implementation") flag.value = false flag } - // The Xlint warning group. - private val xlint = new BooleanSetting("-Zunused", "True if -Xlint or -Xlint:_") - // On -Xlint or -Xlint:_, set xlint, otherwise set the lint warning unless already set true - val lint = { - val description = "Enable or disable specific warnings" - val choices = (lintWarnings map (_.name)).sorted - MultiChoiceSetting( - name = "-Xlint", - helpArg = "warning", - descr = description, - choices = choices, - default = Some(() => xlint.value = true) - ) { s => - def helpline(n: String) = lintWarnings.find(_.name == n).map(w => f" ${w.name}%-25s ${w.helpDescription}%n") - choices flatMap (helpline(_)) mkString (f"$description:%n", "", f"%n") - } withPostSetHook { x => - val Neg = "-" - def setPolitely(b: BooleanSetting, v: Boolean) = if (!b.isSetByUser || !b) b.value = v - def set(w: String, v: Boolean) = lintWarnings find (_.name == w) foreach (setPolitely(_, v)) - def propagate(ss: List[String]): Unit = ss match { - case w :: rest => if (w startsWith Neg) set(w stripPrefix Neg, false) else set(w, true) ; propagate(rest) - case Nil => () - } - propagate(x.value) - } - } + // Lint warnings + + def warnAdaptedArgs = lint contains "adapted-args" + def warnNullaryUnit = lint contains "nullary-unit" + def warnInaccessible = lint contains "inaccessible" + def warnNullaryOverride = lint contains "nullary-override" + def warnInferAny = lint contains "infer-any" + def warnMissingInterpolator = lint contains "missing-interpolator" + def warnDocDetached = lint contains "doc-detached" + def warnPrivateShadow = lint contains "private-shadow" + def warnTypeParameterShadow = lint contains "type-parameter-shadow" + def warnPolyImplicitOverload = lint contains "poly-implicit-overload" + def warnOptionImplicit = lint contains "option-implicit" + def warnDelayedInit = lint contains "delayedinit-select" + def warnByNameRightAssociative = lint contains "by-name-right-associative" + def warnPackageObjectClasses = lint contains "package-object-classes" + def warnUnsoundMatch = lint contains "unsound-match" // Lint warnings that are currently -Y, but deprecated in that usage @deprecated("Use warnAdaptedArgs", since="2.11.2") - val YwarnAdaptedArgs = BooleanSetting("-Ywarn-adapted-args", - "Warn if an argument list is modified to match the receiver.") enabling List(warnAdaptedArgs) - //withDeprecationMessage "Enable -Xlint:adapted-args" + def YwarnAdaptedArgs = warnAdaptedArgs @deprecated("Use warnNullaryUnit", since="2.11.2") - val YwarnNullaryUnit = BooleanSetting("-Ywarn-nullary-unit", - "Warn when nullary methods return Unit.") enabling List(warnNullaryUnit) - //withDeprecationMessage "Enable -Xlint:nullary-unit" + def YwarnNullaryUnit = warnNullaryUnit @deprecated("Use warnInaccessible", since="2.11.2") - val YwarnInaccessible = BooleanSetting("-Ywarn-inaccessible", - "Warn about inaccessible types in method signatures.") enabling List(warnInaccessible) - //withDeprecationMessage "Enable -Xlint:inaccessible" + def YwarnInaccessible = warnInaccessible @deprecated("Use warnNullaryOverride", since="2.11.2") - val YwarnNullaryOverride = BooleanSetting("-Ywarn-nullary-override", - "Warn when non-nullary `def f()' overrides nullary `def f'.") enabling List(warnNullaryOverride) - //withDeprecationMessage "Enable -Xlint:nullary-override" + def YwarnNullaryOverride = warnNullaryOverride @deprecated("Use warnInferAny", since="2.11.2") - val YwarnInferAny = BooleanSetting("-Ywarn-infer-any", - "Warn when a type argument is inferred to be `Any`.") enabling List(warnInferAny) - //withDeprecationMessage "Enable -Xlint:infer-any" + def YwarnInferAny = warnInferAny + + // The Xlint warning group. + val lint: MultiChoiceSetting = { + val description = "Enable or disable specific warnings" + + val choices = List( + ("adapted-args", "Warn if an argument list is modified to match the receiver.", true), + ("nullary-unit", "Warn when nullary methods return Unit.", true), + ("inaccessible", "Warn about inaccessible types in method signatures.", true), + ("nullary-override", "Warn when non-nullary `def f()' overrides nullary `def f'.", true), + ("infer-any", "Warn when a type argument is inferred to be `Any`.", true), + ("missing-interpolator", "A string literal appears to be missing an interpolator id.", false), + ("doc-detached", "A ScalaDoc comment appears to be detached from its element.", false), + ("private-shadow", "A private field (or class parameter) shadows a superclass field.", false), + ("type-parameter-shadow", "A local type parameter shadows a type already in scope.", false), + ("poly-implicit-overload", "Parameterized overloaded implicit methods are not visible as view bounds.", false), + ("option-implicit", "Option.apply used implicit view.", false), + ("delayedinit-select", "Selecting member of DelayedInit", false), + ("by-name-right-associative", "By-name parameter of right associative operator.", false), + ("package-object-classes", "Class or object defined in package object.", false), + ("unsound-match", "Pattern match may not be typesafe.", false) + ).sorted + + for (c <- choices.filter(_._3)) { + BooleanSetting("-Ywarn-"+ c._1, c._2) withPostSetHook { s => + if (s) lint.add(c._1) + else lint.add("-" + c._1) + } // withDeprecationMessage s"Enable -Xlint:${c._1}" + } + + MultiChoiceSetting( + name = "-Xlint", + helpArg = "warning", + descr = description, + choices = choices map (_._1), + descriptions = choices map (_._2), + default = Some(List("_")) + ) + } private lazy val warnSelectNullable = BooleanSetting("-Xcheck-null", "This option is obsolete and does nothing.") diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index fb7651ffd6..421021163e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -552,7 +552,7 @@ trait Infer extends Checkable { } case _ => context.tree.pos } - if (settings.warnInferAny.value && context.reportErrors && canWarnAboutAny) { + if (settings.warnInferAny && context.reportErrors && canWarnAboutAny) { foreachWithIndex(targs) ((targ, idx) => targ.typeSymbol match { case sym @ (AnyClass | AnyValClass) => diff --git a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala index 225f6ca68e..a5d579dc37 100644 --- a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala +++ b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala @@ -14,12 +14,10 @@ abstract class StatisticsInfo { import global._ import scala.reflect.internal.TreesStats.nodeByType - val phasesShown = List("parser", "typer", "patmat", "erasure", "cleanup") - val retainedCount = Statistics.newCounter("#retained tree nodes") val retainedByType = Statistics.newByClass("#retained tree nodes by type")(Statistics.newCounter("")) - def print(phase: Phase) = if (phasesShown contains phase.name) { + def print(phase: Phase) = if (settings.YstatisticsPhases contains phase.name) { inform("*** Cumulative statistics at phase " + phase) retainedCount.value = 0 for (c <- retainedByType.keys) diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala index 960d7f8ac1..a0e015be32 100644 --- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala +++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala @@ -39,7 +39,7 @@ class SettingsTest { } // for the given args, select the desired setting - private def check(args: String*)(b: MutableSettings => MutableSettings#BooleanSetting): MutableSettings#BooleanSetting = { + private def check(args: String*)(b: MutableSettings => Boolean): Boolean = { val s = new MutableSettings(msg => throw new IllegalArgumentException(msg)) val (ok, residual) = s.processArguments(args.toList, processAll = true) assert(residual.isEmpty) @@ -54,7 +54,68 @@ class SettingsTest { @Test def anonymousLintersCanBeNamed() { assertTrue(check("-Xlint")(_.warnMissingInterpolator)) // among Xlint assertFalse(check("-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + + // positive overrides negative, but not the other way around + assertTrue(check("-Xlint:-missing-interpolator,missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:-missing-interpolator", "-Xlint:missing-interpolator")(_.warnMissingInterpolator)) + + assertTrue(check("-Xlint:missing-interpolator,-missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:missing-interpolator", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + + // -Xlint:_ adds all possible choices, but explicit negative settings will override + assertFalse(check("-Xlint:-missing-interpolator,_")(_.warnMissingInterpolator)) + assertFalse(check("-Xlint:-missing-interpolator", "-Xlint:_")(_.warnMissingInterpolator)) + assertFalse(check("-Xlint:_", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + assertFalse(check("-Xlint:_,-missing-interpolator")(_.warnMissingInterpolator)) + + // -Xlint is the same as -Xlint:_ assertFalse(check("-Xlint:-missing-interpolator", "-Xlint")(_.warnMissingInterpolator)) assertFalse(check("-Xlint", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + + // combination of positive, negative and _ + assertTrue(check("-Xlint:_,-missing-interpolator,missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:-missing-interpolator,_,missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:-missing-interpolator,missing-interpolator,_")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:missing-interpolator,-missing-interpolator,_")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:missing-interpolator,_,-missing-interpolator")(_.warnMissingInterpolator)) + } + + @Test def xLintInvalidChoices(): Unit = { + assertThrows[IllegalArgumentException](check("-Xlint:-_")(_.warnAdaptedArgs)) + assertThrows[IllegalArgumentException](check("-Xlint:-warn-adapted-args")(_.warnAdaptedArgs)) // "warn-" should not be there + } + + @Test def xLintNonColonated(): Unit = { + assertTrue(check("-Xlint", "adapted-args", "-deprecation")(_.warnAdaptedArgs)) + assertFalse(check("-Xlint", "adapted-args", "-deprecation")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint", "adapted-args", "missing-interpolator", "-deprecation")(s => s.warnMissingInterpolator && s.warnAdaptedArgs)) + assertThrows[IllegalArgumentException](check("-Xlint", "adapted-args", "-missing-interpolator")(_.warnAdaptedArgs)) // non-colonated: cannot provide negative args + } + + @Test def xLintContainsValues(): Unit = { + // make sure that lint.contains and lint.value.contains are consistent + def t(s: MutableSettings, v: String) = { + val r = s.lint.contains(v) + assertSame(r, s.lint.value.contains(v)) + r + } + + assertTrue(check("-Xlint")(t(_, "adapted-args"))) + assertTrue(check("-Xlint:_")(t(_, "adapted-args"))) + assertFalse(check("-Xlint:_,-adapted-args")(t(_, "adapted-args"))) + assertFalse(check("-Xlint:-adapted-args,_")(t(_, "adapted-args"))) + assertTrue(check("-Xlint:-adapted-args,_,adapted-args")(t(_, "adapted-args"))) + } + + @Test def xLintDeprecatedAlias(): Unit = { + assertTrue(check("-Ywarn-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Xlint:_,-adapted-args", "-Ywarn-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Xlint:-adapted-args", "-Ywarn-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Ywarn-adapted-args", "-Xlint:-adapted-args,_")(_.warnAdaptedArgs)) + + assertFalse(check("-Ywarn-adapted-args:false")(_.warnAdaptedArgs)) + assertFalse(check("-Ywarn-adapted-args:false", "-Xlint:_")(_.warnAdaptedArgs)) + assertFalse(check("-Ywarn-adapted-args:false", "-Xlint:_,-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Ywarn-adapted-args:false", "-Xlint:_,adapted-args")(_.warnAdaptedArgs)) } } -- cgit v1.2.3