aboutsummaryrefslogtreecommitdiff
path: root/sbt-bridge/test/xsbt/ExtractAPISpecification.scala
diff options
context:
space:
mode:
Diffstat (limited to 'sbt-bridge/test/xsbt/ExtractAPISpecification.scala')
-rw-r--r--sbt-bridge/test/xsbt/ExtractAPISpecification.scala80
1 files changed, 76 insertions, 4 deletions
diff --git a/sbt-bridge/test/xsbt/ExtractAPISpecification.scala b/sbt-bridge/test/xsbt/ExtractAPISpecification.scala
index f5af67e45..4b3b2c51a 100644
--- a/sbt-bridge/test/xsbt/ExtractAPISpecification.scala
+++ b/sbt-bridge/test/xsbt/ExtractAPISpecification.scala
@@ -2,9 +2,8 @@
package xsbt
import org.junit.runner.RunWith
-import xsbti.api.ClassLike
-import xsbti.api.Def
-import xsbt.api.ShowAPI
+import xsbti.api._
+import xsbt.api.DefaultShowAPI
import org.specs2.mutable.Specification
import org.specs2.runner.JUnitRunner
@@ -17,7 +16,7 @@ class ExtractAPISpecification extends Specification {
def stableExistentialNames: Boolean = {
def compileAndGetFooMethodApi(src: String): Def = {
- val compilerForTesting = new ScalaCompilerForUnitTesting
+ val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = false)
val sourceApi = compilerForTesting.extractApiFromSrc(src)
val FooApi = sourceApi.definitions().find(_.name() == "Foo").get.asInstanceOf[ClassLike]
val fooMethodApi = FooApi.structure().declared().find(_.name == "foo").get
@@ -38,8 +37,81 @@ class ExtractAPISpecification extends Specification {
|
}""".stripMargin
val fooMethodApi2 = compileAndGetFooMethodApi(src2)
+
fooMethodApi1 == fooMethodApi2
// Fails because xsbt.api is compiled with Scala 2.10
// SameAPI.apply(fooMethodApi1, fooMethodApi2)
}
+
+ /**
+ * Checks if representation of the inherited Namer class (with a declared self variable) in Global.Foo
+ * is stable between compiling from source and unpickling. We compare extracted APIs of Global when Global
+ * is compiled together with Namers or Namers is compiled first and then Global refers
+ * to Namers by unpickling types from class files.
+ *
+ * See https://github.com/sbt/sbt/issues/2504
+ */
+ "Self variable and no self type" in {
+ def selectNamer(api: SourceAPI): ClassLike = {
+ def selectClass(defs: Iterable[Definition], name: String): ClassLike = defs.collectFirst {
+ case cls: ClassLike if cls.name == name => cls
+ }.get
+ val global = selectClass(api.definitions, "Global")
+ val foo = selectClass(global.structure.declared, "Global.Foo")
+ selectClass(foo.structure.inherited, "Namers.Namer")
+ }
+ val src1 =
+ """|class Namers {
+ | class Namer { thisNamer => }
+ |}
+ |""".stripMargin
+ val src2 =
+ """|class Global {
+ | class Foo extends Namers
+ |}
+ |""".stripMargin
+ val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = false)
+ val apis = compilerForTesting.extractApisFromSrcs(reuseCompilerInstance = false)(List(src1, src2), List(src2))
+ val _ :: src2Api1 :: src2Api2 :: Nil = apis.toList
+ val namerApi1 = selectNamer(src2Api1)
+ val namerApi2 = selectNamer(src2Api2)
+
+ DefaultShowAPI(namerApi1) == DefaultShowAPI(namerApi2)
+ // Fails because xsbt.api is compiled with Scala 2.10
+ // SameAPI(namerApi1, namerApi2)
+ }
+
+ /**
+ * Checks if self type is properly extracted in various cases of declaring a self type
+ * with our without a self variable.
+ */
+ "Self type" in {
+ def collectFirstClass(defs: Array[Definition]): ClassLike = defs.collectFirst {
+ case c: ClassLike => c
+ }.get
+ val srcX = "trait X"
+ val srcY = "trait Y"
+ val srcC1 = "class C1 { this: C1 => }"
+ val srcC2 = "class C2 { thisC: C2 => }"
+ val srcC3 = "class C3 { this: X => }"
+ val srcC4 = "class C4 { thisC: X => }"
+ val srcC5 = "class C5 extends AnyRef with X with Y { self: X with Y => }"
+ val srcC6 = "class C6 extends AnyRef with X { self: X with Y => }"
+ // val srcC7 = "class C7 { _ => }" // DOTTY: Syntax not supported
+ val srcC8 = "class C8 { self => }"
+ val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = false)
+ val apis = compilerForTesting.extractApisFromSrcs(reuseCompilerInstance = true)(
+ List(srcX, srcY, srcC1, srcC2, srcC3, srcC4, srcC5, srcC6, srcC8)
+ ).map(x => collectFirstClass(x.definitions))
+ val emptyType = new EmptyType
+ def hasSelfType(c: ClassLike): Boolean =
+ c.selfType != emptyType
+ val (withSelfType, withoutSelfType) = apis.partition(hasSelfType)
+ // DOTTY: In the scalac ExtractAPI phase, the self-type is only
+ // extracted if it differs from the type of the class for stability
+ // reasons. This isn't necessary in dotty because we always pickle
+ // the self type.
+ withSelfType.map(_.name).toSet === Set("C1", "C2", "C3", "C4", "C5", "C6", "C8")
+ withoutSelfType.map(_.name).toSet === Set("X", "Y")
+ }
}