diff --git a/backend/src/main/scala/bloop/BloopClassFileManager.scala b/backend/src/main/scala/bloop/BloopClassFileManager.scala index d98be2a2d..b7219967d 100644 --- a/backend/src/main/scala/bloop/BloopClassFileManager.scala +++ b/backend/src/main/scala/bloop/BloopClassFileManager.scala @@ -41,7 +41,7 @@ final class BloopClassFileManager( private[this] val generatedFiles = new mutable.HashSet[File] // Supported compile products by the class file manager - private[this] val supportedCompileProducts = List(".sjsir", ".nir", ".tasty", ".betasty") + val supportedCompileProducts = List(".sjsir", ".nir", ".tasty", ".betasty") // Files backed up during compilation private[this] val movedFiles = new mutable.HashMap[File, File] diff --git a/backend/src/main/scala/bloop/Compiler.scala b/backend/src/main/scala/bloop/Compiler.scala index b86c50b0e..3b52a94de 100644 --- a/backend/src/main/scala/bloop/Compiler.scala +++ b/backend/src/main/scala/bloop/Compiler.scala @@ -275,7 +275,7 @@ object Compiler { val backgroundTasksForFailedCompilation = new mutable.ListBuffer[CompileBackgroundTasks.Sig]() - def newFileManager: ClassFileManager = { + def newFileManager: BloopClassFileManager = { new BloopClassFileManager( Files.createTempDirectory("bloop"), compileInputs, @@ -453,6 +453,7 @@ object Compiler { () => elapsed, reporter, backgroundTasksWhenNewSuccessfulAnalysis, + fileManager, allInvalidatedClassFilesForProject, allInvalidatedExtraCompileProducts, previousSuccessfulProblems, @@ -673,6 +674,7 @@ object Compiler { () => elapsed, reporter, backgroundTasksWhenNewSuccessfulAnalysis, + fileManager, allInvalidatedClassFilesForProject, allInvalidatedExtraCompileProducts, previousSuccessfulProblems, @@ -871,6 +873,7 @@ object Compiler { elapsed: () => Long, reporter: ZincReporter, backgroundTasksWhenNewSuccessfulAnalysis: mutable.ListBuffer[CompileBackgroundTasks.Sig], + fileManager: BloopClassFileManager, allInvalidatedClassFilesForProject: mutable.HashSet[File], allInvalidatedExtraCompileProducts: mutable.HashSet[File], previousSuccessfulProblems: List[ProblemPerPhase], @@ -878,7 +881,6 @@ object Compiler { ): Result = { val uniqueInputs = compileInputs.uniqueInputs val readOnlyClassesDir = compileOut.internalReadOnlyClassesDir.underlying - val readOnlyClassesDirPath = readOnlyClassesDir.toString val newClassesDir = compileOut.internalNewClassesDir.underlying reporter.processEndCompilation( @@ -903,10 +905,6 @@ object Compiler { Map.empty ) - // Delete all those class files that were invalidated in the external classes dir - val allInvalidated = - allInvalidatedClassFilesForProject ++ allInvalidatedExtraCompileProducts - val backgroundTasksExecution = new CompileBackgroundTasks { def trigger( clientClassesObserver: ClientClassesObserver, @@ -915,7 +913,6 @@ object Compiler { clientLogger: Logger ): Task[Unit] = { val clientClassesDir = clientClassesObserver.classesDir - val clientClassesDirPath = clientClassesDir.toString val successBackgroundTasks = backgroundTasksWhenNewSuccessfulAnalysis .map(f => f(clientClassesDir, clientReporter, clientTracer)) @@ -933,20 +930,13 @@ object Compiler { ) val secondTask = Task { - allInvalidated.foreach { f => - val path = AbsolutePath(f.toPath) - val syntax = path.syntax - if (syntax.startsWith(readOnlyClassesDirPath)) { - val rebasedFile = AbsolutePath( - syntax.replace(readOnlyClassesDirPath, clientClassesDirPath) - ) - if (rebasedFile.exists) { - // In practice this deletes previous successful compilation artifacts - // (like '.tasty' and ".class"), which we do not need in clientDir - Files.delete(rebasedFile.underlying) - } - } - } + val deletedCompileProducts = + fileManager.supportedCompileProducts.filter(_ != ".betasty") :+ ".class" + Files + .walk(clientClassesDir.underlying) + .filter(path => Files.isRegularFile(path)) + .filter(path => deletedCompileProducts.exists(path.toString.endsWith(_))) + .forEach(Files.delete(_)) } Task .gatherUnordered(List(firstTask, secondTask)) diff --git a/frontend/src/test/scala/bloop/bsp/BspMetalsClientSpec.scala b/frontend/src/test/scala/bloop/bsp/BspMetalsClientSpec.scala index c62ceadde..4e65ef357 100644 --- a/frontend/src/test/scala/bloop/bsp/BspMetalsClientSpec.scala +++ b/frontend/src/test/scala/bloop/bsp/BspMetalsClientSpec.scala @@ -657,21 +657,25 @@ class BspMetalsClientSpec( val compiledState = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState assertBetastyFile("A.betasty", compiledState, "A") assertBetastyFile("B.betasty", compiledState, "A") + assertCompilationFile("A.class", compiledState, "A") updateProject(updatedFile1WithError) val compiledState2 = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState assertBetastyFile("A.betasty", compiledState2, "A") assertNoBetastyFile("B.betasty", compiledState2, "A") assertBetastyFile("C.betasty", compiledState2, "A") + assertNoCompilationFile("A.class", compiledState, "A") updateProject(updatedFile2WithoutError) val compiledState3 = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState assertNoBetastyFile("A.betasty", compiledState3, "A") assertBetastyFile("B.betasty", compiledState3, "A") assertBetastyFile("C.betasty", compiledState3, "A") + assertCompilationFile("B.class", compiledState, "A") updateProject(updatedFile3WithError) val compiledState4 = state.compile(`A`, arguments = Some(List("--best-effort"))).toTestState assertNoBetastyFile("A.betasty", compiledState4, "A") assertBetastyFile("B.betasty", compiledState4, "A") assertNoBetastyFile("C.betasty", compiledState4, "A") + assertNoCompilationFile("B.class", compiledState, "A") } } } @@ -791,26 +795,48 @@ class BspMetalsClientSpec( classesDir.resolve(s"META-INF/semanticdb/$projectName/src/$sourcePath.semanticdb") } - private def assertBetastyFile( - expectedBetastyRelativePath: String, + private def assertCompilationFile( + expectedFilePath: String, state: TestState, projectName: String ): Unit = { val project = state.build.getProjectFor(projectName).get val classesDir = state.client.getUniqueClassesDirFor(project, forceGeneration = true) - val beTastyFile = classesDir.resolve(s"META-INF/best-effort/$expectedBetastyRelativePath") - assertIsFile(beTastyFile) + assertIsFile(classesDir.resolve(expectedFilePath)) } - private def assertNoBetastyFile( - expectedBetastyRelativePath: String, + private def assertNoCompilationFile( + expectedFilePath: String, state: TestState, projectName: String ): Unit = { val project = state.build.getProjectFor(projectName).get val classesDir = state.client.getUniqueClassesDirFor(project, forceGeneration = true) - val beTastyFile = classesDir.resolve(s"META-INF/best-effort/$expectedBetastyRelativePath") - assertNotFile(beTastyFile) + assertNotFile(classesDir.resolve(expectedFilePath)) + } + + private def assertBetastyFile( + expectedBetastyRelativePath: String, + state: TestState, + projectName: String + ): Unit = { + assertCompilationFile( + s"META-INF/best-effort/$expectedBetastyRelativePath", + state, + projectName + ) + } + + private def assertNoBetastyFile( + expectedBetastyRelativePath: String, + state: TestState, + projectName: String + ): Unit = { + assertNoCompilationFile( + s"META-INF/best-effort/$expectedBetastyRelativePath", + state, + projectName + ) } private def assertSemanticdbFileFor(