From d7eee101d005640352f74dbd1832fc72b88846bd Mon Sep 17 00:00:00 2001 From: Grzegorz Kossakowski Date: Tue, 8 Mar 2016 20:42:11 +0100 Subject: [PATCH] Add a pending test for self variable bug (#2504) Add a pending test that shows a problem with instability of representing self variables. This test covers the bug described in #2504. In order to test API representation of a class declared either in source file or unpickled from a class file, ScalaCompilerForUnitTesting has been extended to extract APIs from multiple compiler instances sharing a classpath. --- .../api/src/main/scala/xsbt/api/SameAPI.scala | 2 +- .../scala/xsbt/ExtractAPISpecification.scala | 36 +++++++++++++++++-- .../xsbt/ScalaCompilerForUnitTesting.scala | 9 +++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/compile/api/src/main/scala/xsbt/api/SameAPI.scala b/compile/api/src/main/scala/xsbt/api/SameAPI.scala index 1991bed11..de1254d48 100644 --- a/compile/api/src/main/scala/xsbt/api/SameAPI.scala +++ b/compile/api/src/main/scala/xsbt/api/SameAPI.scala @@ -46,7 +46,7 @@ object SameAPI { def apply(a: Source, b: Source): Boolean = a.apiHash == b.apiHash && (a.hash.nonEmpty && b.hash.nonEmpty) && apply(a.api, b.api) - def apply(a: Def, b: Def): Boolean = + def apply(a: Definition, b: Definition): Boolean = (new SameAPI(false, true)).sameDefinitions(List(a), List(b), true) def apply(a: SourceAPI, b: SourceAPI): Boolean = diff --git a/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala b/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala index ab158ee6e..c4009eabc 100644 --- a/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala +++ b/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala @@ -1,8 +1,7 @@ package xsbt import org.junit.runner.RunWith -import xsbti.api.ClassLike -import xsbti.api.Def +import xsbti.api.{ Definition, SourceAPI, ClassLike, Def } import xsbt.api.SameAPI import org.specs2.mutable.Specification import org.specs2.runner.JUnitRunner @@ -39,4 +38,37 @@ class ExtractAPISpecification extends Specification { val fooMethodApi2 = compileAndGetFooMethodApi(src2) 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. + */ + "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 + 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) + SameAPI(namerApi1, namerApi2) + }.pendingUntilFixed("have unstable representation (#2504)") } diff --git a/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala b/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala index 08a29b689..95a27a30d 100644 --- a/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala +++ b/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala @@ -31,6 +31,15 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) { analysisCallback.apis(tempSrcFile) } + /** + * Compiles given source code using Scala compiler and returns API representation + * extracted by ExtractAPI class. + */ + def extractApisFromSrcs(reuseCompilerInstance: Boolean)(srcs: List[String]*): Seq[SourceAPI] = { + val (tempSrcFiles, analysisCallback) = compileSrcs(srcs.toList, reuseCompilerInstance) + tempSrcFiles.map(analysisCallback.apis) + } + def extractUsedNamesFromSrc(src: String): Set[String] = { val (Seq(tempSrcFile), analysisCallback) = compileSrcs(src) analysisCallback.usedNames(tempSrcFile)