Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add resultType extension method on Symbol #381

Merged
merged 3 commits into from
Sep 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion project/Mima.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.*")
)
}
}
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package scalafix.internal.util

import scala.meta._

object DenotationOps {
val defaultDialect =
dialects.Scala212.copy(allowMethodTypes = true, allowTypeLambdas = true)

def resultType(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name is up to debate. resultType is general enough, but it's a bit of a stretch when referring to simple val/var

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result type is the correct nomenclature from scalac 👍

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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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")
}
Original file line number Diff line number Diff line change
@@ -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]")
}
}

}