Skip to content

Commit

Permalink
Merge pull request #26 from olafurpg/integrations
Browse files Browse the repository at this point in the history
Improve semantic rewrite infrastructure
  • Loading branch information
olafurpg authored Dec 8, 2016
2 parents 745c7b0 + 9336a1c commit 4ab8e0e
Show file tree
Hide file tree
Showing 27 changed files with 677 additions and 168 deletions.
2 changes: 1 addition & 1 deletion .drone.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
build:
image: olafurpg/sbt:0.0.1
image: danieletorelli/sbt
environment:
- COURSIER_CACHE=/drone/cache/coursier
commands:
Expand Down
3 changes: 2 additions & 1 deletion bin/testAll.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/bin/bash
set -e
sbt clean test publishLocal scripted
export SBT_OPTS="-Xmx24G -XX:MaxPermSize=4G -Xss4M"
sbt clean test scripted
29 changes: 28 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ lazy val root = project
)
.aggregate(
`scalafix-nsc`,
`scalafix-tests`,
core,
cli,
readme,
Expand Down Expand Up @@ -114,7 +115,7 @@ lazy val `scalafix-nsc` = project
scalaVersion := "2.11.8",
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value,
"org.scalameta" %% "scalameta" % Build.metaV,
"org.scalameta" %% "scalameta" % Build.metaV % "provided",
"org.scalatest" %% "scalatest" % Build.testV % Test
),
// sbt does not fetch transitive dependencies of compiler plugins.
Expand Down Expand Up @@ -169,11 +170,18 @@ lazy val cli = project
)
.dependsOn(core % "compile->compile;test->test")

lazy val publishedArtifacts = Seq(
publishLocal in `scalafix-nsc`,
publishLocal in core
)

