Skip to content

Commit

Permalink
Implement -Xlint:private-shadow, type-parameter-shadow (#17622)
Browse files Browse the repository at this point in the history
Implemented two additional lint warnings for my bachelor project
supervised by @anatoliykmetyuk.

Most of the work has been done in a new `MiniPhase` class called
`CheckShadowing` and running in the same mega phase as the
`CheckUnused.PostTyper` mini phase.

They respectively warn about :
- A private field or a class parameter that shadows a super-class field.
- A type parameter that shadows a type already defined in the scope.

Some examples can be seen in #17612 and #17613.
  • Loading branch information
szymon-rd committed Sep 29, 2023
2 parents 090710a + 0f4f7bf commit 6c37729
Show file tree
Hide file tree
Showing 18 changed files with 672 additions and 10 deletions.
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class Compiler {
protected def frontendPhases: List[List[Phase]] =
List(new Parser) :: // Compiler frontend: scanner, parser
List(new TyperPhase) :: // Compiler frontend: namer, typer
List(new CheckUnused.PostTyper) :: // Check for unused elements
List(new CheckUnused.PostTyper) :: // Check for unused elements
List(new CheckShadowing) :: // Check shadowing elements
List(new YCheckPositions) :: // YCheck positions
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks
List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files
Expand Down
23 changes: 22 additions & 1 deletion compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import dotty.tools.dotc.config.SourceVersion
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.rewrites.Rewrites
import dotty.tools.io.{AbstractFile, Directory, JDK9Reflectors, PlainDirectory}
import Setting.ChoiceWithHelp

import scala.util.chaining._

Expand Down Expand Up @@ -156,7 +157,6 @@ private sealed trait VerboseSettings:
*/
private sealed trait WarningSettings:
self: SettingGroup =>
import Setting.ChoiceWithHelp

val Whelp: Setting[Boolean] = BooleanSetting("-W", "Print a synopsis of warning options.")
val XfatalWarnings: Setting[Boolean] = BooleanSetting("-Werror", "Fail the compilation if there are any warnings.", aliases = List("-Xfatal-warnings"))
Expand Down Expand Up @@ -307,6 +307,27 @@ private sealed trait XSettings:
}

val XmacroSettings: Setting[List[String]] = MultiStringSetting("-Xmacro-settings", "setting1,setting2,..settingN", "List of settings which exposed to the macros")

val Xlint: Setting[List[ChoiceWithHelp[String]]] = UncompleteMultiChoiceHelpSetting(
name = "-Xlint",
helpArg = "advanced warning",
descr = "Enable or disable specific `lint` warnings",
choices = List(
ChoiceWithHelp("all", ""),
ChoiceWithHelp("private-shadow", "Warn if a private field or class parameter shadows a superclass field"),
ChoiceWithHelp("type-parameter-shadow", "Warn when a type parameter shadows a type already in the scope"),
),
default = Nil
)

object XlintHas:
def allOr(s: String)(using Context) =
Xlint.value.pipe(us => us.contains("all") || us.contains(s))
def privateShadow(using Context) =
allOr("private-shadow")
def typeParameterShadow(using Context) =
allOr("type-parameter-shadow")

end XSettings

/** -Y "Forking" as in forked tongue or "Private" settings */
Expand Down
16 changes: 14 additions & 2 deletions compiler/src/dotty/tools/dotc/config/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ object Settings:
prefix: String = "",
aliases: List[String] = Nil,
depends: List[(Setting[?], Any)] = Nil,
ignoreInvalidArgs: Boolean = false,
propertyClass: Option[Class[?]] = None)(private[Settings] val idx: Int) {

private var changed: Boolean = false
Expand Down Expand Up @@ -104,8 +105,16 @@ object Settings:
def fail(msg: String, args: List[String]) =
ArgsSummary(sstate, args, errors :+ msg, warnings)

def warn(msg: String, args: List[String]) =
ArgsSummary(sstate, args, errors, warnings :+ msg)

def missingArg =
fail(s"missing argument for option $name", args)
val msg = s"missing argument for option $name"
if ignoreInvalidArgs then warn(msg + ", the tag was ignored", args) else fail(msg, args)

def invalidChoices(invalid: List[String]) =
val msg = s"invalid choice(s) for $name: ${invalid.mkString(",")}"
if ignoreInvalidArgs then warn(msg + ", the tag was ignored", args) else fail(msg, args)

def setBoolean(argValue: String, args: List[String]) =
if argValue.equalsIgnoreCase("true") || argValue.isEmpty then update(true, args)
Expand Down Expand Up @@ -144,7 +153,7 @@ object Settings:
choices match
case Some(valid) => strings.filterNot(valid.contains) match
case Nil => update(strings, args)
case invalid => fail(s"invalid choice(s) for $name: ${invalid.mkString(",")}", args)
case invalid => invalidChoices(invalid)
case _ => update(strings, args)
case (StringTag, _) if argRest.nonEmpty || choices.exists(_.contains("")) =>
setString(argRest, args)
Expand Down Expand Up @@ -287,6 +296,9 @@ object Settings:
def MultiChoiceHelpSetting(name: String, helpArg: String, descr: String, choices: List[ChoiceWithHelp[String]], default: List[ChoiceWithHelp[String]], aliases: List[String] = Nil): Setting[List[ChoiceWithHelp[String]]] =
publish(Setting(name, descr, default, helpArg, Some(choices), aliases = aliases))

def UncompleteMultiChoiceHelpSetting(name: String, helpArg: String, descr: String, choices: List[ChoiceWithHelp[String]], default: List[ChoiceWithHelp[String]], aliases: List[String] = Nil): Setting[List[ChoiceWithHelp[String]]] =
publish(Setting(name, descr, default, helpArg, Some(choices), aliases = aliases, ignoreInvalidArgs = true))

def IntSetting(name: String, descr: String, default: Int, aliases: List[String] = Nil): Setting[Int] =
publish(Setting(name, descr, default, aliases = aliases))

Expand Down
Loading

0 comments on commit 6c37729

Please sign in to comment.