diff --git a/compiler/src/dotty/tools/backend/jvm/CodeGen.scala b/compiler/src/dotty/tools/backend/jvm/CodeGen.scala index 2286ad6c2c25..c5b0ec0929b8 100644 --- a/compiler/src/dotty/tools/backend/jvm/CodeGen.scala +++ b/compiler/src/dotty/tools/backend/jvm/CodeGen.scala @@ -133,8 +133,15 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)( if (ctx.compilerCallback != null) ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className) - if isLocal then - ctx.withIncCallback(_.generatedLocalClass(sourceFile, clsFile.jpath)) + ctx.withIncCallback: cb => + if isLocal then + cb.generatedLocalClass(sourceFile, clsFile.jpath) + else if !cb.enabled() then + // callback is not enabled, so nonLocalClasses were not reported in ExtractAPI + val fullClassName = atPhase(sbtExtractDependenciesPhase) { + ExtractDependencies.classNameAsString(claszSymbol) + } + cb.generatedNonLocalClass(sourceFile, clsFile.jpath, className, fullClassName) } } diff --git a/sbt-bridge/test/xsbt/ProductsSpecification.scala b/sbt-bridge/test/xsbt/ProductsSpecification.scala index b13defecc4cc..f268818f2d8b 100644 --- a/sbt-bridge/test/xsbt/ProductsSpecification.scala +++ b/sbt-bridge/test/xsbt/ProductsSpecification.scala @@ -23,12 +23,39 @@ class ProductsSpecification { val output = compiler.compileSrcsToJar(src) val srcFile = output.srcFiles.head val products = output.analysis.productClassesToSources.filter(_._2 == srcFile).keys.toSet - + def toPathInJar(className: String): Path = Paths.get(s"${output.classesOutput}!${className.replace('.', File.separatorChar)}.class") val expected = Set("example.A", "example.A$B", "example.A$C$1").map(toPathInJar) assertEquals(products, expected) } + @Test + def extractNonLocalClassesNoInc = { + val src = + """package example + | + |class A { + | class B + | def foo = + | class C + |}""".stripMargin + val output = compiler.compileSrcsNoInc(src) + val srcFile = output.srcFiles.head + val (srcNames, binaryNames) = output.analysis.classNames(srcFile).unzip // non local class names + + assertFalse(output.analysis.enabled()) // inc phases are disabled + assertTrue(output.analysis.apis.isEmpty) // extract-api did not run + assertTrue(output.analysis.usedNamesAndScopes.isEmpty) // extract-dependencies did not run + + // note that local class C is not included, classNames only records non local classes + val expectedBinary = Set("example.A", "example.A$B") + assertEquals(expectedBinary, binaryNames.toSet) + + // note that local class C is not included, classNames only records non local classes + val expectedSrc = Set("example.A", "example.A.B") + assertEquals(expectedSrc, srcNames.toSet) + } + private def compiler = new ScalaCompilerForUnitTesting -} \ No newline at end of file +} diff --git a/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala b/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala index fd125f25560b..400bcd369e27 100644 --- a/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala +++ b/sbt-bridge/test/xsbt/ScalaCompilerForUnitTesting.scala @@ -135,11 +135,15 @@ class ScalaCompilerForUnitTesting { * The sequence of temporary files corresponding to passed snippets and analysis * callback is returned as a result. */ - def compileSrcs(groupedSrcs: List[List[String]], sourcePath: List[String] = Nil, compileToJar: Boolean = false): CompileOutput = { + def compileSrcs(groupedSrcs: List[List[String]], sourcePath: List[String] = Nil, compileToJar: Boolean = false, incEnabled: Boolean = true): CompileOutput = { val temp = IO.createTemporaryDirectory - val analysisCallback = new TestCallback + val (forceSbtArgs, analysisCallback) = + if (incEnabled) + (Seq("-Yforce-sbt-phases"), new TestCallback) + else + (Seq.empty, new TestCallbackNoInc) val testProgress = new TestCompileProgress - val classesOutput = + val classesOutput = if (compileToJar) { val jar = new File(temp, "classes.jar") jar.createNewFile() @@ -174,7 +178,7 @@ class ScalaCompilerForUnitTesting { bridge.run( virtualSrcFiles, new TestDependencyChanges, - Array("-Yforce-sbt-phases", "-classpath", classesOutputPath, "-usejavacp", "-d", classesOutputPath) ++ maybeSourcePath, + (forceSbtArgs ++: Array("-classpath", classesOutputPath, "-usejavacp", "-d", classesOutputPath)) ++ maybeSourcePath, output, analysisCallback, new TestReporter, @@ -193,6 +197,10 @@ class ScalaCompilerForUnitTesting { compileSrcs(List(srcs.toList)) } + def compileSrcsNoInc(srcs: String*): CompileOutput = { + compileSrcs(List(srcs.toList), incEnabled = false) + } + def compileSrcsToJar(srcs: String*): CompileOutput = compileSrcs(List(srcs.toList), compileToJar = true) @@ -202,4 +210,3 @@ class ScalaCompilerForUnitTesting { new TestVirtualFile(srcFile.toPath) } } - diff --git a/sbt-bridge/test/xsbti/TestCallback.scala b/sbt-bridge/test/xsbti/TestCallback.scala index 3398590b169a..9f6df75d84f0 100644 --- a/sbt-bridge/test/xsbti/TestCallback.scala +++ b/sbt-bridge/test/xsbti/TestCallback.scala @@ -11,6 +11,10 @@ import DependencyContext._ import java.{util => ju} import ju.Optional +class TestCallbackNoInc extends TestCallback { + override def enabled(): Boolean = false +} + class TestCallback extends AnalysisCallback2 { case class TestUsedName(name: String, scopes: ju.EnumSet[UseScope])