lazy val `scalafix-sbt` = project.settings(
allSettings,
ScriptedPlugin.scriptedSettings,
sbtPlugin := true,
scripted := scripted.dependsOn(publishedArtifacts: _*).evaluated,
scalaVersion := "2.10.5",
moduleName := "sbt-scalafix",
sources in Compile +=
baseDirectory.value / "../core/src/main/scala/scalafix/Versions.scala",
scriptedLaunchOpts := Seq(
Expand All @@ -186,6 +194,25 @@ lazy val `scalafix-sbt` = project.settings(
scriptedBufferLog := false
)

lazy val `scalafix-tests` = project
.settings(
allSettings,
noPublish,
parallelExecution in Test := true,
compileInputs in (Compile, compile) :=
(compileInputs in (Compile, compile))
.dependsOn(
(publishLocal in `scalafix-sbt`) +:
publishedArtifacts: _*
)
.value,
libraryDependencies ++= Seq(
"com.lihaoyi" %% "ammonite-ops" % "0.8.0",
"org.scalatest" %% "scalatest" % Build.testV % "test"
)
)
.dependsOn(core)

lazy val readme = scalatex
.ScalatexReadme(projectId = "readme",
wd = file(""),
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/scalafix/Scalafix.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import scalafix.rewrite.RewriteCtx
import scalafix.rewrite.SemanticApi
import scalafix.util.Patch
import scalafix.util.TokenList
import scalafix.util.logger

object Scalafix {
def fix(code: Input,
Expand Down
22 changes: 21 additions & 1 deletion core/src/main/scala/scalafix/ScalafixConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,27 @@ import scala.meta.parsers.Parse
import scalafix.rewrite.Rewrite

case class ScalafixConfig(
rewrites: Seq[Rewrite] = Rewrite.syntaxRewrites,
rewrites: Seq[Rewrite] = Rewrite.allRewrites,
parser: Parse[_ <: Tree] = Parse.parseSource,
dialect: Dialect = Scala211
)

object ScalafixConfig {
def fromNames(names: List[String]): Either[String, ScalafixConfig] = {
names match {
case "all" :: Nil =>
Right(ScalafixConfig(rewrites = Rewrite.allRewrites))
case _ =>
val invalidNames =
names.filterNot(Rewrite.name2rewrite.contains)
if (invalidNames.nonEmpty) {
Left(
s"Invalid rewrite rule: ${invalidNames.mkString(",")}. " +
s"Valid rules are: ${Rewrite.name2rewrite.keys.mkString(",")}")
} else {
val rewrites = names.map(Rewrite.name2rewrite)
Right(ScalafixConfig(rewrites = rewrites))
}
}
}
}
2 changes: 1 addition & 1 deletion core/src/main/scala/scalafix/Versions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ package scalafix

object Versions {
val nightly = "0.2.0-SNAPSHOT"
val stable = nightly
val stable: String = nightly
val scala = "2.11.8"
}
11 changes: 10 additions & 1 deletion core/src/main/scala/scalafix/rewrite/ExplicitImplicit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import scalafix.util.Patch
import scalafix.util.Whitespace

case object ExplicitImplicit extends Rewrite {
// Don't explicitly annotate vals when the right-hand body is a single call
// to `implicitly`. Prevents ambiguous implicit. Not annotating in such cases,
// this a common trick employed implicit-heavy code to workaround SI-2712.
// Context: https://gitter.im/typelevel/cats?at=584573151eb3d648695b4a50
private def isImplicitly(term: m.Term): Boolean = term match {
case m.Term.ApplyType(m.Term.Name("implicitly"), _) => true
case _ => false
}
override def rewrite(ast: m.Tree, ctx: RewriteCtx): Seq[Patch] = {
import scala.meta._
val semantic = getSemanticApi(ctx)
Expand All @@ -23,7 +31,8 @@ case object ExplicitImplicit extends Rewrite {
}.toSeq
ast.collect {
case t @ m.Defn.Val(mods, _, None, body)
if mods.exists(_.syntax == "implicit") =>
if mods.exists(_.syntax == "implicit") &&
!isImplicitly(body) =>
fix(t, body)
case t @ m.Defn.Def(mods, _, _, _, None, body)
if mods.exists(_.syntax == "implicit") =>
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/scalafix/rewrite/SemanticApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import scala.meta.Type
* See [[ExplicitImplicit]] for an example usage of this semantic api.
*/
trait SemanticApi {

/** Returns the type annotation for given val/def. */
def typeSignature(defn: Defn): Option[Type]
}
146 changes: 145 additions & 1 deletion core/src/test/resources/ExplicitImplicit/basic.source
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ package foo {
class A[T](e: T)
package foo {
class B {
implicit val x: deeperpackage.A[Int] = new A(10)
implicit val x: A[Int] = new A(10)
}
}
<<< shallow package
Expand All @@ -90,3 +90,147 @@ package foo {
class B {
implicit val x: foo.A[Int] = new foo.A(10)
}
<<< implicitly 2712 trick
class A {
implicit val s = "string"
implicit val x = implicitly[String]
}
>>>
class A {
implicit val s: String = "string"
implicit val x = implicitly[String]
}
<<< shorten imported name
import scala.collection.immutable.Map
class A {
implicit val x = Map(1 -> "")
}
>>>
import scala.collection.immutable.Map
class A {
implicit val x: Map[Int, String] = Map(1 -> "")
}
<<< shorten imported name 2
import scala.collection.immutable._
class A {
implicit val x = Map(1 -> "")
}
>>>
import scala.collection.immutable._
class A {
implicit val x: Map[Int, String] = Map(1 -> "")
}
<<< enclosing package strip is last
package b { class B }
package a {
import b.B
class A {
implicit val x = new B
}
}
>>>
package b { class B }
package a {
import b.B
class A {
implicit val x: B = new B
}
}
<<< inner inner object
object A {
object B {
class C
object C {
implicit val x = List(new C)
}
}
}
>>>
object A {
object B {
class C
object C {
implicit val x: List[C] = List(new C)
}
}
}
<<< sibling objects
object D {
class B
}
object A {
class C {
implicit val x = List(new D.B)
}
}
>>>
object D {
class B
}
object A {
class C {
implicit val x: List[D.B] = List(new D.B)
}
}
<<< SKIP slick tuple
object slick {
case class Supplier(id: Int, name: String)
implicit val supplierGetter = (arg: (Int, String)) => Supplier(arg._1, arg._2)
}
>>>
object slick {
case class Supplier(id: Int, name: String)
implicit val supplierGetter: ((Int, String)) => slick.Supplier = (arg: (Int, String)) => Supplier(arg._1, arg._2)
}
<<< NOWRAP package import
package scala.concurrent {
package banana {
object x {
implicit val f = Future.successful(1)
}
}
}
>>>
package scala.concurrent
package banana
object x {
implicit val f: Future[Int] = Future.successful(1)
}
<<< SKIP global
class Global {
type Position = Int
class Symbol {
def pos: Position = ???
}
}
trait Compiler {
val g: Global
val s: g.Symbol
}
trait Foo { self: Compiler =>
val addons: Object {
val g: Foo.this.g.type
}
import g._
import addons._
implicit val x = s.pos
}
>>>
class Global {
type Position = Int
class Symbol {
def pos: Position = ???
}
}
trait Compiler {
val g: Global
val s: g.Symbol
}
trait Foo { self: Compiler =>
val addons: Object {
val g: Foo.this.g.type
}
import g._
import addons._
implicit val x: Position = s.pos
}
2 changes: 1 addition & 1 deletion scalafix-nsc/src/main/resources/scalac-plugin.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<plugin>
<name>scalafix</name>
<classname>scalafix.nsc.ScalafixNsc</classname>
<classname>scalafix.nsc.ScalafixNscPlugin</classname>
</plugin>
Loading

0 comments on commit 4ab8e0e

Please sign in to comment.