diff options
Diffstat (limited to 'sbt-bridge/test/xsbt/ExtractAPISpecification.scala')
-rw-r--r-- | sbt-bridge/test/xsbt/ExtractAPISpecification.scala | 80 |
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") + } } |