diff --git a/project/Mima.scala b/project/Mima.scala index ede65e6a2..72513778e 100644 --- a/project/Mima.scala +++ b/project/Mima.scala @@ -4,6 +4,8 @@ object Mima { val ignoredABIProblems: Seq[ProblemFilter] = { // After v0.5, start running mima checks in CI and document breaking changes here. // See https://github.com/typesafehub/migration-manager/wiki/sbt-plugin#basic-usage - Seq() + Seq( + ProblemFilters.exclude[Problem]("scalafix.internal.*") + ) } } diff --git a/project/plugins.sbt b/project/plugins.sbt index fac6e0a44..5e539f28d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -14,6 +14,6 @@ addSbtPlugin( "com.eed3si9n" % "sbt-assembly" % "0.14.5" exclude ("org.apache.maven", "maven-plugin-api")) addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.18") addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.7.0") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.14") +addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.15") libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala index 3662dd84b..b18afa762 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala @@ -66,37 +66,12 @@ case class ExplicitResultTypes( case _: Defn.Var => MemberKind.Var } - private val denotDialect = - dialects.Scala212.copy(allowMethodTypes = true, allowTypeLambdas = true) - - def parseDenotationInfo(symbol: Symbol, denot: Denotation): Option[Type] = { - def getDeclType(tpe: Type): Type = tpe match { - case Type.Method(_, tpe) if denot.isDef => tpe - case Type.Lambda(_, tpe) if denot.isDef => getDeclType(tpe) - case Type.Method((Term.Param(_, _, Some(tpe), _) :: Nil) :: Nil, _) - if denot.isVar => - // Workaround for https://github.com/scalameta/scalameta/issues/1100 - tpe - case x => - x - } - val signature = - if (denot.isVal || denot.isDef | denot.isVar) denot.signature - else { - throw new UnsupportedOperationException( - s"Can't parse type for denotation $denot, denot.info=${denot.signature}") - } - val input = Input.Denotation(signature, symbol) - (denotDialect, input).parse[Type].toOption.map(getDeclType) - } - override def fix(ctx: RuleCtx): Patch = { def defnType(defn: Defn): Option[(Type, Patch)] = for { name <- defnName(defn) symbol <- name.symbol - denot <- symbol.denotation - typ <- parseDenotationInfo(symbol, denot) + typ <- symbol.resultType } yield TypeSyntax.prettify(typ, ctx, config.unsafeShortenNames) import scala.meta._ def fix(defn: Defn, body: Term): Patch = { diff --git a/scalafix-core/shared/src/main/scala/scalafix/internal/util/DenotationOps.scala b/scalafix-core/shared/src/main/scala/scalafix/internal/util/DenotationOps.scala new file mode 100644 index 000000000..b10e04b22 --- /dev/null +++ b/scalafix-core/shared/src/main/scala/scalafix/internal/util/DenotationOps.scala @@ -0,0 +1,32 @@ +package scalafix.internal.util + +import scala.meta._ + +object DenotationOps { + val defaultDialect = + dialects.Scala212.copy(allowMethodTypes = true, allowTypeLambdas = true) + + def resultType( + symbol: Symbol, + denot: Denotation, + dialect: Dialect): Option[Type] = { + def getDeclType(tpe: Type): Type = tpe match { + case Type.Method(_, tpe) if denot.isDef => tpe + case Type.Lambda(_, tpe) if denot.isDef => getDeclType(tpe) + case Type.Method((Term.Param(_, _, Some(tpe), _) :: Nil) :: Nil, _) + if denot.isVar => + // Workaround for https://github.com/scalameta/scalameta/issues/1100 + tpe + case x => + x + } + val signature = + if (denot.isVal || denot.isDef | denot.isVar) denot.signature + else { + throw new UnsupportedOperationException( + s"Can't parse type for denotation $denot, denot.info=${denot.signature}") + } + val input = Input.Denotation(signature, symbol) + (dialect, input).parse[Type].toOption.map(getDeclType) + } +} diff --git a/scalafix-core/shared/src/main/scala/scalafix/syntax/package.scala b/scalafix-core/shared/src/main/scala/scalafix/syntax/package.scala index bde2903da..badcc947d 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/syntax/package.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/syntax/package.scala @@ -8,6 +8,7 @@ import scala.meta.semanticdb.Symbol import scala.compat.Platform.EOL import scala.meta.internal.scalafix.ScalafixScalametaHacks import scalafix.internal.util.SymbolOps +import scalafix.internal.util.DenotationOps import scalafix.util.SymbolMatcher import scalafix.util.TreeOps @@ -30,6 +31,9 @@ package object syntax { @deprecated("Renamed to denotation", "0.5.0") def denotOpt: Option[Denotation] = denotation def denotation: Option[Denotation] = index.denotation(symbol) + def resultType: Option[Type] = + denotation.flatMap(denot => + DenotationOps.resultType(symbol, denot, DenotationOps.defaultDialect)) } implicit class XtensionSymbol(symbol: Symbol) { def normalized: Symbol = SymbolOps.normalize(symbol) diff --git a/scalafix-tests/shared/src/main/scala/test/DenotationOpsTest.scala b/scalafix-tests/shared/src/main/scala/test/DenotationOpsTest.scala new file mode 100644 index 000000000..29e6544f0 --- /dev/null +++ b/scalafix-tests/shared/src/main/scala/test/DenotationOpsTest.scala @@ -0,0 +1,7 @@ +package test + +object DenotationOpsTest { + def m(x: Int, y: String): List[String] = List(y) + var x = true + val y = m(42, "hey") +} diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/DenotationOpsTest.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/DenotationOpsTest.scala new file mode 100644 index 000000000..4ca30f4d3 --- /dev/null +++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/DenotationOpsTest.scala @@ -0,0 +1,33 @@ +package scalafix.tests + +import scala.meta._ +import scala.meta.contrib._ +import scalafix.syntax._ +import scalafix.internal.util.DenotationOps + +class DenotationOpsTest extends BaseSemanticTest("DenotationOpsTest") { + + test("resultType") { + val source = docs.input.parse[Source].get + source.collect { + case t @ Pat.Var(Name("x")) => + for { + symbol <- t.symbol + resultType <- symbol.resultType + } yield assert(resultType isEqual t"Boolean") + + case t @ Pat.Var(Name("y")) => + for { + symbol <- t.symbol + resultType <- symbol.resultType + } yield assert(resultType isEqual t"List[String]") + + case t: Defn.Def if t.name.value == "m" => + for { + symbol <- t.symbol + resultType <- symbol.resultType + } yield assert(resultType isEqual t"List[String]") + } + } + +}