Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Names from nonexisiting objects #422

Merged
merged 3 commits into from Jun 5, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions zinc/src/test/resources/sources/NoopMacroUsed.scala
@@ -0,0 +1,6 @@
import foo.NoopMacro // this import pull nonexisting object based on class NoopMacro
import scala.language.experimental.macros

class NoopMacroUsed {
def noop(arg: Int): Int = macro NoopMacro.noop
}
7 changes: 7 additions & 0 deletions zinc/src/test/resources/sources/foo/NoopMacro.scala
@@ -0,0 +1,7 @@
package foo

import scala.reflect.macros.blackbox.Context

class NoopMacro(val c: Context){
def noop(arg: c.Tree): c.Tree = arg
}
52 changes: 46 additions & 6 deletions zinc/src/test/scala/sbt/inc/BaseCompilerSpec.scala
Expand Up @@ -18,6 +18,7 @@ import sbt.io.IO
import sbt.io.syntax._
import sbt.util.{ InterfaceUtil, Logger }
import xsbti.compile.{ ScalaInstance => _, _ }
import xsbti.compile.FileAnalysisStore

class BaseCompilerSpec extends BridgeProviderSpecification {

Expand All @@ -32,7 +33,11 @@ class BaseCompilerSpec extends BridgeProviderSpecification {
Locate.definesClass(classpathEntry)
}

case class ProjectSetup(baseLocation: Path, sources: Map[Path, Seq[Path]], classPath: Seq[Path]) {
case class ProjectSetup(baseLocation: Path,
sources: Map[Path, Seq[Path]],
classPath: Seq[Path],
analysisForCp: Map[File, File] = Map.empty
) {
private def fromResource(prefix: Path)(path: Path): File = {
val fullPath = prefix.resolve(path).toString()
Option(getClass.getClassLoader.getResource(fullPath))
Expand All @@ -59,6 +64,8 @@ class BaseCompilerSpec extends BridgeProviderSpecification {
val target = classpathBase.resolve(zippedClassesPath.toString.dropRight(4)).toFile
IO.unzip(fromResource(binPrefix)(zippedClassesPath), target)
target
case existingFile if existingFile.isAbsolute && Files.exists(existingFile) =>
existingFile.toFile
case jarPath =>
val newJar = classpathBase.resolve(jarPath).toFile
IO.copyFile(fromResource(binPrefix)(jarPath), newJar)
Expand All @@ -70,19 +77,41 @@ class BaseCompilerSpec extends BridgeProviderSpecification {
def defaultStoreLocation: File = baseLocation.resolve("inc_data.zip").toFile

def createCompiler() =
CompilerSetup(defaultClassesDir, baseLocation.toFile, allSources.toArray, allClasspath)
CompilerSetup(defaultClassesDir,
baseLocation.toFile,
allSources.toArray,
allClasspath,
IncOptions.of(),
analysisForCp,
defaultStoreLocation
)

def update(source: Path)(change: String => String): Unit = {
import collection.JavaConverters._
val sourceFile = baseLocation.resolve(source)
val text = Files.readAllLines(sourceFile).asScala.mkString("\n")
Files.write(sourceFile, Seq(change(text)).asJava)
}

def dependsOnJarFrom(other: ProjectSetup): ProjectSetup = {
val sources = other.defaultClassesDir ** "*.class"
val mapping = sources.get.map{
file =>
file -> other.defaultClassesDir.toPath.relativize(file.toPath).toString
}
val dest = baseLocation.resolve("bin").resolve(s"${other.baseLocation.getFileName}.jar")
IO.zip(mapping, dest.toFile)

copy(
classPath = classPath :+ dest ,
analysisForCp = analysisForCp + (dest.toFile -> other.defaultStoreLocation)
)
}
}

object ProjectSetup {
def simple(baseLocation: Path, classes: Seq[String]): ProjectSetup =
ProjectSetup(baseLocation, Map(Paths.get("src") -> classes.map(path => Paths.get(path))), Nil)
ProjectSetup(baseLocation, Map(Paths.get("src") -> classes.map(path => Paths.get(path))), Nil, Map.empty)
}

def scalaCompiler(instance: xsbti.compile.ScalaInstance, bridgeJar: File): AnalyzingCompiler = {
Expand All @@ -97,7 +126,9 @@ class BaseCompilerSpec extends BridgeProviderSpecification {
tempDir: File,
sources: Array[File],
classpath: Seq[File],
incOptions: IncOptions = IncOptions.of()
incOptions: IncOptions,
analysisForCp: Map[File, File],
analysisStoreLocation: File
) {
val noLogger = Logger.Null
val compiler = new IncrementalCompilerImpl
Expand All @@ -107,7 +138,16 @@ class BaseCompilerSpec extends BridgeProviderSpecification {
val sc = scalaCompiler(si, compilerBridge)
val cs = compiler.compilers(si, ClasspathOptionsUtil.boot, None, sc)

val lookup = MockedLookup(Function.const(Optional.empty[CompileAnalysis]))
private def analysis(forEntry: File): Optional[CompileAnalysis] = {
analysisForCp.get(forEntry) match {
case Some(analysisStore) =>
FileAnalysisStore.getDefault(analysisStore).get().map(_.getAnalysis)
case _ =>
Optional.empty()
}
}

val lookup = MockedLookup(analysis)
val reporter = new ManagedLoggedReporter(maxErrors, log)
val extra = Array(InterfaceUtil.t2(("key", "value")))

Expand Down Expand Up @@ -144,7 +184,7 @@ class BaseCompilerSpec extends BridgeProviderSpecification {
compiler.compile(newInputs(in), log)
}

def doCompileWithStore(store: AnalysisStore,
def doCompileWithStore(store: AnalysisStore = FileAnalysisStore.getDefault(analysisStoreLocation),
newInputs: Inputs => Inputs = identity): CompileResult = {
import JavaInterfaceUtil.EnrichOptional
val previousResult = store.get().toOption match {
Expand Down
26 changes: 26 additions & 0 deletions zinc/src/test/scala/sbt/inc/BinaryDepSpec.scala
@@ -0,0 +1,26 @@
package sbt.inc

import sbt.internal.inc.Analysis
import sbt.io.IO

class BinaryDepSpec extends BaseCompilerSpec{
it should "not depend on non-existing objects" in {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this expectation true? What if you changed the macro? Shouldn't we invalidate the macro consumer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not change macro here we compile each project once.

We depend on NoopMacro but as a external dependency and we should not depended at the same time on it as library dependency (so we don't want recompile every usage of NoopMacro when we change anything in jar where it comes from)

IO.withTemporaryDirectory { tempDir =>
val basePath = tempDir.toPath.resolve("base")
val baseSetup = ProjectSetup.simple(basePath, Seq("foo/NoopMacro.scala"))
baseSetup.createCompiler().doCompileWithStore()

val projPath = tempDir.toPath.resolve("proj")
val projectSetup = ProjectSetup.simple(projPath, Seq("NoopMacroUsed.scala")).dependsOnJarFrom(baseSetup)

val result = projectSetup.createCompiler().doCompile()
result.analysis() match {
case analysis: Analysis =>
// We should not depend on jar creating from project that we depend on (since we've got analysis for it)
analysis.relations.libraryDep._2s
.filter(_.toPath.startsWith(projPath)) shouldBe 'empty

}
}
}
}
1 change: 0 additions & 1 deletion zinc/src/test/scala/sbt/inc/IncrementalCompilerSpec.scala
Expand Up @@ -57,5 +57,4 @@ class IncrementalCompilerSpec extends BaseCompilerSpec {
assert(result3.hasModified)
}
}

}