diff --git a/src/main/java/xsbti/InteractiveConsoleFactory.java b/src/main/java/xsbti/InteractiveConsoleFactory.java deleted file mode 100644 index 91b683ad5f75..000000000000 --- a/src/main/java/xsbti/InteractiveConsoleFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Zinc - The incremental compiler for Scala. - * Copyright 2011 - 2017, Lightbend, Inc. - * Copyright 2008 - 2010, Mark Harrah - * This software is released under the terms written in LICENSE. - */ - -package xsbti; - -public interface InteractiveConsoleFactory { - InteractiveConsoleInterface createConsole( - String[] args, - String bootClasspathString, - String classpathString, - String initialCommands, - String cleanupCommands, - ClassLoader loader, - String[] bindNames, - Object[] bindValues, - Logger log - ); -} diff --git a/src/main/java/xsbti/InteractiveConsoleInterface.java b/src/main/java/xsbti/InteractiveConsoleInterface.java deleted file mode 100644 index 6bd1b83d553c..000000000000 --- a/src/main/java/xsbti/InteractiveConsoleInterface.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Zinc - The incremental compiler for Scala. - * Copyright 2011 - 2017, Lightbend, Inc. - * Copyright 2008 - 2010, Mark Harrah - * This software is released under the terms written in LICENSE. - */ - -package xsbti; - -public interface InteractiveConsoleInterface { - void reset(); - InteractiveConsoleResponse interpret(String line, boolean synthetic); -} diff --git a/src/main/java/xsbti/InteractiveConsoleResponse.java b/src/main/java/xsbti/InteractiveConsoleResponse.java deleted file mode 100644 index 849651749f86..000000000000 --- a/src/main/java/xsbti/InteractiveConsoleResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Zinc - The incremental compiler for Scala. - * Copyright 2011 - 2017, Lightbend, Inc. - * Copyright 2008 - 2010, Mark Harrah - * This software is released under the terms written in LICENSE. - */ - -package xsbti; - -/** Public interface for repl responses. */ -public interface InteractiveConsoleResponse { - InteractiveConsoleResult result(); - - String output(); -} diff --git a/src/main/java/xsbti/InteractiveConsoleResult.java b/src/main/java/xsbti/InteractiveConsoleResult.java deleted file mode 100644 index 15cfd047853a..000000000000 --- a/src/main/java/xsbti/InteractiveConsoleResult.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Zinc - The incremental compiler for Scala. - * Copyright 2011 - 2017, Lightbend, Inc. - * Copyright 2008 - 2010, Mark Harrah - * This software is released under the terms written in LICENSE. - */ - -package xsbti; - -public enum InteractiveConsoleResult { - Success, - Incomplete, - Error -} diff --git a/src/main/mima-filters/1.0.0.backwards.excludes b/src/main/mima-filters/1.0.0.backwards.excludes new file mode 100644 index 000000000000..0adbb561dcd1 --- /dev/null +++ b/src/main/mima-filters/1.0.0.backwards.excludes @@ -0,0 +1,6 @@ +# xsbti Java interfaces must be defined in the compiler interface, not the bridge. +# Bridge implementations are compiled per Zinc, so these are safe to change. +ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleFactory") +ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleResult") +ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleInterface") +ProblemFilters.exclude[MissingClassProblem]("xsbti.InteractiveConsoleResponse") diff --git a/src/main/scala/xsbt/ClassName.scala b/src/main/scala/xsbt/ClassName.scala index ec32db1927a5..b81e91c1d1b8 100644 --- a/src/main/scala/xsbt/ClassName.scala +++ b/src/main/scala/xsbt/ClassName.scala @@ -68,15 +68,19 @@ trait ClassName extends Compat { * * If `s` represents a package object `pkg3`, then the returned name will be `pkg1.pkg2.pkg3.package`. * If `s` represents a class `Foo` nested in package object `pkg3` then the returned name is `pkg1.pkg2.pk3.Foo`. + * + * Note that some objects with special access rights are encoded in names + * (like qualified privates `private[qualifier]`). In order to get the right + * original names, we need to use `unexpandedName`. */ protected def classNameAsSeenIn(in: Symbol, s: Symbol): String = enteringPhase(currentRun.picklerPhase.next) { if (in.isRoot || in.isRootPackage || in == NoSymbol || in.isEffectiveRoot) s.simpleName.toString else if (in.isPackageObjectOrClass) - in.owner.fullName + "." + s.name + in.owner.fullName + "." + s.unexpandedName else - in.fullName + "." + s.name + in.fullName + "." + s.unexpandedName } private def pickledName(s: Symbol): Name = diff --git a/src/main/scala/xsbt/Dependency.scala b/src/main/scala/xsbt/Dependency.scala index 6ee53309aabc..4148265449a0 100644 --- a/src/main/scala/xsbt/Dependency.scala +++ b/src/main/scala/xsbt/Dependency.scala @@ -92,16 +92,21 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile with } // Define processor reusing `processDependency` definition - val memberRef = processDependency(DependencyByMemberRef) _ - val inheritance = processDependency(DependencyByInheritance) _ - val localInheritance = processDependency(LocalDependencyByInheritance) _ + val memberRef = processDependency(DependencyByMemberRef, false) _ + val inheritance = processDependency(DependencyByInheritance, true) _ + val localInheritance = processDependency(LocalDependencyByInheritance, true) _ + + @deprecated("Use processDependency that takes allowLocal.", "1.1.0") + def processDependency(context: DependencyContext)(dep: ClassDependency): Unit = + processDependency(context, true)(dep) /* * Handles dependency on given symbol by trying to figure out if represents a term * that is coming from either source code (not necessarily compiled in this compilation * run) or from class file and calls respective callback method. */ - def processDependency(context: DependencyContext)(dep: ClassDependency): Unit = { + def processDependency(context: DependencyContext, allowLocal: Boolean)( + dep: ClassDependency): Unit = { val fromClassName = classNameAsString(dep.from) def binaryDependency(file: File, binaryClassName: String) = @@ -134,11 +139,12 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile with case None => debuglog(Feedback.noOriginFileForExternalSymbol(dep.to)) } - } else if (onSource.file != sourceFile) { - // Dependency is internal -- but from other file / compilation unit + } else if (onSource.file != sourceFile || allowLocal) { + // We cannot ignore dependencies coming from the same source file because + // the dependency info needs to propagate. See source-dependencies/trait-trait-211. val onClassName = classNameAsString(dep.to) callback.classDependency(onClassName, fromClassName, context) - } else () // Comes from the same file, ignore + } } } @@ -228,7 +234,6 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile with val depClass = enclOrModuleClass(dep) val dependency = ClassDependency(fromClass, depClass) if (!cache.contains(dependency) && - fromClass.associatedFile != depClass.associatedFile && !depClass.isRefinementClass) { process(dependency) cache.add(dependency) diff --git a/src/main/scala/xsbt/ExtractAPI.scala b/src/main/scala/xsbt/ExtractAPI.scala index 2a2405297693..07ba61e5e5e3 100644 --- a/src/main/scala/xsbt/ExtractAPI.scala +++ b/src/main/scala/xsbt/ExtractAPI.scala @@ -358,7 +358,16 @@ class ExtractAPI[GlobalType <: Global]( * TODO: can we include hashes for parent classes instead? This seems a bit messy. */ private def mkStructureWithInherited(info: Type, s: Symbol): xsbti.api.Structure = { - val ancestorTypes = linearizedAncestorTypes(info) + val ancestorTypes0 = linearizedAncestorTypes(info) + val ancestorTypes = + if (s.isDerivedValueClass) { + val underlying = s.derivedValueClassUnbox.tpe.finalResultType + // The underlying type of a value class should be part of the name hash + // of the value class (see the test `value-class-underlying`), this is accomplished + // by adding the underlying type to the list of parent types. + underlying :: ancestorTypes0 + } else + ancestorTypes0 val decls = info.decls.toList val declsNoModuleCtor = if (s.isModuleClass) removeConstructors(decls) else decls val declSet = decls.toSet diff --git a/src/main/scala/xsbt/InteractiveConsoleHelper.scala b/src/main/scala/xsbt/InteractiveConsoleHelper.scala index 42f571db2763..01dd182e5e96 100644 --- a/src/main/scala/xsbt/InteractiveConsoleHelper.scala +++ b/src/main/scala/xsbt/InteractiveConsoleHelper.scala @@ -7,14 +7,14 @@ package xsbt -import scala.tools.nsc.interpreter.IR +import Compat._ import xsbti.InteractiveConsoleResult object InteractiveConsoleHelper { - implicit def toConsoleResult(ir: IR.Result): InteractiveConsoleResult = + implicit def toConsoleResult(ir: Results.Result): InteractiveConsoleResult = ir match { - case IR.Success => InteractiveConsoleResult.Success - case IR.Incomplete => InteractiveConsoleResult.Incomplete - case IR.Error => InteractiveConsoleResult.Error + case Results.Success => InteractiveConsoleResult.Success + case Results.Incomplete => InteractiveConsoleResult.Incomplete + case Results.Error => InteractiveConsoleResult.Error } } diff --git a/src/main/scala/xsbt/InteractiveConsoleInterface.scala b/src/main/scala/xsbt/InteractiveConsoleInterface.scala index 2aa9f5f48306..24e61717224d 100644 --- a/src/main/scala/xsbt/InteractiveConsoleInterface.scala +++ b/src/main/scala/xsbt/InteractiveConsoleInterface.scala @@ -14,6 +14,7 @@ import scala.tools.nsc.{ GenericRunnerCommand, Settings } import xsbti.Logger +import Compat._ import InteractiveConsoleHelper._ class InteractiveConsoleInterface( @@ -38,9 +39,10 @@ class InteractiveConsoleInterface( val outWriter: StringWriter = new StringWriter val poutWriter: PrintWriter = new PrintWriter(outWriter) - val interpreter: IMain = new IMain(compilerSettings, new PrintWriter(outWriter)) { - def lastReq: Request = prevRequestList.last - } + val interpreter: IMain = + new IMain(compilerSettings, replReporter(compilerSettings, new PrintWriter(outWriter))) { + def lastReq: Request = prevRequestList.last + } def interpret(line: String, synthetic: Boolean): InteractiveConsoleResponse = { clearBuffer() diff --git a/src/main/scala_2.10/xsbt/Compat.scala b/src/main/scala_2.10/xsbt/Compat.scala index 752ac20d6b76..c34db28ae4ab 100644 --- a/src/main/scala_2.10/xsbt/Compat.scala +++ b/src/main/scala_2.10/xsbt/Compat.scala @@ -1,5 +1,6 @@ package xsbt +import java.io.PrintWriter import xsbti.compile.Output import scala.reflect.{ internal => sri } import scala.reflect.internal.{ util => sriu } @@ -150,6 +151,12 @@ trait ZincGlobalCompat { } object Compat { + // IR is renamed to Results + val Results = scala.tools.nsc.interpreter.IR + + // IMain in 2.13 accepts ReplReporter + def replReporter(settings: Settings, writer: PrintWriter) = writer + implicit final class TreeOps(val tree: sri.Trees#Tree) extends AnyVal { // Introduced in 2.11 @inline final def hasSymbolField: Boolean = tree.hasSymbol diff --git a/src/main/scala/xsbt/ConsoleInterface.scala b/src/main/scala_2.10/xsbt/ConsoleInterface.scala similarity index 96% rename from src/main/scala/xsbt/ConsoleInterface.scala rename to src/main/scala_2.10/xsbt/ConsoleInterface.scala index caff0157b6d4..531891ab2e6d 100644 --- a/src/main/scala/xsbt/ConsoleInterface.scala +++ b/src/main/scala_2.10/xsbt/ConsoleInterface.scala @@ -8,7 +8,7 @@ package xsbt import xsbti.Logger -import scala.tools.nsc.interpreter.{ ILoop, IMain, InteractiveReader } +import scala.tools.nsc.interpreter.{ ILoop, IMain, InteractiveReader, NamedParam } import scala.tools.nsc.reporters.Reporter import scala.tools.nsc.{ GenericRunnerCommand, Settings } @@ -54,7 +54,7 @@ class ConsoleInterface { super.createInterpreter() for ((id, value) <- bindNames zip bindValues) - intp.beQuietDuring(intp.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value)) + intp.quietBind(NamedParam.clazz(id, value)) if (!initialCommands.isEmpty) intp.interpret(initialCommands) diff --git a/src/main/scala_2.11+/xsbt/Compat.scala b/src/main/scala_2.11-12/xsbt/Compat.scala similarity index 73% rename from src/main/scala_2.11+/xsbt/Compat.scala rename to src/main/scala_2.11-12/xsbt/Compat.scala index 56a05d9d5cd9..790ff4e83bc2 100644 --- a/src/main/scala_2.11+/xsbt/Compat.scala +++ b/src/main/scala_2.11-12/xsbt/Compat.scala @@ -7,12 +7,19 @@ package xsbt +import java.io.PrintWriter import xsbti.compile.Output import scala.tools.nsc.Settings abstract class Compat -object Compat +object Compat { + // IR is renamed to Results + val Results = scala.tools.nsc.interpreter.IR + + // IMain in 2.13 accepts ReplReporter + def replReporter(settings: Settings, writer: PrintWriter) = writer +} /** Defines compatibility utils for [[ZincCompiler]]. */ trait ZincGlobalCompat { diff --git a/src/main/scala_2.11-12/xsbt/ConsoleInterface.scala b/src/main/scala_2.11-12/xsbt/ConsoleInterface.scala new file mode 100644 index 000000000000..531891ab2e6d --- /dev/null +++ b/src/main/scala_2.11-12/xsbt/ConsoleInterface.scala @@ -0,0 +1,105 @@ +/* + * Zinc - The incremental compiler for Scala. + * Copyright 2011 - 2017, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * This software is released under the terms written in LICENSE. + */ + +package xsbt + +import xsbti.Logger +import scala.tools.nsc.interpreter.{ ILoop, IMain, InteractiveReader, NamedParam } +import scala.tools.nsc.reporters.Reporter +import scala.tools.nsc.{ GenericRunnerCommand, Settings } + +class ConsoleInterface { + def commandArguments( + args: Array[String], + bootClasspathString: String, + classpathString: String, + log: Logger + ): Array[String] = + MakeSettings.sync(args, bootClasspathString, classpathString, log).recreateArgs.toArray[String] + + def run( + args: Array[String], + bootClasspathString: String, + classpathString: String, + initialCommands: String, + cleanupCommands: String, + loader: ClassLoader, + bindNames: Array[String], + bindValues: Array[Any], + log: Logger + ): Unit = { + lazy val interpreterSettings = MakeSettings.sync(args.toList, log) + val compilerSettings = MakeSettings.sync(args, bootClasspathString, classpathString, log) + + log.info(Message("Starting scala interpreter...")) + log.info(Message("")) + + val loop = new ILoop { + override def createInterpreter() = { + if (loader ne null) { + in = InteractiveReader.apply() + intp = new IMain(settings) { + override protected def parentClassLoader = + if (loader eq null) super.parentClassLoader else loader + + override protected def newCompiler(settings: Settings, reporter: Reporter) = + super.newCompiler(compilerSettings, reporter) + } + intp.setContextClassLoader() + } else + super.createInterpreter() + + for ((id, value) <- bindNames zip bindValues) + intp.quietBind(NamedParam.clazz(id, value)) + + if (!initialCommands.isEmpty) + intp.interpret(initialCommands) + + () + } + + override def closeInterpreter(): Unit = { + if (!cleanupCommands.isEmpty) + intp.interpret(cleanupCommands) + super.closeInterpreter() + } + } + + loop.process(if (loader eq null) compilerSettings else interpreterSettings) + + () + } +} + +object MakeSettings { + def apply(args: List[String], log: Logger): Settings = { + val command = new GenericRunnerCommand(args, message => log.error(Message(message))) + if (command.ok) + command.settings + else + throw new InterfaceCompileFailed(Array(), Array(), command.usageMsg) + } + + def sync( + args: Array[String], + bootClasspathString: String, + classpathString: String, + log: Logger + ): Settings = { + val compilerSettings = sync(args.toList, log) + if (!bootClasspathString.isEmpty) + compilerSettings.bootclasspath.value = bootClasspathString + compilerSettings.classpath.value = classpathString + compilerSettings + } + + def sync(options: List[String], log: Logger): Settings = { + val settings = apply(options, log) + settings.Yreplsync.value = true + settings + } +} diff --git a/src/main/scala_2.13/xsbt/Compat.scala b/src/main/scala_2.13/xsbt/Compat.scala new file mode 100644 index 000000000000..19ca44cd9d08 --- /dev/null +++ b/src/main/scala_2.13/xsbt/Compat.scala @@ -0,0 +1,33 @@ +/* + * Zinc - The incremental compiler for Scala. + * Copyright 2011 - 2017, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * This software is released under the terms written in LICENSE. + */ + +package xsbt + +import java.io.PrintWriter +import xsbti.compile.Output +import scala.tools.nsc.Settings +import scala.tools.nsc.interpreter.shell.ReplReporterImpl + +abstract class Compat +object Compat { + // IR is renanmed to Results + val Results = scala.tools.nsc.interpreter.Results + + // IMain in 2.13 accepts ReplReporter + def replReporter(settings: Settings, writer: PrintWriter) = + new ReplReporterImpl(settings, writer) +} + +/** Defines compatibility utils for [[ZincCompiler]]. */ +trait ZincGlobalCompat { + protected def superDropRun(): Unit = () +} + +private trait CachedCompilerCompat { self: CachedCompiler0 => + def newCompiler(settings: Settings, reporter: DelegatingReporter, output: Output): ZincCompiler = + new ZincCompiler(settings, reporter, output) +} diff --git a/src/main/scala_2.13/xsbt/ConsoleInterface.scala b/src/main/scala_2.13/xsbt/ConsoleInterface.scala new file mode 100644 index 000000000000..2081ce0c7829 --- /dev/null +++ b/src/main/scala_2.13/xsbt/ConsoleInterface.scala @@ -0,0 +1,102 @@ +/* + * Zinc - The incremental compiler for Scala. + * Copyright 2011 - 2017, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * This software is released under the terms written in LICENSE. + */ + +package xsbt + +import xsbti.Logger +import scala.tools.nsc.interpreter.IMain +import scala.tools.nsc.interpreter.shell.{ ILoop, ShellConfig, ReplReporterImpl } +import scala.tools.nsc.reporters.Reporter +import scala.tools.nsc.{ GenericRunnerCommand, Settings } + +class ConsoleInterface { + def commandArguments( + args: Array[String], + bootClasspathString: String, + classpathString: String, + log: Logger + ): Array[String] = + MakeSettings.sync(args, bootClasspathString, classpathString, log).recreateArgs.toArray[String] + + def run( + args: Array[String], + bootClasspathString: String, + classpathString: String, + initialCommands: String, + cleanupCommands: String, + loader: ClassLoader, + bindNames: Array[String], + bindValues: Array[Any], + log: Logger + ): Unit = { + lazy val interpreterSettings = MakeSettings.sync(args.toList, log) + val compilerSettings = MakeSettings.sync(args, bootClasspathString, classpathString, log) + + log.info(Message("Starting scala interpreter...")) + log.info(Message("")) + + val loop = new ILoop(ShellConfig(interpreterSettings)) { + override def createInterpreter(interpreterSettings: Settings) = { + if (loader ne null) { + val reporter = new ReplReporterImpl(interpreterSettings) + intp = new IMain(interpreterSettings, reporter) { + override protected def parentClassLoader = + if (loader eq null) super.parentClassLoader + else loader + } + intp.setContextClassLoader() + } else + super.createInterpreter(interpreterSettings) + + for ((id, value) <- bindNames zip bindValues) + intp.beQuietDuring(intp.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value)) + + if (!initialCommands.isEmpty) + intp.interpret(initialCommands) + + () + } + + override def closeInterpreter(): Unit = { + if (!cleanupCommands.isEmpty) + intp.interpret(cleanupCommands) + super.closeInterpreter() + } + } + + loop.run(compilerSettings) + } +} + +object MakeSettings { + def apply(args: List[String], log: Logger): Settings = { + val command = new GenericRunnerCommand(args, message => log.error(Message(message))) + if (command.ok) + command.settings + else + throw new InterfaceCompileFailed(Array(), Array(), command.usageMsg) + } + + def sync( + args: Array[String], + bootClasspathString: String, + classpathString: String, + log: Logger + ): Settings = { + val compilerSettings = sync(args.toList, log) + if (!bootClasspathString.isEmpty) + compilerSettings.bootclasspath.value = bootClasspathString + compilerSettings.classpath.value = classpathString + compilerSettings + } + + def sync(options: List[String], log: Logger): Settings = { + val settings = apply(options, log) + settings.Yreplsync.value = true + settings + } +} diff --git a/src/test/resources/ExtractUsedNamesPerformance.scala.source b/src/test/resources/ExtractUsedNamesPerformance.scala.source deleted file mode 100644 index cd113ea2af19..000000000000 --- a/src/test/resources/ExtractUsedNamesPerformance.scala.source +++ /dev/null @@ -1,177 +0,0 @@ -package acme - -/** - * File took pattern from shapeless hlist.scala and tupler.scala just - * for performance test - */ - -sealed trait HList extends Product with Serializable - -final case class ::[+H, +T <: HList](head: H, tail: T) extends HList { - override def toString = head match { - case _: ::[_, _] => "(" + head + ") :: " + tail.toString - case _ => head + " :: " + tail.toString - } -} - -sealed trait HNil extends HList { - def ::[H](h: H) = acme.::(h, this) - override def toString = "HNil" -} - -case object HNil extends HNil - -trait DepFn1[T] { - type Out - def apply(t: T): Out -} - -trait Tupler[L <: HList] extends DepFn1[L] with Serializable - -object Tupler extends TuplerInstances { - def apply[L <: HList](implicit tupler: Tupler[L]): Aux[L, tupler.Out] = tupler - - implicit val hnilTupler: Aux[HNil, Unit] = - new Tupler[HNil] { - type Out = Unit - def apply(l: HNil): Out = () - } -} - -import Tupler._ - -trait TuplerInstances { - type Aux[L <: HList, Out0] = Tupler[L] { type Out = Out0 } - - implicit def hlistTupler1[A]: Aux[A :: HNil, Tuple1[A]] = - new Tupler[A :: HNil] { - type Out = Tuple1[A] - def apply(l: A :: HNil): Out = l match { case a :: HNil => Tuple1(a) } - } - - implicit def hlistTupler2[A, B]: Aux[A :: B :: HNil, (A, B)] = - new Tupler[A :: B :: HNil] { - type Out = (A, B) - def apply(l: A :: B :: HNil): Out = l match { case a :: b :: HNil => (a, b) } - } - - implicit def hlistTupler3[A, B, C]: Aux[A :: B :: C :: HNil, (A, B, C)] = - new Tupler[A :: B :: C :: HNil] { - type Out = (A, B, C) - def apply(l: A :: B :: C :: HNil): Out = l match { case a :: b :: c :: HNil => (a, b, c) } - } - - implicit def hlistTupler4[A, B, C, D]: Aux[A :: B :: C :: D :: HNil, (A, B, C, D)] = - new Tupler[A :: B :: C :: D :: HNil] { - type Out = (A, B, C, D) - def apply(l: A :: B :: C :: D :: HNil): Out = l match { case a :: b :: c :: d :: HNil => (a, b, c, d) } - } - - implicit def hlistTupler5[A, B, C, D, E]: Aux[A :: B :: C :: D :: E :: HNil, (A, B, C, D, E)] = - new Tupler[A :: B :: C :: D :: E :: HNil] { - type Out = (A, B, C, D, E) - def apply(l: A :: B :: C :: D :: E :: HNil): Out = l match { case a :: b :: c :: d :: e :: HNil => (a, b, c, d, e) } - } - - implicit def hlistTupler6[A, B, C, D, E, F]: Aux[A :: B :: C :: D :: E :: F :: HNil, (A, B, C, D, E, F)] = - new Tupler[A :: B :: C :: D :: E :: F :: HNil] { - type Out = (A, B, C, D, E, F) - def apply(l: A :: B :: C :: D :: E :: F :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: HNil => (a, b, c, d, e, f) } - } - - implicit def hlistTupler7[A, B, C, D, E, F, G]: Aux[A :: B :: C :: D :: E :: F :: G :: HNil, (A, B, C, D, E, F, G)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: HNil] { - type Out = (A, B, C, D, E, F, G) - def apply(l: A :: B :: C :: D :: E :: F :: G :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: HNil => (a, b, c, d, e, f, g) } - } - - implicit def hlistTupler8[A, B, C, D, E, F, G, H]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: HNil, (A, B, C, D, E, F, G, H)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: HNil] { - type Out = (A, B, C, D, E, F, G, H) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: HNil => (a, b, c, d, e, f, g, h) } - } - - implicit def hlistTupler9[A, B, C, D, E, F, G, H, I]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: HNil, (A, B, C, D, E, F, G, H, I)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: HNil => (a, b, c, d, e, f, g, h, i) } - } - - implicit def hlistTupler10[A, B, C, D, E, F, G, H, I, J]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: HNil, (A, B, C, D, E, F, G, H, I, J)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: HNil => (a, b, c, d, e, f, g, h, i, j) } - } - - implicit def hlistTupler11[A, B, C, D, E, F, G, H, I, J, K]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: HNil, (A, B, C, D, E, F, G, H, I, J, K)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: HNil => (a, b, c, d, e, f, g, h, i, j, k) } - } - - implicit def hlistTupler12[A, B, C, D, E, F, G, H, I, J, K, L]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l) } - } - - implicit def hlistTupler13[A, B, C, D, E, F, G, H, I, J, K, L, M]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m) } - } - - implicit def hlistTupler14[A, B, C, D, E, F, G, H, I, J, K, L, M, N]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n) } - } - - implicit def hlistTupler15[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) } - } - - implicit def hlistTupler16[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) } - } - - implicit def hlistTupler17[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: q :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) } - } - - implicit def hlistTupler18[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: q :: r :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) } - } - - implicit def hlistTupler19[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: q :: r :: s :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) } - } - - implicit def hlistTupler20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: q :: r :: s :: t :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) } - } - - implicit def hlistTupler21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: U :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: U :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: U :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: q :: r :: s :: t :: u :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) } - } - - implicit def hlistTupler22[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V]: Aux[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: U :: V :: HNil, (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V)] = - new Tupler[A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: U :: V :: HNil] { - type Out = (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) - def apply(l: A :: B :: C :: D :: E :: F :: G :: H :: I :: J :: K :: L :: M :: N :: O :: P :: Q :: R :: S :: T :: U :: V :: HNil): Out = l match { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: q :: r :: s :: t :: u :: v :: HNil => (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) } - } -} diff --git a/src/test/scala/xsbt/ClassNameSpecification.scala b/src/test/scala/xsbt/ClassNameSpecification.scala deleted file mode 100644 index aa4c18a7d80d..000000000000 --- a/src/test/scala/xsbt/ClassNameSpecification.scala +++ /dev/null @@ -1,80 +0,0 @@ -package xsbt - -import sbt.internal.inc.UnitSpec - -class ClassNameSpecification extends UnitSpec { - - "ClassName" should "create correct binary names for top level object" in { - val src = "object A" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val binaryClassNames = compilerForTesting.extractBinaryClassNamesFromSrc(src) - - assert(binaryClassNames === Set("A" -> "A", "A" -> "A$")) - } - - it should "create binary names for top level companions" in { - val src = "class A; object A" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val binaryClassNames = compilerForTesting.extractBinaryClassNamesFromSrc(src) - - assert(binaryClassNames === Set("A" -> "A", "A" -> "A$")) - } - - it should "create correct binary names for nested object" in { - val src = - """|object A { - | object C { - | object D - | } - |} - |class B { - | object E - |} - """.stripMargin - - val compilerForTesting = new ScalaCompilerForUnitTesting - val binaryClassNames = compilerForTesting.extractBinaryClassNamesFromSrc(src) - - assert( - binaryClassNames === Set("A" -> "A$", - "A" -> "A", - "A.C" -> "A$C$", - "A.C.D" -> "A$C$D$", - "B" -> "B", - "B.E" -> "B$E$")) - } - - it should "create a binary name for a trait" in { - val src = - """|trait A - """.stripMargin - - val compilerForTesting = new ScalaCompilerForUnitTesting - val binaryClassNames = compilerForTesting.extractBinaryClassNamesFromSrc(src) - - // we do not track $impl classes because nobody can depend on them directly - assert(binaryClassNames === Set("A" -> "A")) - } - - it should "not create binary names for local classes" in { - val src = """ - |class Container { - | def foo = { - | class C - | } - | def bar = { - | // anonymous class - | new T {} - | } - |} - | - |trait T - |""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val binaryClassNames = compilerForTesting.extractBinaryClassNamesFromSrc(src) - assert(binaryClassNames === Set("Container" -> "Container", "T" -> "T")) - } - -} diff --git a/src/test/scala/xsbt/DependencySpecification.scala b/src/test/scala/xsbt/DependencySpecification.scala deleted file mode 100644 index f529163f8d49..000000000000 --- a/src/test/scala/xsbt/DependencySpecification.scala +++ /dev/null @@ -1,220 +0,0 @@ -package xsbt - -import xsbti.TestCallback.ExtractedClassDependencies -import sbt.internal.inc.UnitSpec - -class DependencySpecification extends UnitSpec { - - "Dependency phase" should "extract class dependencies from public members" in { - val classDependencies = extractClassDependenciesPublic - val memberRef = classDependencies.memberRef - val inheritance = classDependencies.inheritance - assert(memberRef("A") === Set.empty) - assert(inheritance("A") === Set.empty) - assert(memberRef("B") === Set("A", "D")) - assert(inheritance("B") === Set("D")) - assert(memberRef("C") === Set("A")) - assert(inheritance("C") === Set.empty) - assert(memberRef("D") === Set.empty) - assert(inheritance("D") === Set.empty) - assert(memberRef("E") === Set.empty) - assert(inheritance("E") === Set.empty) - assert(memberRef("F") === Set("A", "B", "D", "E", "G", "C")) // C is the underlying type of MyC - assert(inheritance("F") === Set("A", "E")) - assert(memberRef("H") === Set("B", "E", "G")) - // aliases and applied type constructors are expanded so we have inheritance dependency on B - assert(inheritance("H") === Set("B", "E")) - } - - it should "extract class dependencies from local members" in { - val classDependencies = extractClassDependenciesLocal - val memberRef = classDependencies.memberRef - val inheritance = classDependencies.inheritance - val localInheritance = classDependencies.localInheritance - assert(memberRef("A") === Set.empty) - assert(inheritance("A") === Set.empty) - assert(memberRef("B") === Set.empty) - assert(inheritance("B") === Set.empty) - assert(memberRef("C.Inner1") === Set("A")) - assert(inheritance("C.Inner1") === Set("A")) - assert(memberRef("D") === Set("B")) - assert(inheritance("D") === Set.empty) - assert(localInheritance("D") === Set("B")) - assert(memberRef("E") === Set("B")) - assert(inheritance("E") === Set.empty) - assert(localInheritance("E") === Set("B")) - } - - it should "extract class dependencies with trait as first parent" in { - val classDependencies = extractClassDependenciesTraitAsFirstPatent - val memberRef = classDependencies.memberRef - val inheritance = classDependencies.inheritance - assert(memberRef("A") === Set.empty) - assert(inheritance("A") === Set.empty) - assert(memberRef("B") === Set("A")) - assert(inheritance("B") === Set("A")) - // verify that memberRef captures the oddity described in documentation of `Relations.inheritance` - // we are mainly interested whether dependency on A is captured in `memberRef` relation so - // the invariant that says that memberRef is superset of inheritance relation is preserved - assert(memberRef("C") === Set("A", "B")) - assert(inheritance("C") === Set("A", "B")) - // same as above but indirect (C -> B -> A), note that only A is visible here - assert(memberRef("D") === Set("A", "C")) - assert(inheritance("D") === Set("A", "C")) - } - - it should "extract class dependencies from macro arguments" in { - val classDependencies = extractClassDependenciesFromMacroArgument - val memberRef = classDependencies.memberRef - val inheritance = classDependencies.inheritance - - assert(memberRef("A") === Set("B", "C")) - assert(inheritance("A") === Set.empty) - assert(memberRef("B") === Set.empty) - assert(inheritance("B") === Set.empty) - assert(memberRef("C") === Set.empty) - assert(inheritance("C") === Set.empty) - } - - it should "extract class dependencies from a refinement" in { - val srcFoo = - "object Outer {\n class Inner { type Xyz }\n\n type TypeInner = Inner { type Xyz = Int }\n}" - val srcBar = "object Bar {\n def bar: Outer.TypeInner = null\n}" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val classDependencies = - compilerForTesting.extractDependenciesFromSrcs(srcFoo, srcBar) - - val memberRef = classDependencies.memberRef - val inheritance = classDependencies.inheritance - assert(memberRef("Outer") === Set.empty) - assert(inheritance("Outer") === Set.empty) - assert(memberRef("Bar") === Set("Outer", "Outer.Inner")) - assert(inheritance("Bar") === Set.empty) - } - - it should "extract class dependency on a object correctly" in { - val srcA = - """object A { - | def foo = { B; () } - |}""".stripMargin - val srcB = "object B" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val classDependencies = - compilerForTesting.extractDependenciesFromSrcs(srcA, srcB) - - val memberRef = classDependencies.memberRef - val inheritance = classDependencies.inheritance - assert(memberRef("A") === Set("B")) - assert(inheritance("A") === Set.empty) - assert(memberRef("B") === Set.empty) - assert(inheritance("B") === Set.empty) - } - - it should "handle top level import dependencies" in { - val srcA = - """ - |package abc - |object A { - | class Inner - |} - |class A2""".stripMargin - val srcB = "import abc.A; import abc.A.Inner; class B" - val srcC = "import abc.{A, A2}; class C" - val srcD = "import abc.{A2 => Foo}; class D" - val srcE = "import abc.A._; class E" - val srcF = "import abc._; class F" - val srcG = - """|package foo { - | package bar { - | import abc.A - | class G - | } - |} - """.stripMargin - val srcH = "class H { import abc.A }" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val deps = compilerForTesting - .extractDependenciesFromSrcs(srcA, srcB, srcC, srcD, srcE, srcF, srcG, srcH) - .memberRef - - assert(deps("A") === Set.empty) - assert(deps("B") === Set("abc.A", "abc.A.Inner")) - assert(deps("C") === Set("abc.A", "abc.A2")) - assert(deps("D") === Set("abc.A2")) - assert(deps("E") === Set("abc.A")) - assert(deps("F") === Set.empty) - assert(deps("foo.bar.G") === Set("abc.A")) - assert(deps("H") === Set("abc.A")) - } - - private def extractClassDependenciesPublic: ExtractedClassDependencies = { - val srcA = "class A" - val srcB = "class B extends D[A]" - val srcC = """|class C { - | def a: A = null - |}""".stripMargin - val srcD = "class D[T]" - val srcE = "trait E[T]" - val srcF = "trait F extends A with E[D[B]] { self: G.MyC => }" - val srcG = "object G { type T[x] = B ; type MyC = C }" - // T is a type constructor [x]B - // B extends D - // E verifies the core type gets pulled out - val srcH = "trait H extends G.T[Int] with (E[Int] @unchecked)" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val classDependencies = - compilerForTesting.extractDependenciesFromSrcs(srcA, srcB, srcC, srcD, srcE, srcF, srcG, srcH) - classDependencies - } - - private def extractClassDependenciesLocal: ExtractedClassDependencies = { - val srcA = "class A" - val srcB = "class B" - val srcC = "class C { private class Inner1 extends A }" - val srcD = "class D { def foo: Unit = { class Inner2 extends B } }" - val srcE = "class E { def foo: Unit = { new B {} } }" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val classDependencies = - compilerForTesting.extractDependenciesFromSrcs(srcA, srcB, srcC, srcD, srcE) - classDependencies - } - - private def extractClassDependenciesTraitAsFirstPatent: ExtractedClassDependencies = { - val srcA = "class A" - val srcB = "trait B extends A" - val srcC = "trait C extends B" - val srcD = "class D extends C" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val classDependencies = - compilerForTesting.extractDependenciesFromSrcs(srcA, srcB, srcC, srcD) - classDependencies - } - - private def extractClassDependenciesFromMacroArgument: ExtractedClassDependencies = { - val srcA = "class A { println(B.printTree(C.foo)) }" - val srcB = """ - |import scala.language.experimental.macros - |import scala.reflect.macros._ - |object B { - | def printTree(arg: Any) = macro printTreeImpl - | def printTreeImpl(c: Context)(arg: c.Expr[Any]): c.Expr[String] = { - | val argStr = arg.tree.toString - | val literalStr = c.universe.Literal(c.universe.Constant(argStr)) - | c.Expr[String](literalStr) - | } - |}""".stripMargin - val srcC = "object C { val foo = 1 }" - - val compilerForTesting = new ScalaCompilerForUnitTesting - val classDependencies = - compilerForTesting.extractDependenciesFromSrcs(List(List(srcB, srcC), List(srcA))) - classDependencies - } - -} diff --git a/src/test/scala/xsbt/ExtractAPISpecification.scala b/src/test/scala/xsbt/ExtractAPISpecification.scala deleted file mode 100644 index 697a44145817..000000000000 --- a/src/test/scala/xsbt/ExtractAPISpecification.scala +++ /dev/null @@ -1,206 +0,0 @@ -package xsbt - -import xsbti.api._ -import xsbt.api.SameAPI -import sbt.internal.inc.UnitSpec - -class ExtractAPISpecification extends UnitSpec { - - "ExtractAPI" should "give stable names to members of existential types in method signatures" in stableExistentialNames() - - it should "extract children of a sealed class" in { - def compileAndGetFooClassApi(src: String): ClassLike = { - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src) - val FooApi = apis.find(_.name() == "Foo").get - FooApi - } - val src1 = - """|sealed abstract class Foo - |case class C1(x: Int) extends Foo - |""".stripMargin - val fooClassApi1 = compileAndGetFooClassApi(src1) - val src2 = - """|sealed abstract class Foo - |case class C1(x: Int) extends Foo - |case class C2(x: Int) extends Foo - |""".stripMargin - val fooClassApi2 = compileAndGetFooClassApi(src2) - assert(SameAPI(fooClassApi1, fooClassApi2) !== true) - } - - it should "extract correctly the definition type of a package object" in { - val src = "package object foo".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src) - val Seq(fooClassApi) = apis.toSeq - assert(fooClassApi.definitionType === DefinitionType.PackageModule) - } - - it should "extract nested classes" in { - val src = - """class A { - | class B - |}""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src).map(c => c.name -> c).toMap - assert(apis.keys === Set("A", "A.B")) - } - - it should "not extract local classes" in { - val src = - """class A - |class B - |class C { def foo: Unit = { class Inner2 extends B } } - |class D { def foo: Unit = { new B {} } }""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src).map(c => c.name -> c).toMap - assert(apis.keys === Set("A", "B", "C", "D")) - } - - it should "extract flat (without members) api for a nested class" in { - def compileAndGetFooClassApi(src: String): ClassLike = { - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src) - val FooApi = apis.find(_.name() == "Foo").get - FooApi - } - val src1 = - """class Foo { - | class A - |}""".stripMargin - val fooClassApi1 = compileAndGetFooClassApi(src1) - val src2 = - """class Foo { - | class A { - | def foo: Int = 123 - | } - |}""".stripMargin - val fooClassApi2 = compileAndGetFooClassApi(src2) - assert(SameAPI(fooClassApi1, fooClassApi2) === true) - } - - it should "extract private classes" in { - val src = - """private class A - |class B { private class Inner1 extends A } - |""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src).map(c => c.name -> c).toMap - assert(apis.keys === Set("A", "B", "B.Inner1")) - } - - def stableExistentialNames(): Unit = { - def compileAndGetFooMethodApi(src: String): Def = { - val compilerForTesting = new ScalaCompilerForUnitTesting - val sourceApi = compilerForTesting.extractApisFromSrc(src) - val FooApi = sourceApi.find(_.name() == "Foo").get - val fooMethodApi = FooApi.structure().declared().find(_.name == "foo").get - fooMethodApi.asInstanceOf[Def] - } - val src1 = """ - |class Box[T] - |class Foo { - | def foo: Box[_] = null - | - }""".stripMargin - val fooMethodApi1 = compileAndGetFooMethodApi(src1) - val src2 = """ - |class Box[T] - |class Foo { - | def bar: Box[_] = null - | def foo: Box[_] = null - | - }""".stripMargin - val fooMethodApi2 = compileAndGetFooMethodApi(src2) - assert(SameAPI.apply(fooMethodApi1, fooMethodApi2), "APIs are not the same.") - () - } - - /** - * 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. - */ - it should "make a stable representation of a self variable that has no self type" in { - def selectNamer(apis: Set[ClassLike]): ClassLike = { - // TODO: this doesn't work yet because inherited classes are not extracted - apis.find(_.name == "Global.Foo.Namer").get - } - 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) - assert(SameAPI(namerApi1, namerApi2)) - } - - it should "make a different representation for an inherited class" in { - val src = - """|class A[T] { - | abstract class AA { def t: T } - |} - |class B extends A[Int] - """.stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src).map(a => a.name -> a).toMap - assert(apis.keySet === Set("A", "A.AA", "B", "B.AA")) - assert(apis("A.AA") !== apis("B.AA")) - } - - it should "handle package objects and type companions" in { - val src = - """|package object abc { - | type BuildInfoKey = BuildInfoKey.Entry[_] - | object BuildInfoKey { - | sealed trait Entry[A] - | } - |} - """.stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting.extractApisFromSrc(src).map(a => a.name -> a).toMap - assert(apis.keySet === Set("abc.package", "abc.BuildInfoKey", "abc.BuildInfoKey.Entry")) - } - - /** - * Checks if self type is properly extracted in various cases of declaring a self type - * with our without a self variable. - */ - it should "represent a self type correctly" in { - 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 { _ => }" - val srcC8 = "class C8 { self => }" - val compilerForTesting = new ScalaCompilerForUnitTesting - val apis = compilerForTesting - .extractApisFromSrcs(reuseCompilerInstance = true)( - List(srcX, srcY, srcC1, srcC2, srcC3, srcC4, srcC5, srcC6, srcC7, srcC8) - ) - .map(_.head) - val emptyType = EmptyType.of() - def hasSelfType(c: ClassLike): Boolean = - c.selfType != emptyType - val (withSelfType, withoutSelfType) = apis.partition(hasSelfType) - assert(withSelfType.map(_.name).toSet === Set("C3", "C4", "C5", "C6")) - assert(withoutSelfType.map(_.name).toSet === Set("X", "Y", "C1", "C2", "C7", "C8")) - } -} diff --git a/src/test/scala/xsbt/ExtractUsedNamesPerformanceSpecification.scala b/src/test/scala/xsbt/ExtractUsedNamesPerformanceSpecification.scala deleted file mode 100644 index 1a61fa925fe3..000000000000 --- a/src/test/scala/xsbt/ExtractUsedNamesPerformanceSpecification.scala +++ /dev/null @@ -1,115 +0,0 @@ -package xsbt - -import java.net.URI -import java.nio.file.FileSystem -import java.nio.file.FileSystemNotFoundException -import java.nio.file.FileSystems -import java.nio.file.Files -import java.nio.file.Paths - -import sbt.internal.inc.UnitSpec - -class ExtractUsedNamesPerformanceSpecification extends UnitSpec { - private def initFileSystem(uri: URI): Option[FileSystem] = { - try Option(FileSystems.getFileSystem(uri)) - catch { - case _: FileSystemNotFoundException => - val env = Map("create" -> "true") - import scala.collection.JavaConverters._ - Option(FileSystems.newFileSystem(uri, env.asJava)) - case _: IllegalArgumentException => - Option(FileSystems.getDefault) - } - } - - val TestResource = "/ExtractUsedNamesPerformance.scala.source" - // Some difference between 2.10, 2.11, and 2.12 - val scalaDiff = Set("Any", "Nothing", "_root_", "StringAdd", "Option") - - it should "be executed in reasonable time" in { - var zipfs: Option[FileSystem] = None - val src = try { - val fileUri = getClass.getResource(TestResource).toURI - zipfs = initFileSystem(fileUri) - new String(Files.readAllBytes(Paths.get(fileUri))) - } finally zipfs.foreach { fs => - try fs.close() - catch { case _: Throwable => /*ignore*/ } - } - import org.scalatest.concurrent.Timeouts._ - import org.scalatest.time.SpanSugar._ - val usedNames = failAfter(30 seconds) { - val compilerForTesting = new ScalaCompilerForUnitTesting - compilerForTesting.extractUsedNamesFromSrc(src) - } - // format: off - val expectedNamesForTupler = Set("java;lang;Object;init;", "Object", "scala", "tupler", "TuplerInstances", "DepFn1", "HNil", "$anon", "Out", "Out0", "Tupler", "acme;Tupler;$anon;init;", "hnilTupler", "acme", "L", "Aux", "HList", "Serializable", "Unit") - val expectedNamesForTuplerInstances = Set("E", "Tuple4", "e", "case7", "Tuple15", "s", "case19", "T7", "x", "TuplerInstances", "matchEnd19", "T20", "Tuple11", "HNil", "matchEnd6", "p16", "$anon", "T19", "p20", "T2", "p10", "case22", "p19", "n", "Tuple12", "case11", "Tuple22", "p12", "matchEnd7", "N", "p4", "T13", "case26", "Tuple19", "p7", "p5", "j", "Out", "T", "p23", "case15", "matchEnd20", "t", "p21", "matchEnd15", "J", "head", "case13", "u", "matchEnd18", "U", "Tupler", "f", "T8", "T16", "F", "Tuple3", "case8", "case18", "case24", "Boolean", "matchEnd21", "A", "matchEnd26", "a", "Tuple14", "T1", "::", "Nothing", "p18", "case20", "m", "matchEnd10", "M", "matchEnd25", "tail", "Tuple2", "matchEnd5", "p15", "matchEnd23", "I", "i", "matchEnd14", "AnyRef", "Tuple8", "matchEnd8", "case25", "T12", "p3", "case14", "case23", "T5", "matchEnd22", "T17", "v", "p22", "Tuple18", "G", "Tuple13", "matchEnd12", "scala;MatchError;init;", "acme;TuplerInstances;$anon;init;", "java;lang;Object;init;", "V", "q", "p11", "Q", "case12", "L", "b", "apply", "Object", "g", "B", "l", "==", "Out0", "Tuple1", "matchEnd9", "P", "p2", "T15", "Aux", "matchEnd24", "p", "scala", "matchEnd11", "Tuple20", "HList", "case17", "T9", "p14", "Tuple7", "matchEnd17", "T4", "case28", "T22", "p17", "C", "Tuple6", "MatchError", "T11", "x1", "H", "case16", "matchEnd13", "c", "Tuple9", "h", "T6", "T18", "r", "K", "Tuple17", "p9", "R", "ne", "T14", "case21", "k", "case10", "Tuple21", "O", "case9", "Tuple10", "Any", "T10", "case27", "Tuple5", "D", "p13", "o", "p6", "p8", "matchEnd16", "S", "T21", "Tuple16", "d", "T3") - val expectedNamesForRefinement = Set("Out0") - val `expectedNamesFor::` = Set("x", "T2", "ScalaRunTime", "Iterator", "T", "head", "asInstanceOf", "Boolean", "A", "$" + "isInstanceOf", "T1", "||", "acme;::;init;", "::", "Nothing", "x$1", "any2stringadd", "acme", "typedProductIterator", "tail", "Tuple2", "AnyRef", "isInstanceOf", "Int", "java;lang;Object;init;", "_hashCode", "apply", "Object", "x$0", "==", "Some", "IndexOutOfBoundsException", "java;lang;IndexOutOfBoundsException;init;", "T0", "Predef", "scala", "matchEnd4", "HList", "None", "x1", "toString", "H", "+", "&&", "Serializable", "Product", "case6", "::$1", "eq", "Any", "runtime", "String") - val expectedNamesForDepFn1 = Set("DepFn1", "Out", "T", "AnyRef", "Object", "scala") - val expectedNamesForHNil = Set("x", "HNil", "ScalaRunTime", "Iterator", "Boolean", "A", "T", "$" + "isInstanceOf", "::", "Nothing", "x$1", "acme", "typedProductIterator", "Int", "java;lang;Object;init;", "apply", "Object", "IndexOutOfBoundsException", "java;lang;IndexOutOfBoundsException;init;", "scala", "HList", "toString", "H", "Serializable", "h", "Product", "Any", "runtime", "matchEnd3", "String", "T0") - val expectedNamesForHList = Set("Tupler", "acme", "scala", "Serializable", "Product") - // format: on - assert(usedNames("acme.Tupler") -- scalaDiff === expectedNamesForTupler -- scalaDiff) - assert( - usedNames("acme.TuplerInstances") -- scalaDiff === expectedNamesForTuplerInstances -- scalaDiff) - assert( - usedNames("acme.TuplerInstances.") -- scalaDiff === expectedNamesForRefinement -- scalaDiff) - assert(usedNames("acme.$colon$colon") -- scalaDiff === `expectedNamesFor::` -- scalaDiff) - assert(usedNames("acme.DepFn1") -- scalaDiff === expectedNamesForDepFn1 -- scalaDiff) - assert(usedNames("acme.HNil") -- scalaDiff === expectedNamesForHNil -- scalaDiff) - assert(usedNames("acme.HList") -- scalaDiff === expectedNamesForHList -- scalaDiff) - } - - it should "correctly find Out0 (not stored in inspected trees) both in TuplerInstances and TuplerInstances." in { - val src = """|sealed trait HList extends Product with Serializable - |trait DepFn1[T] { - | type Out - | def apply(t: T): Out - |} - |trait Tupler[L <: HList] extends DepFn1[L] with Serializable - |trait TuplerInstances { - | type Aux[L <: HList, Out0] = Tupler[L] { type Out = Out0 } - |}""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(src) - val expectedNamesForTuplerInstances = - Set("Tupler", "AnyRef", "L", "Out0", "scala", "HList", "Object") - val expectedNamesForTuplerInstancesRefinement = Set("Out0") - assert( - usedNames("TuplerInstances") -- scalaDiff === expectedNamesForTuplerInstances -- scalaDiff) - assert( - usedNames("TuplerInstances.") -- scalaDiff === expectedNamesForTuplerInstancesRefinement -- scalaDiff) - } - - it should "correctly collect used names from macro extension" in { - pending - val ext = """|package acme - |import scala.reflect.macros.blackbox.Context - | - |object Foo { - | def foo_impl[A](c: Context)(implicit atag: c.WeakTypeTag[A]): c.Expr[List[A]] = { - | import c.universe._ - | reify { List.empty[A] } - | } - |}""".stripMargin - val cod = """|package acme - |import scala.language.experimental.macros - | - |class Bar { - | def bar[Out] = macro Foo.foo_impl[Out] - |}""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val (_, analysis) = - compilerForTesting.compileSrcs(List(List(ext), List(cod)), reuseCompilerInstance = true) - val usedNames = analysis.usedNames.toMap - - // format: off - val expectedNamesForFoo = Set("TypeApplyExtractor", "mkIdent", "package", "", "tpe", "in", "$u", "internal", "reify", "WeakTypeTag", "Name", "empty", "collection", "ThisType", "staticModule", "staticPackage", "Singleton", "T", "asInstanceOf", "ReificationSupportApi", "U", "Expr", "Universe", "TypeApply", "A", "Tree", "Nothing", "acme", "ClassSymbol", "blackbox", "AnyRef", "Context", "mkTypeTree", "immutable", "SelectExtractor", "java.lang.Object.init;", "$treecreator1", "apply", "Object", "macros", "moduleClass", "Foo", "T0", "Symbol", "Predef", "scala", "asModule", "Internal", "$m", "TypeCreator", "TermNameExtractor", "ModuleSymbol", "staticClass", "universe", "c", "", "TypeTree", "List", "Select", "TermName", "Mirror", "atag", "reificationSupport", "rootMirror", "reflect", "TypeRef", "Ident", "Any", "TreeCreator", "$typecreator2", "$m$untyped", "String", "Type") - val expectedNamesForBar = Set("experimental", "package", "WeakTypeTag", "Out", "foo_impl", "Expr", "A", "Nothing", "acme", "AnyRef", "Context", "java;lang;Object;init;", "language", "Object", "macros", "Bar", "Foo", "scala", "List", "Any") - // format: on - assert(usedNames("acme.Foo") === expectedNamesForFoo) - assert(usedNames("acme.Bar") === expectedNamesForBar) - } -} diff --git a/src/test/scala/xsbt/ExtractUsedNamesSpecification.scala b/src/test/scala/xsbt/ExtractUsedNamesSpecification.scala deleted file mode 100644 index e77e30146221..000000000000 --- a/src/test/scala/xsbt/ExtractUsedNamesSpecification.scala +++ /dev/null @@ -1,307 +0,0 @@ -package xsbt - -import sbt.internal.inc.UnitSpec -import xsbti.UseScope - -class ExtractUsedNamesSpecification extends UnitSpec { - - "Used names extraction" should "extract imported name" in { - val src = """package a { class A } - |package b { - | import a.{A => A2} - |}""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(src) - val expectedNames = standardNames ++ Set("a", "A", "A2", "b") - // names used at top level are attributed to the first class defined in a compilation unit - - assert(usedNames("a.A") === expectedNames) - } - - // test covers https://github.com/gkossakowski/sbt/issues/6 - it should "extract names in type tree" in { - val srcA = """|package a { - | class A { - | class C { class D } - | } - | class B[T] - |} - |package c { - | class BB - |} - | - |""".stripMargin - val srcB = """|package b { - | abstract class X { - | def foo: a.A#C#D - | def bar: a.B[c.BB] - | } - |}""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB) - val expectedNames = standardNames ++ Set("a", "c", "A", "B", "C", "D", "b", "X", "BB") - assert(usedNames("b.X") === expectedNames) - } - - // test for https://github.com/gkossakowski/sbt/issues/5 - it should "extract symbolic names" in { - val srcA = """|class A { - | def `=`: Int = 3 - |}""".stripMargin - val srcB = """|class B { - | def foo(a: A) = a.`=` - |}""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB) - val expectedNames = standardNames ++ Set("A", "a", "B", "=", "Int") - assert(usedNames("B") === expectedNames) - } - - it should "extract type names for objects depending on abstract types" in { - val srcA = - """abstract class A { - | type T - | object X { - | def foo(x: T): T = x - | } - |} - """.stripMargin - val srcB = "class B extends A { type T = Int }" - val srcC = "object C extends B" - val srcD = "object D { C.X.foo(12) }" - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB, srcC, srcD) - val scalaVersion = scala.util.Properties.versionNumberString - // TODO: Find out what's making these types appear in 2.10 - // They don't come from type dependency traverser, but from `addSymbol` - val versionDependentNames = - if (scalaVersion.contains("2.10")) Set("Nothing", "Any") else Set() - val namesA = standardNames ++ Set("A") ++ versionDependentNames - val namesAX = standardNames ++ Set("X", "x", "T", "A") - val namesB = Set("B", "A", "Int", "A;init;", "scala") - val namesC = Set("B;init;", "C", "B") - val namesD = standardNames ++ Set("D", "C", "X", "foo", "Int", "T") - assert(usedNames("A") === namesA) - assert(usedNames("A.X") === namesAX) - assert(usedNames("B") === namesB) - assert(usedNames("C") === namesC) - assert(usedNames("D") === namesD) - } - - // See source-dependencies/types-in-used-names-a for an example where - // this is required. - it should "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_lista { - | val x = B.lista - |} - |object Test_at { - | val x = B.at - |} - |object Test_as { - | val x = B.as - |} - |object Test_foo { - | val x = B.foo(???) - |} - |object Test_bar { - | val x = B.bar(???) - |} - |""".stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(src1, src2) - val expectedNames_lista = standardNames ++ Set("Test_lista", "x", "B", "lista", "List", "A") - val expectedNames_at = standardNames ++ Set("Test_at", "x", "B", "at", "A", "T", "X0", "X1") - val expectedNames_as = standardNames ++ Set("Test_as", "x", "B", "as", "S", "Y") - val expectedNames_foo = standardNames ++ Set("Test_foo", - "x", - "B", - "foo", - "M", - "N", - "Predef", - "???", - "Nothing") - val expectedNames_bar = standardNames ++ Set("Test_bar", - "x", - "B", - "bar", - "Param", - "P1", - "P0", - "Predef", - "???", - "Nothing") - assert(usedNames("Test_lista") === expectedNames_lista) - assert(usedNames("Test_at") === expectedNames_at) - assert(usedNames("Test_as") === expectedNames_as) - assert(usedNames("Test_foo") === expectedNames_foo) - assert(usedNames("Test_bar") === expectedNames_bar) - } - - it should "extract used names from an existential" in { - val srcFoo = - """import scala.language.existentials - |class Foo { - | val foo: T forSome { type T <: Double } = ??? - |} - """.stripMargin - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcFoo) - val expectedNames = standardNames ++ Seq("Double", - "Foo", - "T", - "foo", - "scala", - "language", - "existentials", - "Nothing", - "???", - "Predef") - assert(usedNames("Foo") === expectedNames) - } - - it should "extract used names from a refinement" in { - val srcFoo = - "object Outer {\n class Inner { type Xyz }\n\n type TypeInner = Inner { type Xyz = Int }\n}" - val srcBar = "object Bar {\n def bar: Outer.TypeInner = null\n}" - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcFoo, srcBar) - val expectedNames = standardNames ++ Set("Bar", "Outer", "TypeInner", "Inner", "Xyz", "Int") - assert(usedNames("Bar") === expectedNames) - } - - // test for https://github.com/gkossakowski/sbt/issues/3 - it should "extract used names from the same compilation unit" in { - val src = "class A { def foo: Int = 0; def bar: Int = foo }" - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(src) - val expectedNames = standardNames ++ Set("A", "foo", "Int") - assert(usedNames("A") === expectedNames) - } - - // pending test for https://issues.scala-lang.org/browse/SI-7173 - it should "extract names of constants" in pendingUntilFixed { - val src = "class A { final val foo = 12; def bar: Int = foo }" - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(src) - val expectedNames = standardNames ++ Set("A", "foo", "Int") - assert(usedNames === expectedNames) - () - } - - // test for https://github.com/gkossakowski/sbt/issues/4 - // TODO: we should fix it by having special treatment of `selectDynamic` and `applyDynamic` calls - it should "extract names from method calls on Dynamic" in pendingUntilFixed { - val srcA = """|import scala.language.dynamics - |class A extends Dynamic { - | def selectDynamic(name: String): Int = name.length - |}""".stripMargin - val srcB = "class B { def foo(a: A): Int = a.bla }" - val compilerForTesting = new ScalaCompilerForUnitTesting - val usedNames = compilerForTesting.extractUsedNamesFromSrc(srcA, srcB) - val expectedNames = standardNames ++ Set("B", "A", "a", "Int", "selectDynamic", "bla") - assert(usedNames === expectedNames) - () - } - - it should "extract sealed classes scope" in { - val sealedClassName = "Sealed" - val sealedClass = - s"""package base - | - |sealed class $sealedClassName - |object Usage extends $sealedClassName - |object Usage2 extends $sealedClassName - """.stripMargin - - def findPatMatUsages(in: String): Set[String] = { - val compilerForTesting = new ScalaCompilerForUnitTesting - val (_, callback) = - compilerForTesting.compileSrcs(List(List(sealedClass, in)), reuseCompilerInstance = false) - val clientNames = callback.usedNamesAndScopes.filterKeys(!_.startsWith("base.")) - - val names: Set[String] = clientNames.flatMap { - case (_, usages) => - usages.filter(_.scopes.contains(UseScope.PatMatTarget)).map(_.name) - }(collection.breakOut) - - names - } - - def classWithPatMatOfType(tpe: String = sealedClassName) = - s"""package client - |import base._ - | - |class test(a: $tpe) { - | a match { - | case _ => 1 - | } - |} - """.stripMargin - - findPatMatUsages(classWithPatMatOfType()) shouldEqual Set(sealedClassName) - // Option is sealed - findPatMatUsages(classWithPatMatOfType(s"Option[$sealedClassName]")) shouldEqual Set( - sealedClassName, - "Option") - // Seq and Set is not - findPatMatUsages(classWithPatMatOfType(s"Seq[Set[$sealedClassName]]")) shouldEqual Set( - sealedClassName) - - def inNestedCase(tpe: String) = - s"""package client - |import base._ - | - |class test(a: Any) { - | a match { - | case _: $tpe => 1 - | } - |}""".stripMargin - - findPatMatUsages(inNestedCase(sealedClassName)) shouldEqual Set() - - val notUsedInPatternMatch = - s"""package client - |import base._ - | - |class test(a: Any) { - | a match { - | case _ => 1 - | } - | val aa: $sealedClassName = ??? - |}""".stripMargin - - findPatMatUsages(notUsedInPatternMatch) shouldEqual Set() - } - - /** - * Standard names that appear in every compilation unit that has any class - * definition. - */ - private val standardNames = Set( - "scala", - // The default parent of a class is "AnyRef" which is an alias for "Object" - "AnyRef", - "Object", - "java;lang;Object;init;" - ) - -} diff --git a/src/test/scala/xsbt/InteractiveConsoleInterfaceSpecification.scala b/src/test/scala/xsbt/InteractiveConsoleInterfaceSpecification.scala deleted file mode 100644 index 12f82dc22363..000000000000 --- a/src/test/scala/xsbt/InteractiveConsoleInterfaceSpecification.scala +++ /dev/null @@ -1,70 +0,0 @@ -package xsbt - -import sbt.internal.inc.UnitSpec -import sbt.util.Logger -import xsbti.InteractiveConsoleResult - -// This is a specification to check the REPL block parsing. -class InteractiveConsoleInterfaceSpecification extends UnitSpec { - - private val consoleFactory = new InteractiveConsoleFactory - - def consoleWithArgs(args: String*) = consoleFactory.createConsole( - args = args.toArray, - bootClasspathString = "", - classpathString = "", - initialCommands = "", - cleanupCommands = "", - loader = this.getClass.getClassLoader, - bindNames = Array.empty, - bindValues = Array.empty, - log = Logger.Null - ) - - private val consoleWithoutArgs = consoleWithArgs() - - "Scala interpreter" should "evaluate arithmetic expression" in { - val response = consoleWithoutArgs.interpret("1+1", false) - response.output.trim shouldBe "res0: Int = 2" - response.result shouldBe InteractiveConsoleResult.Success - } - - it should "evaluate list constructor" in { - val response = consoleWithoutArgs.interpret("List(1,2)", false) - response.output.trim shouldBe "res1: List[Int] = List(1, 2)" - response.result shouldBe InteractiveConsoleResult.Success - } - - it should "evaluate import" in { - val response = consoleWithoutArgs.interpret("import xsbt._", false) - response.output.trim shouldBe "import xsbt._" - response.result shouldBe InteractiveConsoleResult.Success - } - - it should "mark partial expression as incomplete" in { - val response = consoleWithoutArgs.interpret("val a =", false) - response.result shouldBe InteractiveConsoleResult.Incomplete - } - - it should "not evaluate incorrect expression" in { - val response = consoleWithoutArgs.interpret("1 ++ 1", false) - response.result shouldBe InteractiveConsoleResult.Error - } - - val postfixOpExpression = "import scala.concurrent.duration._\nval t = 1 second" - - it should "evaluate postfix op with a warning" in { - val response = consoleWithoutArgs.interpret(postfixOpExpression, false) - response.output.trim should startWith("warning") - response.result shouldBe InteractiveConsoleResult.Success - } - - private val consoleWithPostfixOps = consoleWithArgs("-language:postfixOps") - - it should "evaluate postfix op without warning when -language:postfixOps arg passed" in { - val response = consoleWithPostfixOps.interpret(postfixOpExpression, false) - response.output.trim should not startWith "warning" - response.result shouldBe InteractiveConsoleResult.Success - } - -} diff --git a/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala b/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala deleted file mode 100644 index 423d968c2066..000000000000 --- a/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala +++ /dev/null @@ -1,213 +0,0 @@ -package xsbt - -import xsbti.TestCallback.ExtractedClassDependencies -import xsbti.compile.SingleOutput -import java.io.File -import xsbti._ -import sbt.io.IO.withTemporaryDirectory -import xsbti.api.ClassLike - -import sbt.internal.util.ConsoleLogger -import xsbti.api.DependencyContext._ - -/** - * Provides common functionality needed for unit tests that require compiling - * source code using Scala compiler. - */ -class ScalaCompilerForUnitTesting { - - /** - * Compiles given source code using Scala compiler and returns API representation - * extracted by ExtractAPI class. - */ - def extractApisFromSrc(src: String): Set[ClassLike] = { - val (Seq(tempSrcFile), analysisCallback) = compileSrcs(src) - 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[Set[ClassLike]] = { - val (tempSrcFiles, analysisCallback) = compileSrcs(srcs.toList, reuseCompilerInstance) - tempSrcFiles.map(analysisCallback.apis) - } - - def extractUsedNamesFromSrc(src: String): Map[String, Set[String]] = { - val (_, analysisCallback) = compileSrcs(src) - analysisCallback.usedNames.toMap - } - - def extractBinaryClassNamesFromSrc(src: String): Set[(String, String)] = { - val (Seq(tempSrcFile), analysisCallback) = compileSrcs(src) - analysisCallback.classNames(tempSrcFile).toSet - } - - /** - * Extract used names from src provided as the second argument. - * If `assertDefaultScope` is set to true it will fail if there is any name used in scope other then Default - * - * The purpose of the first argument is to define names that the second - * source is going to refer to. Both files are compiled in the same compiler - * Run but only names used in the second src file are returned. - */ - def extractUsedNamesFromSrc( - definitionSrc: String, - actualSrc: String, - assertDefaultScope: Boolean = true - ): Map[String, Set[String]] = { - // we drop temp src file corresponding to the definition src file - val (Seq(_, tempSrcFile), analysisCallback) = compileSrcs(definitionSrc, actualSrc) - - if (assertDefaultScope) for { - (className, used) <- analysisCallback.usedNamesAndScopes - analysisCallback.TestUsedName(name, scopes) <- used - } assert(scopes.size() == 1 && scopes.contains(UseScope.Default), s"$className uses $name in $scopes") - - val classesInActualSrc = analysisCallback.classNames(tempSrcFile).map(_._1) - classesInActualSrc.map(className => className -> analysisCallback.usedNames(className)).toMap - } - - /** - * Extract used names from the last source file in `sources`. - * - * The previous source files are provided to successfully compile examples. - * Only the names used in the last src file are returned. - */ - def extractUsedNamesFromSrc(sources: String*): Map[String, Set[String]] = { - val (srcFiles, analysisCallback) = compileSrcs(sources: _*) - srcFiles - .map { srcFile => - val classesInSrc = analysisCallback.classNames(srcFile).map(_._1) - classesInSrc.map(className => className -> analysisCallback.usedNames(className)).toMap - } - .reduce(_ ++ _) - } - - /** - * Compiles given source code snippets (passed as Strings) using Scala compiler and returns extracted - * dependencies between snippets. Source code snippets are identified by symbols. Each symbol should - * be associated with one snippet only. - * - * Snippets can be grouped to be compiled together in the same compiler run. This is - * useful to compile macros, which cannot be used in the same compilation run that - * defines them. - * - * Symbols are used to express extracted dependencies between source code snippets. This way we have - * file system-independent way of testing dependencies between source code "files". - */ - def extractDependenciesFromSrcs(srcs: List[List[String]]): ExtractedClassDependencies = { - val (_, testCallback) = compileSrcs(srcs, reuseCompilerInstance = true) - - val memberRefDeps = testCallback.classDependencies collect { - case (target, src, DependencyByMemberRef) => (src, target) - } - val inheritanceDeps = testCallback.classDependencies collect { - case (target, src, DependencyByInheritance) => (src, target) - } - val localInheritanceDeps = testCallback.classDependencies collect { - case (target, src, LocalDependencyByInheritance) => (src, target) - } - ExtractedClassDependencies.fromPairs(memberRefDeps, inheritanceDeps, localInheritanceDeps) - } - - def extractDependenciesFromSrcs(srcs: String*): ExtractedClassDependencies = { - extractDependenciesFromSrcs(List(srcs.toList)) - } - - /** - * Compiles given source code snippets written to temporary files. Each snippet is - * written to a separate temporary file. - * - * Snippets can be grouped to be compiled together in the same compiler run. This is - * useful to compile macros, which cannot be used in the same compilation run that - * defines them. - * - * The `reuseCompilerInstance` parameter controls whether the same Scala compiler instance - * is reused between compiling source groups. Separate compiler instances can be used to - * test stability of API representation (with respect to pickling) or to test handling of - * binary dependencies. - * - * The sequence of temporary files corresponding to passed snippets and analysis - * callback is returned as a result. - */ - private[xsbt] def compileSrcs( - groupedSrcs: List[List[String]], - reuseCompilerInstance: Boolean - ): (Seq[File], TestCallback) = { - withTemporaryDirectory { temp => - val analysisCallback = new TestCallback - val classesDir = new File(temp, "classes") - classesDir.mkdir() - - lazy val commonCompilerInstance = - prepareCompiler(classesDir, analysisCallback, classesDir.toString) - - val files = for ((compilationUnit, unitId) <- groupedSrcs.zipWithIndex) yield { - // use a separate instance of the compiler for each group of sources to - // have an ability to test for bugs in instability between source and pickled - // representation of types - val compiler = - if (reuseCompilerInstance) commonCompilerInstance - else - prepareCompiler(classesDir, analysisCallback, classesDir.toString) - val run = new compiler.Run - val srcFiles = compilationUnit.zipWithIndex map { - case (src, i) => - val fileName = s"Test-$unitId-$i.scala" - prepareSrcFile(temp, fileName, src) - } - val srcFilePaths = srcFiles.map(srcFile => srcFile.getAbsolutePath).toList - - run.compile(srcFilePaths) - - srcFilePaths.foreach(f => new File(f).delete) - srcFiles - } - (files.flatten, analysisCallback) - } - } - - private def compileSrcs(srcs: String*): (Seq[File], TestCallback) = { - compileSrcs(List(srcs.toList), reuseCompilerInstance = true) - } - - private def prepareSrcFile(baseDir: File, fileName: String, src: String): File = { - val srcFile = new File(baseDir, fileName) - sbt.io.IO.write(srcFile, src) - srcFile - } - - private[xsbt] def prepareCompiler(outputDir: File, - analysisCallback: AnalysisCallback, - classpath: String = "."): ZincCompiler = { - val args = Array.empty[String] - object output extends SingleOutput { - def getOutputDirectory: File = outputDir - override def toString = s"SingleOutput($getOutputDirectory)" - } - val weakLog = new WeakLog(ConsoleLogger(), ConsoleReporter) - val cachedCompiler = new CachedCompiler0(args, output, weakLog) - val settings = cachedCompiler.settings - settings.classpath.value = classpath - settings.usejavacp.value = true - val delegatingReporter = DelegatingReporter(settings, ConsoleReporter) - val compiler = cachedCompiler.compiler - compiler.set(analysisCallback, delegatingReporter) - compiler - } - - private object ConsoleReporter extends Reporter { - def reset(): Unit = () - def hasErrors: Boolean = false - def hasWarnings: Boolean = false - def printWarnings(): Unit = () - def problems: Array[Problem] = Array.empty - def log(problem: Problem): Unit = println(problem.message()) - def comment(pos: Position, msg: String): Unit = () - def printSummary(): Unit = () - } - -}