diff --git a/scalafix-core/shared/src/main/scala/scalafix/config/CustomMessage.scala b/scalafix-core/shared/src/main/scala/scalafix/config/CustomMessage.scala new file mode 100644 index 000000000..fb2373400 --- /dev/null +++ b/scalafix-core/shared/src/main/scala/scalafix/config/CustomMessage.scala @@ -0,0 +1,47 @@ +package scalafix +package config + +import metaconfig.{Conf, ConfError, ConfDecoder, Configured, Metaconfig} +import org.langmeta._ +import scalafix.internal.config.MetaconfigPendingUpstream.XtensionConfScalafix + +import scala.language.implicitConversions + +class CustomMessage[T]( + val value: T, + val message: Option[String], + val id: Option[String]) + +object CustomMessage { + def getOption[T](obj: Conf.Obj, path: String)( + implicit ev: ConfDecoder[T]): Configured[Option[T]] = + Metaconfig + .getKey(obj, Seq(path)) + .map( + value => ev.read(value).map(Some(_)) + ) + .getOrElse(Configured.Ok(None)) + + def decoder[T](field: String)( + implicit ev: ConfDecoder[T]): ConfDecoder[CustomMessage[T]] = + ConfDecoder.instance[CustomMessage[T]] { + case obj: Conf.Obj => { + (obj.get[T](field) |@| + getOption[String](obj, "message") |@| + getOption[String](obj, "id")).map { + case ((value, message0), id) => + val message = + message0.map(msg => + if (msg.isMultiline) { + "\n" + msg.stripMargin + } else { + msg + }) + + new CustomMessage(value, message, id) + } + } + case els => + ev.read(els).map(value => new CustomMessage(value, None, None)) + } +} diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/config/CustomMessage.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/config/CustomMessage.scala deleted file mode 100644 index d7b539022..000000000 --- a/scalafix-core/shared/src/main/scala/scalafix/internal/config/CustomMessage.scala +++ /dev/null @@ -1,31 +0,0 @@ -package scalafix -package internal.config - -import metaconfig.{Conf, ConfError, ConfDecoder, Configured} -import org.langmeta._ -import MetaconfigPendingUpstream.XtensionConfScalafix - -import scala.language.implicitConversions - -case class CustomMessage[T](value: T, message: Option[String]) - -object CustomMessage { - def decoder[T](field: String)( - implicit ev: ConfDecoder[T]): ConfDecoder[CustomMessage[T]] = - ConfDecoder.instance[CustomMessage[T]] { - case obj: Conf.Obj => - (obj.get[T](field) |@| obj.get[String]("message")).map { - case (value, message0) => { - val message = - if (message0.isMultiline) { - "\n" + message0.stripMargin - } else { - message0 - } - CustomMessage(value, Some(message)) - } - } - case els => - ev.read(els).map(value => CustomMessage(value, None)) - } -} diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableConfig.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableConfig.scala index e967143f5..78a8ee34a 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableConfig.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableConfig.scala @@ -1,5 +1,7 @@ package scalafix.internal.config +import scalafix.config.CustomMessage + import metaconfig.ConfDecoder import MetaconfigPendingUpstream.XtensionConfScalafix import org.langmeta.Symbol @@ -8,14 +10,13 @@ import scalafix.internal.util.SymbolOps case class DisableConfig(symbols: List[CustomMessage[Symbol.Global]] = Nil) { def allSymbols = symbols.map(_.value) - private val messageBySymbol: Map[String, String] = + private val messageBySymbol: Map[String, CustomMessage[Symbol.Global]] = symbols - .flatMap(custom => - custom.message.map(message => - (SymbolOps.normalize(custom.value).syntax, message))) + .map(custom => (SymbolOps.normalize(custom.value).syntax, custom)) .toMap - def customMessage(symbol: Symbol.Global): Option[String] = + def customMessage( + symbol: Symbol.Global): Option[CustomMessage[Symbol.Global]] = messageBySymbol.get(SymbolOps.normalize(symbol).syntax) implicit val customMessageReader: ConfDecoder[CustomMessage[Symbol.Global]] = diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableSyntaxConfig.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableSyntaxConfig.scala index c5feb2e28..9b272ce06 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableSyntaxConfig.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/internal/config/DisableSyntaxConfig.scala @@ -1,5 +1,7 @@ package scalafix.internal.config +import scalafix.config.CustomMessage + import metaconfig.{Conf, ConfError, ConfDecoder, Configured} import org.langmeta._ import MetaconfigPendingUpstream.XtensionConfScalafix diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/rule/Disable.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/rule/Disable.scala index 2d4ff8c30..2f0b01524 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/internal/rule/Disable.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/internal/rule/Disable.scala @@ -51,11 +51,18 @@ final case class Disable(index: SemanticdbIndex, config: DisableConfig) case _ => "" -> pos } - val message = config - .customMessage(symbol) + val custom = config.customMessage(symbol) + + val message = custom + .flatMap(_.message) .getOrElse(s"${signature.name} is disabled$details") + + val id = custom + .flatMap(_.id) + .getOrElse(signature.name) + errorCategory - .copy(id = signature.name) + .copy(id = id) .at(message, caret) } } diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/rule/DisableSyntax.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/rule/DisableSyntax.scala index 3893dea69..1714787c9 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/internal/rule/DisableSyntax.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/internal/rule/DisableSyntax.scala @@ -35,7 +35,7 @@ final case class DisableSyntax( while (matcher.find()) { regexLintMessages += errorCategory - .copy(id = pattern) + .copy(id = regex.id.getOrElse(pattern)) .at(message, pos(matcher.start)) } } diff --git a/scalafix-tests/input/src/main/scala/test/Disable.scala b/scalafix-tests/input/src/main/scala/test/Disable.scala index 3adbe6c02..ea6d560cd 100644 --- a/scalafix-tests/input/src/main/scala/test/Disable.scala +++ b/scalafix-tests/input/src/main/scala/test/Disable.scala @@ -5,6 +5,7 @@ Disable.symbols = [ "test.Disable.D.disabledFunction" { symbol = "scala.Option.get" + id = "Option.get" message = """|Option.get is the root of all evils | @@ -47,7 +48,7 @@ case object Disable { def asInstanceOf: O = "test" } val yy = AA.asInstanceOf // OK, no errors - Option(1).get /* assert: Disable.get + Option(1).get /* assert: Disable.Option.get ^ Option.get is the root of all evils diff --git a/scalafix-tests/input/src/main/scala/test/DisableSyntax.scala b/scalafix-tests/input/src/main/scala/test/DisableSyntax.scala index ac7976098..729c23775 100644 --- a/scalafix-tests/input/src/main/scala/test/DisableSyntax.scala +++ b/scalafix-tests/input/src/main/scala/test/DisableSyntax.scala @@ -11,6 +11,7 @@ DisableSyntax.noSemicolons = true DisableSyntax.noXml = true DisableSyntax.regex = [ { + id = offensive pattern = "[P|p]imp" message = "Please consider a less offensive word such as Extension" } @@ -39,7 +40,7 @@ case object DisableSyntax { xml // assert: DisableSyntax.noXml // assert: DisableSyntax.noTabs - implicit class StringPimp(value: String) { // assert: DisableSyntax.[P|p]imp + implicit class StringPimp(value: String) { // assert: DisableSyntax.offensive def -(other: String): String = s"$value - $other" }