Skip to content

Commit

Permalink
Move Analyze and ClassToAPI specifications
Browse files Browse the repository at this point in the history
The b0a8a91 merge commit didn't resolve
merge conflicts for AnalyzeSpecification.scala and for
ClassToAPISpecifaction.scala. This commit oves them to the right
subprojects and adapts them to Scalatest APIs.

Both specifications depend on TestCallback so it had to be moved to a
subproject commonly referenced. I've moved it to the compiler-interface
subproject. As a consequence, I had to add a dependency on scala-library
in `test` configuration to compile TestCallback written in Scala.
  • Loading branch information
gkossakowski committed Mar 25, 2016
1 parent 8df9757 commit ae5d0fe
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 22 deletions.
6 changes: 3 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ lazy val compilerInterface = (project in internalPath / "compiler-interface").
// javaOnlySettings,
name := "Compiler Interface",
crossScalaVersions := Seq(scala211),
libraryDependencies ++= Seq(utilInterface),
libraryDependencies ++= Seq(utilInterface, scalaLibrary.value % Test),
exportJars := true,
watchSources <++= apiDefinitions,
resourceGenerators in Compile <+= (version, resourceManaged, streams, compile in Compile) map generateVersionFile,
Expand Down Expand Up @@ -203,7 +203,7 @@ lazy val compilerBridge: Project = (project in internalPath / "compiler-bridge")
// defines operations on the API of a source, including determining whether it has changed and converting it to a string
// and discovery of Projclasses and annotations
lazy val incrementalcompilerApiInfo = (project in internalPath / "incrementalcompiler-apiinfo").
dependsOn(compilerInterface, incrementalcompilerClassfile).
dependsOn(compilerInterface, incrementalcompilerClassfile % "compile;test->test").
settings(
testedBaseSettings,
name := "Incrementalcompiler ApiInfo"
Expand All @@ -222,7 +222,7 @@ lazy val incrementalcompilerClasspath = (project in internalPath / "incrementalc

// class file reader and analyzer
lazy val incrementalcompilerClassfile = (project in internalPath / "incrementalcompiler-classfile").
dependsOn(compilerInterface).
dependsOn(compilerInterface % "compile;test->test").
settings(
testedBaseSettings,
libraryDependencies ++= Seq(sbtIO, utilLogging),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package sbt
package internal
package inc

import java.io.File

import sbt.internal.inc.classfile.JavaCompilerForUnitTesting
import sbt.internal.util.UnitSpec
import xsbti.AnalysisCallback
import xsbti.api.{ ClassLike, DefinitionType }

class ClassToAPISpecification extends UnitSpec {

"ClassToAPI" should "extract api of inner classes" in {
val src =
"""|class A {
| class B {}
|}
""".stripMargin
val apis = extractApisFromSrc("A.java" -> src).map(c => c.name -> c).toMap
assert(apis.keySet === Set("A", "A.B"))

val companionsA = apis("A")
assert(companionsA.classApi.topLevel === true)
assert(companionsA.objectApi.topLevel === true)

val innerClassApiB = findDeclaredInnerClass(companionsA.classApi, "A.B", DefinitionType.ClassDef).get
assert(innerClassApiB.structure.declared === Array.empty)
assert(innerClassApiB.structure.inherited === Array.empty)

val companionsB = apis("A.B")
assert(companionsB.classApi.topLevel === false)
assert(companionsB.objectApi.topLevel === false)
assert(companionsB.classApi.structure.declared.isEmpty === false)
}

it should "extract a private inner class" in {
val src =
"""|class A {
| private class B {}
|}
""".stripMargin
val apis = extractApisFromSrc("A.java" -> src).map(c => c.name -> c).toMap
assert(apis.keySet === Set("A", "A.B"))
}

/**
* Compiles given source code using Java compiler and returns API representation
* extracted by ClassToAPI class.
*/
private def extractApisFromSrc(src: (String, String)): Set[Companions] = {
val (Seq(tempSrcFile), analysisCallback) = JavaCompilerForUnitTesting.compileJavaSrcs(src)(readAPI)
val apis = analysisCallback.apis(tempSrcFile)
apis.groupBy(_.name).map((companions _).tupled).toSet
}

private def companions(className: String, classes: Set[ClassLike]): Companions = {
assert(classes.size <= 2, s"Too many classes named $className: $classes")
def isClass(c: ClassLike) =
(c.definitionType == DefinitionType.Trait) || (c.definitionType == DefinitionType.ClassDef)
def isModule(c: ClassLike) =
(c.definitionType == DefinitionType.Module) || (c.definitionType == DefinitionType.PackageModule)
// the ClassToAPI always create both class and object APIs
val classApi = classes.find(isClass).get
val objectApi = classes.find(isModule).get
Companions(className, classApi, objectApi)
}

private case class Companions(name: String, classApi: ClassLike, objectApi: ClassLike)

private def findDeclaredInnerClass(classApi: ClassLike, innerClassName: String,
defType: DefinitionType): Option[ClassLike] = {
classApi.structure.declared.collectFirst({
case c: ClassLike if c.name == innerClassName && c.definitionType == defType => c
})
}

def readAPI(callback: AnalysisCallback, source: File, classes: Seq[Class[_]]): Set[(String, String)] = {
val (apis, inherits) = ClassToAPI.process(classes)
apis.foreach(callback.api(source, _))
inherits.map {
case (from: Class[_], to: Class[_]) => (from.getName, to.getName)
}
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package sbt.classfile
package sbt
package internal
package inc
package classfile

import org.junit.runner.RunWith
import org.specs2.mutable.Specification
import org.specs2.runner.JUnitRunner
import sbt.internal.util.UnitSpec

@RunWith(classOf[JUnitRunner])
class AnalyzeSpecification extends Specification {
class AnalyzeSpecification extends UnitSpec {

"dependencies of inner classes" in {
"Analyze" should "extract dependencies of inner classes" in {
val srcA =
"""class A {
| class B {
Expand All @@ -28,10 +28,10 @@ class AnalyzeSpecification extends Specification {
val deps = JavaCompilerForUnitTesting.
extractDependenciesFromSrcs("A.java" -> srcA, "C.java" -> srcC, "D.java" -> srcD)

deps.memberRef("A") === Set("A.B")
deps.memberRef("A.B") === Set("A", "D")
deps.memberRef("C") === Set("A", "A.B")
deps.memberRef("D") === Set.empty
assert(deps.memberRef("A") === Set("A.B"))
assert(deps.memberRef("A.B") === Set("A", "D"))
assert(deps.memberRef("C") === Set("A", "A.B"))
assert(deps.memberRef("D") === Set.empty)
}

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package sbt.classfile
package sbt
package internal
package inc
package classfile

import java.io.File
import java.net.URLClassLoader
import javax.tools.{ StandardLocation, ToolProvider }

import sbt.IO._
import sbt.{ ConsoleLogger, PathFinder }
import xsbti.DependencyContext._
import sbt.io.IO
import sbt.internal.util.ConsoleLogger
import xsbti.api.DependencyContext._
import xsbti.{ AnalysisCallback, TestCallback }
import xsbti.TestCallback.ExtractedClassDependencies

Expand All @@ -30,7 +33,7 @@ object JavaCompilerForUnitTesting {
}

def compileJavaSrcs(srcs: (String, String)*)(readAPI: (AnalysisCallback, File, Seq[Class[_]]) => Set[(String, String)]): (Seq[File], TestCallback) = {
withTemporaryDirectory { temp =>
IO.withTemporaryDirectory { temp =>
val srcFiles = srcs.map {
case (fileName, src) => prepareSrcFile(temp, fileName, src)
}
Expand All @@ -45,7 +48,7 @@ object JavaCompilerForUnitTesting {
compiler.getTask(null, fileManager, null, null, null, compilationUnits).call()
fileManager.close()

val classesFinder = PathFinder(classesDir) ** "*.class"
val classesFinder = sbt.io.PathFinder(classesDir) ** "*.class"
val classFiles = classesFinder.get

val classloader = new URLClassLoader(Array(classesDir.toURI.toURL))
Expand All @@ -63,7 +66,7 @@ object JavaCompilerForUnitTesting {

private def prepareSrcFile(baseDir: File, fileName: String, src: String): File = {
val srcFile = new File(baseDir, fileName)
sbt.IO.write(srcFile, src)
IO.write(srcFile, src)
srcFile
}

Expand Down
3 changes: 2 additions & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ object Dependencies {

lazy val launcherInterface = "org.scala-sbt" % "launcher-interface" % "1.0.0-M1"

lazy val scalaLibrary = Def.setting { "org.scala-lang" % "scala-compiler" % scalaVersion.value }
lazy val scalaCompiler = Def.setting { "org.scala-lang" % "scala-compiler" % scalaVersion.value }
lazy val scalaReflect = Def.setting { "org.scala-lang" % "scala-reflect" % scalaVersion.value }

Expand All @@ -31,7 +32,7 @@ object Dependencies {
lazy val scalatest = "org.scalatest" %% "scalatest" % "2.2.4"
lazy val specs2 = "org.specs2" %% "specs2" % "2.3.11"
lazy val junit = "junit" % "junit" % "4.11"
def testDependencies = Seq(libraryDependencies :=
def testDependencies = Seq(libraryDependencies ++=
Seq(
utilTesting % Test,
scalaCheck % Test,
Expand Down

0 comments on commit ae5d0fe

Please sign in to comment.