Skip to content

Commit 63b349d

Browse files
committed
Indicate deprecated option aliases
1 parent 1416876 commit 63b349d

File tree

3 files changed

+40
-16
lines changed

3 files changed

+40
-16
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ private sealed trait PluginSettings:
146146
private sealed trait VerboseSettings:
147147
self: SettingGroup =>
148148
val Vhelp: Setting[Boolean] = BooleanSetting(VerboseSetting, "V", "Print a synopsis of verbose options.")
149-
val Vprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", aliases = List("-Xprint"))
150-
val XshowPhases: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vphases", "List compiler phases.", aliases = List("-Xshow-phases"))
149+
val Vprint: Setting[List[String]] = PhasesSetting(VerboseSetting, "Vprint", "Print out program after", aliases = List("-Xprint*"))
150+
val XshowPhases: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vphases", "List compiler phases.", aliases = List("-Xshow-phases*"))
151151

152152
val Vprofile: Setting[Boolean] = BooleanSetting(VerboseSetting, "Vprofile", "Show metrics about sources and internal representations to estimate compile-time complexity.")
153153
val VprofileSortedBy = ChoiceSetting(VerboseSetting, "Vprofile-sorted-by", "key", "Show metrics about sources and internal representations sorted by given column name", List("name", "path", "lines", "tokens", "tasty", "complexity"), "")
@@ -161,7 +161,7 @@ private sealed trait WarningSettings:
161161
self: SettingGroup =>
162162

163163
val Whelp: Setting[Boolean] = BooleanSetting(WarningSetting, "W", "Print a synopsis of warning options.")
164-
val Werror: Setting[Boolean] = BooleanSetting(WarningSetting, "Werror", "Fail the compilation if there are any warnings.", aliases = List("-Xfatal-warnings"))
164+
val Werror: Setting[Boolean] = BooleanSetting(WarningSetting, "Werror", "Fail the compilation if there are any warnings.", aliases = List("-Xfatal-warnings*"))
165165
val Wall: Setting[Boolean] = BooleanSetting(WarningSetting, "Wall", "Enable all warning settings.")
166166
private val WvalueDiscard: Setting[Boolean] = BooleanSetting(WarningSetting, "Wvalue-discard", "Warn when non-Unit expression results are unused.")
167167
private val WNonUnitStatement = BooleanSetting(WarningSetting, "Wnonunit-statement", "Warn when block statements are non-Unit expressions.")

compiler/src/dotty/tools/dotc/config/Settings.scala

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ object Settings:
111111
// accept legacy choices (for example, valid in Scala 2 but no longer supported)
112112
legacyChoices: Option[Seq[?]] = None)(private[Settings] val idx: Int)(using ct: ClassTag[T]):
113113

114+
val alternatives = aliases.map(_.stripSuffix("*"))
114115
validateSettingString(prefix.getOrElse(name))
115-
aliases.foreach(validateSettingString)
116+
alternatives.foreach(validateSettingString)
116117
assert(name.startsWith(s"-${category.prefixLetter}"), s"Setting $name does not start with category -$category")
117118
assert(legacyArgs || !choices.exists(_.contains("")), s"Empty string is not supported as a choice for setting $name")
118119
validateSettingTag(ct)
@@ -121,7 +122,7 @@ object Settings:
121122
// Example: -opt Main.scala would be interpreted as -opt:Main.scala, and the source file would be ignored.
122123
assert(!(ct == ListTag && ignoreInvalidArgs), s"Ignoring invalid args is not supported for multivalue settings: $name")
123124

124-
val allFullNames: List[String] = s"$name" :: s"-$name" :: aliases
125+
val allFullNames: List[String] = s"$name" :: s"-$name" :: alternatives
125126

126127
def valueIn(state: SettingsState): T = state.value(idx).asInstanceOf[T]
127128

@@ -143,8 +144,9 @@ object Settings:
143144
case None => ""
144145

145146
// Updates the state from the next arg if this setting is applicable.
146-
def tryToSet(state: ArgsSummary): ArgsSummary =
147-
val ArgsSummary(sstate, arg :: args, _, _) = state: @unchecked
147+
def tryToSet(state0: ArgsSummary): ArgsSummary =
148+
val ArgsSummary(sstate, arg :: args, _, _) = state0: @unchecked
149+
def state(using ArgsSummary) = summon[ArgsSummary]
148150
def changed = sstate.wasChanged(idx)
149151

150152
/** Updates the value in state.
@@ -154,7 +156,7 @@ object Settings:
154156
* @param args remaining arguments to process
155157
* @return updated argument state
156158
*/
157-
def update(value: => Any, altArg: String, args: List[String]): ArgsSummary =
159+
def update(value: => Any, altArg: String, args: List[String])(using ArgsSummary): ArgsSummary =
158160
deprecation match
159161
case Some(Deprecation(msg, Some(replacedBy))) =>
160162
val deprecatedMsg = s"Option $name is deprecated: $msg"
@@ -169,7 +171,7 @@ object Settings:
169171
state.updated(updateIn(sstate, value), args)
170172
end update
171173

