mirror of https://github.com/sbt/sbt.git
Merge pull request #2583 from eed3si9n/wip/2523
Disable scripted test for source-dependencies/as-seen-from-b
This commit is contained in:
commit
74d8a574d1
|
|
@ -51,6 +51,22 @@ abstract class Compat {
|
|||
def transformedType(tpe: Type): Type = tpe
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses given type and collects result of applying a partial function `pf`.
|
||||
*
|
||||
* NOTE: This class exists in Scala 2.10 as CollectTypeCollector but does not in earlier
|
||||
* versions (like 2.9) of Scala compiler that incremental cmpiler supports so we had to
|
||||
* reimplement that class here.
|
||||
*/
|
||||
class CollectTypeTraverser[T](pf: PartialFunction[Type, T]) extends TypeTraverser {
|
||||
var collected: List[T] = Nil
|
||||
def traverse(tpe: Type): Unit = {
|
||||
if (pf.isDefinedAt(tpe))
|
||||
collected = pf(tpe) :: collected
|
||||
mapOver(tpe)
|
||||
}
|
||||
}
|
||||
|
||||
private[this] final class MiscCompat {
|
||||
// in 2.9, nme.LOCALCHILD was renamed to tpnme.LOCAL_CHILD
|
||||
def tpnme = nme
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ object Dependency {
|
|||
* where it originates from. The Symbol->Classfile mapping is implemented by
|
||||
* LocateClassFile that we inherit from.
|
||||
*/
|
||||
final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
|
||||
final class Dependency(val global: CallbackGlobal) extends LocateClassFile with GlobalHelpers {
|
||||
import global._
|
||||
|
||||
def newPhase(prev: Phase): Phase = new DependencyPhase(prev)
|
||||
|
|
@ -79,6 +79,12 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
|
|||
private class ExtractDependenciesTraverser extends Traverser {
|
||||
private val _dependencies = collection.mutable.HashSet.empty[Symbol]
|
||||
protected def addDependency(dep: Symbol): Unit = if (dep ne NoSymbol) _dependencies += dep
|
||||
protected def addTreeDependency(tree: Tree): Unit = {
|
||||
addDependency(tree.symbol)
|
||||
if (tree.tpe != null)
|
||||
symbolsInType(tree.tpe).foreach(addDependency)
|
||||
()
|
||||
}
|
||||
def dependencies: Iterator[Symbol] = _dependencies.iterator
|
||||
def topLevelDependencies: Iterator[Symbol] = _dependencies.map(enclosingTopLevelClass).iterator
|
||||
|
||||
|
|
@ -118,11 +124,11 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
|
|||
* this looks fishy, see this thread:
|
||||
* https://groups.google.com/d/topic/scala-internals/Ms9WUAtokLo/discussion
|
||||
*/
|
||||
case id: Ident => addDependency(id.symbol)
|
||||
case id: Ident => addTreeDependency(id)
|
||||
case sel @ Select(qual, _) =>
|
||||
traverse(qual); addDependency(sel.symbol)
|
||||
traverse(qual); addTreeDependency(sel)
|
||||
case sel @ SelectFromTypeTree(qual, _) =>
|
||||
traverse(qual); addDependency(sel.symbol)
|
||||
traverse(qual); addTreeDependency(sel)
|
||||
|
||||
case Template(parents, self, body) =>
|
||||
// use typeSymbol to dealias type aliases -- we want to track the dependency on the real class in the alias's RHS
|
||||
|
|
@ -151,32 +157,6 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
|
|||
super.traverse(m)
|
||||
case other => super.traverse(other)
|
||||
}
|
||||
|
||||
private def symbolsInType(tp: Type): Set[Symbol] = {
|
||||
val typeSymbolCollector =
|
||||
new CollectTypeTraverser({
|
||||
case tpe if (tpe != null) && !tpe.typeSymbolDirect.isPackage => tpe.typeSymbolDirect
|
||||
})
|
||||
|
||||
typeSymbolCollector.traverse(tp)
|
||||
typeSymbolCollector.collected.toSet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses given type and collects result of applying a partial function `pf`.
|
||||
*
|
||||
* NOTE: This class exists in Scala 2.10 as CollectTypeCollector but does not in earlier
|
||||
* versions (like 2.9) of Scala compiler that incremental cmpiler supports so we had to
|
||||
* reimplement that class here.
|
||||
*/
|
||||
private final class CollectTypeTraverser[T](pf: PartialFunction[Type, T]) extends TypeTraverser {
|
||||
var collected: List[T] = Nil
|
||||
def traverse(tpe: Type): Unit = {
|
||||
if (pf.isDefinedAt(tpe))
|
||||
collected = pf(tpe) :: collected
|
||||
mapOver(tpe)
|
||||
}
|
||||
}
|
||||
|
||||
/** Copied straight from Scala 2.10 as it does not exist in Scala 2.9 compiler */
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import scala.tools.nsc._
|
|||
*
|
||||
* Extracts simple (unqualified) names mentioned in given in non-definition position by collecting
|
||||
* all symbols associated with non-definition trees and extracting names from all collected symbols.
|
||||
* Also extract the names of the types of non-definition trees (see source-dependencies/types-in-used-names
|
||||
* for an example where this is required).
|
||||
*
|
||||
* If given symbol is mentioned both in definition and in non-definition position (e.g. in member
|
||||
* selection) then that symbol is collected. It means that names of symbols defined and used in the
|
||||
|
|
@ -38,7 +40,7 @@ import scala.tools.nsc._
|
|||
* The tree walking algorithm walks into TypeTree.original explicitly.
|
||||
*
|
||||
*/
|
||||
class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) extends Compat {
|
||||
class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) extends Compat with GlobalHelpers {
|
||||
import global._
|
||||
|
||||
@inline def debug(msg: => String) = if (settings.verbose.value) inform(msg)
|
||||
|
|
@ -61,10 +63,12 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext
|
|||
*/
|
||||
val inspectedOriginalTrees = collection.mutable.Set.empty[Tree]
|
||||
|
||||
def addSymbol(symbol: Symbol): Unit = {
|
||||
val symbolNameAsString = symbol.name.decode.trim
|
||||
namesBuffer += symbolNameAsString
|
||||
}
|
||||
def addSymbol(symbol: Symbol): Unit =
|
||||
if (eligibleAsUsedName(symbol)) {
|
||||
val symbolNameAsString = symbol.name.decode.trim
|
||||
namesBuffer += symbolNameAsString
|
||||
()
|
||||
}
|
||||
|
||||
def handleTreeNode(node: Tree): Unit = {
|
||||
def handleMacroExpansion(original: Tree): Unit = {
|
||||
|
|
@ -91,8 +95,10 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext
|
|||
// not what we need
|
||||
case t: TypeTree if t.original != null =>
|
||||
t.original.foreach(handleTreeNode)
|
||||
case t if t.hasSymbol && eligibleAsUsedName(t.symbol) =>
|
||||
case t if t.hasSymbol =>
|
||||
addSymbol(t.symbol)
|
||||
if (t.tpe != null)
|
||||
symbolsInType(t.tpe).foreach(addSymbol)
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package xsbt
|
||||
|
||||
import scala.tools.nsc.Global
|
||||
|
||||
trait GlobalHelpers extends Compat {
|
||||
val global: CallbackGlobal
|
||||
import global.{ Tree, Type, Symbol, TypeTraverser }
|
||||
|
||||
def symbolsInType(tp: Type): Set[Symbol] = {
|
||||
val typeSymbolCollector =
|
||||
new CollectTypeTraverser({
|
||||
case tpe if (tpe != null) && !tpe.typeSymbolDirect.isPackage => tpe.typeSymbolDirect
|
||||
})
|
||||
|
||||
typeSymbolCollector.traverse(tp)
|
||||
typeSymbolCollector.collected.toSet
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,9 @@ class ExtractUsedNamesSpecification extends Specification {
|
|||
* definition.
|
||||
*/
|
||||
private val standardNames = Set(
|
||||
// AnyRef is added as default parent of a class
|
||||
"scala", "AnyRef",
|
||||
"scala",
|
||||
// The default parent of a class is "AnyRef" which is an alias for "Object"
|
||||
"AnyRef", "Object",
|
||||
// class receives a default constructor which is internally called "<init>"
|
||||
"<init>")
|
||||
|
||||
|
|
@ -69,7 +70,45 @@ class ExtractUsedNamesSpecification extends Specification {
|
|||
|}""".stripMargin
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = true)
|
||||
val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB)
|
||||
val expectedNames = standardNames ++ Set("A", "a", "B", "=")
|
||||
val expectedNames = standardNames ++ Set("A", "a", "B", "=", "Int")
|
||||
usedNames === expectedNames
|
||||
}
|
||||
|
||||
"extract names in the types of trees" in {
|
||||
val src1 = """|class X0
|
||||
|class X1 extends X0
|
||||
|class Y
|
||||
|class A {
|
||||
| type T >: X1 <: X0
|
||||
|}
|
||||
|class M
|
||||
|class N
|
||||
|class P0
|
||||
|class P1 extends P0
|
||||
|object B {
|
||||
| type S = Y
|
||||
| val lista: List[A] = ???
|
||||
| val at: A#T = ???
|
||||
| val as: S = ???
|
||||
| def foo(m: M): N = ???
|
||||
| def bar[Param >: P1 <: P0](p: Param): Param = ???
|
||||
|}""".stripMargin
|
||||
val src2 = """|object Test {
|
||||
| val x = B.lista
|
||||
| val y = B.at
|
||||
| val z = B.as
|
||||
| B.foo(???)
|
||||
| B.bar(???)
|
||||
|}""".stripMargin
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = true)
|
||||
val usedNames = compilerForTesting.extractUsedNamesFromSrc(src1, src2)
|
||||
val expectedNames = standardNames ++ Set("Test", "B", "x", "y", "z",
|
||||
"Predef", "???", "Nothing",
|
||||
"lista", "package", "List", "A",
|
||||
"at", "T",
|
||||
"as", "S",
|
||||
"foo", "M", "N",
|
||||
"bar", "Param", "P1", "P0")
|
||||
usedNames === expectedNames
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
abstract class A {
|
||||
type T
|
||||
object X {
|
||||
def foo(x: T): T = x
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class B extends A {
|
||||
type T = Int
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
object C extends B
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object D {
|
||||
C.X.foo(12)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class B extends A {
|
||||
type T = String
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
> compile
|
||||
$ copy-file changes/B2.scala B.scala
|
||||
-> compile
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
lazy val root = (project in file(".")).
|
||||
settings(
|
||||
scalaVersion := "2.11.8"
|
||||
)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
abstract class A {
|
||||
type T <: S
|
||||
type S
|
||||
object X {
|
||||
def foo: T = null.asInstanceOf[T]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class B extends A {
|
||||
type S <: Int
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class B extends A {
|
||||
type S <: String
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
object C extends B
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object D {
|
||||
val x: Int = C.X.foo
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
$ copy-file changes/A1.scala A.scala
|
||||
|
||||
> compile
|
||||
|
||||
$ copy-file changes/B1.scala B.scala
|
||||
|
||||
> compile
|
||||
|
||||
|
||||
$ copy-file changes/C1.scala C.scala
|
||||
|
||||
> compile
|
||||
|
||||
|
||||
$ copy-file changes/D1.scala D.scala
|
||||
|
||||
> compile
|
||||
|
||||
$ copy-file changes/B2.scala B.scala
|
||||
$ sleep 1000
|
||||
|
||||
-> compile
|
||||
|
|
@ -0,0 +1 @@
|
|||
class A
|
||||
|
|
@ -0,0 +1 @@
|
|||
class B extends A
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object C {
|
||||
val listb: List[B] = List(new B)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object D {
|
||||
val lista: List[A] = C.listb
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
class B
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
> compile
|
||||
$ copy-file changes/B2.scala B.scala
|
||||
# Compilation of D.scala should fail because B is no longer a subtype of A
|
||||
-> compile
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class A {
|
||||
type T <: S
|
||||
type S <: Int
|
||||
def foo: T = null.asInstanceOf[T]
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object B {
|
||||
val x: Int = (new A).foo
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class A {
|
||||
type T <: S
|
||||
type S <: String
|
||||
def foo: T = null.asInstanceOf[T]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
> compile
|
||||
$ copy-file changes/A2.scala A.scala
|
||||
# Same workaround as #2565
|
||||
# Compilation of B.scala should fail because A#S is no longer a subtype of Int
|
||||
-> compile
|
||||
Loading…
Reference in New Issue