|
| 1 | +package dotty.tools |
| 2 | +package dotc |
| 3 | +package reporting |
| 4 | + |
| 5 | +import dotty.tools.dotc.core.Contexts._ |
| 6 | + |
| 7 | +import java.util.regex.PatternSyntaxException |
| 8 | +import scala.annotation.internal.sharable |
| 9 | +import scala.collection.mutable.ListBuffer |
| 10 | +import scala.util.matching.Regex |
| 11 | + |
| 12 | +enum MessageFilter: |
| 13 | + def matches(message: Diagnostic): Boolean = this match { |
| 14 | + case Any => true |
| 15 | + case Deprecated => message.isInstanceOf[Diagnostic.DeprecationWarning] |
| 16 | + case Feature => message.isInstanceOf[Diagnostic.FeatureWarning] |
| 17 | + case MessagePattern(pattern) => pattern.findFirstIn(message.msg.rawMessage).nonEmpty |
| 18 | + } |
| 19 | + case Any, Deprecated, Feature |
| 20 | + case MessagePattern(pattern: Regex) |
| 21 | + |
| 22 | +enum Action: |
| 23 | + case Error, Warning, Info, Silent |
| 24 | + |
| 25 | +final case class WConf(confs: List[(List[MessageFilter], Action)]): |
| 26 | + def action(message: Diagnostic): Action = confs.collectFirst { |
| 27 | + case (filters, action) if filters.forall(_.matches(message)) => action |
| 28 | + }.getOrElse(Action.Warning) |
| 29 | + |
| 30 | +@sharable object WConf: |
| 31 | + import Action._ |
| 32 | + import MessageFilter._ |
| 33 | + |
| 34 | + private type Conf = (List[MessageFilter], Action) |
| 35 | + |
| 36 | + def parseAction(s: String): Either[List[String], Action] = s match { |
| 37 | + case "error" | "e" => Right(Error) |
| 38 | + case "warning" | "w" => Right(Warning) |
| 39 | + case "info" | "i" => Right(Info) |
| 40 | + case "silent" | "s" => Right(Silent) |
| 41 | + case _ => Left(List(s"unknown action: `$s`")) |
| 42 | + } |
| 43 | + |
| 44 | + private def regex(s: String) = |
| 45 | + try Right(s.r) |
| 46 | + catch { case e: PatternSyntaxException => Left(s"invalid pattern `$s`: ${e.getMessage}") } |
| 47 | + |
| 48 | + val splitter = raw"([^=]+)=(.+)".r |
| 49 | + |
| 50 | + def parseFilter(s: String): Either[String, MessageFilter] = s match { |
| 51 | + case "any" => Right(Any) |
| 52 | + case splitter(filter, conf) => filter match { |
| 53 | + case "msg" => regex(conf).map(MessagePattern.apply) |
| 54 | + case "cat" => |
| 55 | + conf match { |
| 56 | + case "deprecation" => Right(Deprecated) |
| 57 | + case "feature" => Right(Feature) |
| 58 | + case _ => Left(s"unknown category: $conf") |
| 59 | + } |
| 60 | + case _ => Left(s"unknown filter: $filter") |
| 61 | + } |
| 62 | + case _ => Left(s"unknown filter: $s") |
| 63 | + } |
| 64 | + |
| 65 | + private var parsedCache: (List[String], WConf) = null |
| 66 | + def parsed(using Context): WConf = |
| 67 | + val setting = ctx.settings.Wconf.value |
| 68 | + if parsedCache == null || parsedCache._1 != setting then |
| 69 | + val conf = fromSettings(setting) |
| 70 | + parsedCache = (setting, conf.getOrElse(WConf(Nil))) |
| 71 | + conf.swap.foreach(msgs => |
| 72 | + val multiHelp = |
| 73 | + if (setting.sizeIs > 1) |
| 74 | + """ |
| 75 | + |Note: for multiple filters, use `-Wconf:filter1:action1,filter2:action2` |
| 76 | + | or alternatively `-Wconf:filter1:action1 -Wconf:filter2:action2`""".stripMargin |
| 77 | + else "" |
| 78 | + report.warning(s"Failed to parse `-Wconf` configuration: ${ctx.settings.Wconf.value.mkString(",")}\n${msgs.mkString("\n")}$multiHelp")) |
| 79 | + parsedCache._2 |
| 80 | + |
| 81 | + def fromSettings(settings: List[String]): Either[List[String], WConf] = |
| 82 | + if (settings.isEmpty) Right(WConf(Nil)) |
| 83 | + else { |
| 84 | + val parsedConfs: List[Either[List[String], (List[MessageFilter], Action)]] = settings.map(conf => { |
| 85 | + val parts = conf.split("[&:]") // TODO: don't split on escaped \& |
| 86 | + val (ms, fs) = parts.view.init.map(parseFilter).toList.partitionMap(identity) |
| 87 | + if (ms.nonEmpty) Left(ms) |
| 88 | + else if (fs.isEmpty) Left(List("no filters or no action defined")) |
| 89 | + else parseAction(parts.last).map((fs, _)) |
| 90 | + }) |
| 91 | + val (ms, fs) = parsedConfs.partitionMap(identity) |
| 92 | + if (ms.nonEmpty) Left(ms.flatten) |
| 93 | + else Right(WConf(fs)) |
| 94 | + } |
0 commit comments