172-
def setBoolean(argValue: String, args: List[String]) =
174+
def setBoolean(argValue: String, args: List[String])(using ArgsSummary) =
173175
def checkAndSet(v: Boolean) =
174176
val dubious = changed && v != valueIn(sstate).asInstanceOf[Boolean]
175177
if dubious then
@@ -183,7 +185,7 @@ object Settings:
183185
else if argValue.equalsIgnoreCase("false") then checkAndSet(false)
184186
else state.fail(s"$argValue is not a valid choice for Boolean flag $name", args)
185187

186-
def setString(argValue: String, args: List[String]) =
188+
def setString(argValue: String, args: List[String])(using ArgsSummary) =
187189
choices match
188190
case Some(choices) if !choices.contains(argValue) =>
189191
state.fail(s"$argValue is not a valid choice for $name", args)
@@ -193,7 +195,7 @@ object Settings:
193195
else
194196
update(argValue, argValue, args)
195197

196-
def setInt(argValue: String, args: List[String]) =
198+
def setInt(argValue: String, args: List[String])(using ArgsSummary) =
197199
argValue.toIntOption.map: intValue =>
198200
choices match
199201
case Some(r: Range) if intValue < r.head || r.last < intValue =>
@@ -207,7 +209,7 @@ object Settings:
207209
.getOrElse:
208210
state.fail(s"$argValue is not an integer argument for $name", args)
209211

210-
def setOutput(arg: String, args: List[String]) =
212+
def setOutput(arg: String, args: List[String])(using ArgsSummary) =
211213
val path = Directory(arg)
212214
val isJar = path.ext.isJar
213215
if (!isJar && !path.isDirectory) then
@@ -221,7 +223,7 @@ object Settings:
221223

222224
// argRest is the remainder of -foo:bar if any. This setting will receive a value from argRest or args.head.
223225
// useArg means use argRest even if empty.
224-
def doSet(argRest: String, useArg: Boolean): ArgsSummary =
226+
def doSet(argRest: String, useArg: Boolean)(using ArgsSummary): ArgsSummary =
225227
def missingArg =
226228
val msg = s"missing argument for option $name"
227229
if ignoreInvalidArgs then state.warn(s"$msg, the tag was ignored", args) else state.fail(msg, args)
@@ -248,12 +250,12 @@ object Settings:
248250
doSet(arg1, args1)
249251
end doSet
250252

251-
def setVersion(arg: String, args: List[String]) =
253+
def setVersion(arg: String, args: List[String])(using ArgsSummary) =
252254
ScalaVersion.parse(arg) match
253255
case Success(v) => update(v, arg, args)
254256
case Failure(e) => state.fail(e.getMessage, args)
255257

256-
def setMultivalue(arg: String, args: List[String]) =
258+
def setMultivalue(arg: String, args: List[String])(using ArgsSummary) =
257259
val split = arg.split(",").toList
258260
def setOrUpdate(actual: List[String]) =
259261
val updated =
@@ -285,7 +287,22 @@ object Settings:
285287
val name = arg.takeWhile(_ != ':')
286288
allFullNames.exists(_ == name) || prefix.exists(arg.startsWith)
287289

290+
def checkDeprecatedAlias()(using ArgsSummary) =
291+
val name = arg.takeWhile(_ != ':')
292+
val found =
293+
for
294+
alt <- alternatives.find(_ == name)
295+
altx = alt + "*"
296+
_ <- aliases.find(_ == altx)
297+
yield
298+
alt
299+
found.map: alt =>
300+
state.warn(s"Option $alt is a deprecated alias: use ${this.name}", args)
301+
.getOrElse(state)
302+
288303
if matches then
304+
val checked = checkDeprecatedAlias()(using state0)
305+
given ArgsSummary = checked
289306
deprecation match
290307
case Some(Deprecation(msg, _)) if ignoreInvalidArgs => // a special case for Xlint
291308
state.warn(s"Option $name is deprecated: $msg", args)
@@ -300,7 +317,7 @@ object Settings:
300317
doSet("", useArg = false)
301318
else
302319
doSet(split(1), useArg = true)
303-
else state
320+
else state0
304321

305322
end tryToSet
306323
end Setting

compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,11 @@ class ScalaSettingsTests:
306306
assertEquals(0, result.warnings.length)
307307
assertEquals(1, result.errors.length)
308308

309+
@Test def `deprecated aliases warn`: Unit =
310+
val settings = ScalaSettings
311+
val args = "-Xfatal-warnings" :: "-Xprint" :: "typer" :: Nil
312+
val result = settings.processArguments(args, processAll = true)
313+
assertEquals(2, result.warnings.length)
314+
assertEquals(0, result.errors.length)
315+
309316
end ScalaSettingsTests

0 commit comments

Comments
 (0)