From befc809e2d6d2971f666d006f99bbda92fff70d2 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 11 Apr 2017 15:33:06 +0200 Subject: [PATCH] [java] allows one module-info file in either source or test root - compilation (IDEA-171221) --- .../compiler/impl/JavaModuleIndexBuildTask.kt | 44 ++++++++++++------- .../jps/incremental/java/JavaBuilder.java | 20 ++++++--- .../jps/model/java/JavaModuleIndex.java | 10 +---- .../model/java/impl/JavaModuleIndexImpl.java | 36 +++++++-------- 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt b/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt index a929a0e26fdd..e90cee6527c1 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt +++ b/java/compiler/impl/src/com/intellij/compiler/impl/JavaModuleIndexBuildTask.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import com.intellij.openapi.compiler.CompilerManager import com.intellij.openapi.compiler.CompilerMessageCategory import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.roots.ModuleRootManager import com.intellij.psi.PsiJavaModule import com.intellij.psi.search.FilenameIndex import org.jetbrains.jps.builders.impl.BuildDataPathsImpl @@ -35,37 +36,50 @@ class JavaModuleIndexBuildTask : CompileTask { val systemDir = BuildManager.getInstance().getProjectSystemDirectory(project) if (systemDir == null) { - context.addMessage(CompilerMessageCategory.ERROR, "Internal error: no system directory for project: ${project}", null, 0, 0) + context.error("Internal error: no system directory for project: ${project}") return false } - val map = runReadAction { - val compilerManager = CompilerManager.getInstance(project) - ModuleManager.getInstance(project).modules.asSequence() - .map { - val files = FilenameIndex.getVirtualFilesByName(project, PsiJavaModule.MODULE_INFO_FILE, it.getModuleScope(false)) - it.name to files.filter { !compilerManager.isExcludedFromCompilation(it) } + val badModules = mutableListOf() + val paths = mutableMapOf() + + val compilerManager = CompilerManager.getInstance(project) + runReadAction { + ModuleManager.getInstance(project).modules.forEach { module -> + val index = ModuleRootManager.getInstance(module).fileIndex + val sourceFiles = mutableListOf() + val testFiles = mutableListOf() + FilenameIndex.getVirtualFilesByName(project, PsiJavaModule.MODULE_INFO_FILE, module.moduleScope).forEach { file -> + if (!compilerManager.isExcludedFromCompilation(file)) { + (if (index.isInTestSourceContent(file)) testFiles else sourceFiles) += file.path + } } - .toMap() + if (sourceFiles.size + testFiles.size > 1) { + badModules += module.name + } + else { + paths += module.name + JavaModuleIndexImpl.SOURCE_SUFFIX to sourceFiles.firstOrNull() + paths += module.name + JavaModuleIndexImpl.TEST_SUFFIX to testFiles.firstOrNull() + } + } } - val errors = map.filter { it.value.size > 1 }.map { IdeBundle.message("compiler.multiple.module.descriptors", it.key) } - if (errors.isNotEmpty()) { - errors.forEach { context.addMessage(CompilerMessageCategory.ERROR, it, null, 0, 0) } + if (badModules.isNotEmpty()) { + badModules.forEach { context.error(IdeBundle.message("compiler.multiple.module.descriptors", it)) } return false } - val paths = map.map { it.key to it.value.firstOrNull()?.path }.toMap() - try { JavaModuleIndexImpl.store(BuildDataPathsImpl(systemDir).dataStorageRoot, paths) } catch(e: Exception) { Logger.getInstance(JavaModuleIndexBuildTask::class.java).error(e) - context.addMessage(CompilerMessageCategory.ERROR, "Internal error: can't save module index: ${e.message}", null, 0, 0) + context.error("Internal error: can't save module index: ${e.message}") return false } return true } + + private fun CompileContext.error(message: String) = addMessage(CompilerMessageCategory.ERROR, message, null, 0, 0) } \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 1bd2bd80792d..71faff7b93c4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -235,12 +235,17 @@ public class JavaBuilder extends ModuleLevelBuilder { } }); + boolean hasModules = false; if ((!filesToCompile.isEmpty() || dirtyFilesHolder.hasRemovedFiles()) && JpsJavaSdkType.parseVersion(getLanguageLevel(ContainerUtil.getFirstItem(chunk.getModules()))) >= 9) { // at the moment, there is no incremental compilation for module-info files, so they should be rebuilt on every change JavaModuleIndex index = getJavaModuleIndex(context); - for (JpsModule module : chunk.getModules()) { - ContainerUtil.addIfNotNull(filesToCompile, index.getModuleInfoFile(module)); + for (ModuleBuildTarget target : chunk.getTargets()) { + File moduleInfoFile = index.getModuleInfoFile(target.getModule(), target.isTests()); + if (moduleInfoFile != null) { + filesToCompile.add(moduleInfoFile); + hasModules = true; + } } } @@ -251,7 +256,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } - return compile(context, chunk, dirtyFilesHolder, filesToCompile, outputConsumer, compilingTool); + return compile(context, chunk, dirtyFilesHolder, filesToCompile, outputConsumer, compilingTool, hasModules); } catch (BuildDataCorruptedException | PersistentEnumeratorBase.CorruptedException | ProjectBuildException e) { throw e; @@ -270,7 +275,8 @@ public class JavaBuilder extends ModuleLevelBuilder { DirtyFilesHolder dirtyFilesHolder, Collection files, OutputConsumer outputConsumer, - JavaCompilingTool compilingTool) throws Exception { + JavaCompilingTool compilingTool, + boolean hasModules) throws Exception { ExitCode exitCode = ExitCode.NOTHING_DONE; final boolean hasSourcesToCompile = !files.isEmpty(); @@ -323,7 +329,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } try { - compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink, compilingTool); + compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink, compilingTool, hasModules); } finally { // heuristic: incorrect paths data recovery, so that the next make should not contain non-existing sources in 'recompile' list @@ -370,7 +376,8 @@ public class JavaBuilder extends ModuleLevelBuilder { Collection sourcePath, DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink, - JavaCompilingTool compilingTool) throws Exception { + JavaCompilingTool compilingTool, + boolean hasModules) throws Exception { final TasksCounter counter = new TasksCounter(); COUNTER_KEY.set(context, counter); @@ -395,7 +402,6 @@ public class JavaBuilder extends ModuleLevelBuilder { try { final int targetLanguageLevel = JpsJavaSdkType.parseVersion(getLanguageLevel(chunk.getModules().iterator().next())); final boolean shouldForkJavac = shouldForkCompilerProcess(context, chunk, targetLanguageLevel); - final boolean hasModules = targetLanguageLevel >= 9 && getJavaModuleIndex(context).hasJavaModules(modules); // when forking external javac, compilers from SDK 1.6 and higher are supported Pair forkSdk = null; diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java index 9a401a674b46..aaa3f4f72e3b 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java +++ b/jps/model-api/src/org/jetbrains/jps/model/java/JavaModuleIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,17 +20,11 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.module.JpsModule; import java.io.File; -import java.util.Set; public abstract class JavaModuleIndex { /** * Returns a path to a module descriptor (module-info.java file) for the given module, * or {@code null} when there is no descriptor. */ - public abstract @Nullable File getModuleInfoFile(@NotNull JpsModule module); - - /** - * Returns {@code true} when at least one module in the chunk has a module descriptor (module-info.java file). - */ - public abstract boolean hasJavaModules(@NotNull Set chunk); + public abstract @Nullable File getModuleInfoFile(@NotNull JpsModule module, boolean forTests); } \ No newline at end of file diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java index fe7eced0bfae..e291bc29fa12 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaModuleIndexImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.java.JavaModuleIndex; +import org.jetbrains.jps.model.java.JavaSourceRootType; import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes; import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.module.JpsModuleSourceRoot; @@ -30,9 +31,11 @@ import java.io.*; import java.util.Collections; import java.util.Map; import java.util.Properties; -import java.util.Set; public class JavaModuleIndexImpl extends JavaModuleIndex { + public static final String SOURCE_SUFFIX = ":S"; + public static final String TEST_SUFFIX = ":T"; + private static final String INDEX_PATH = "jigsaw/module-info.map"; private static final String NULL_PATH = "-"; private static final String MODULE_INFO_FILE = "module-info.java"; @@ -50,34 +53,27 @@ public class JavaModuleIndexImpl extends JavaModuleIndex { myExcludes = null; } + @Nullable @Override - public @Nullable File getModuleInfoFile(@NotNull JpsModule module) { - String key = module.getName(); + public File getModuleInfoFile(@NotNull JpsModule module, boolean forTests) { + String key = module.getName() + (forTests ? TEST_SUFFIX : SOURCE_SUFFIX); + if (myExcludes == null || myMapping.containsKey(key)) { return myMapping.get(key); } - File file = findModuleInfoFile(module); + File file = findModuleInfoFile(module, forTests ? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE); myMapping.put(key, file); return file; } - @Override - public boolean hasJavaModules(@NotNull Set chunk) { - for (JpsModule module : chunk) { - if (getModuleInfoFile(module) != null) { - return true; - } - } - - return false; - } - - private File findModuleInfoFile(JpsModule module) { + private File findModuleInfoFile(JpsModule module, JavaSourceRootType rootType) { for (JpsModuleSourceRoot root : module.getSourceRoots()) { - File file = new File(JpsPathUtil.urlToOsPath(root.getUrl()), MODULE_INFO_FILE); - if (file.isFile() && !myExcludes.isExcluded(file)) { - return file; + if (rootType.equals(root.getRootType())) { + File file = new File(JpsPathUtil.urlToOsPath(root.getUrl()), MODULE_INFO_FILE); + if (file.isFile() && !myExcludes.isExcluded(file)) { + return file; + } } }