diff --git a/jps/jps-builders/resources/messages/JpsBuildBundle.properties b/jps/jps-builders/resources/messages/JpsBuildBundle.properties index 3e7b96c420bb..ced98ae39ef5 100644 --- a/jps/jps-builders/resources/messages/JpsBuildBundle.properties +++ b/jps/jps-builders/resources/messages/JpsBuildBundle.properties @@ -26,6 +26,7 @@ progress.message.dependency.analysis.found.0.affected.files=Dependency analysis progress.message.finished.saving.caches=Finished, saving caches\u2026 progress.message.running.after.tasks=Running 'after' tasks progress.message.running.before.tasks=Running 'before' tasks +build.message.conflicting.outputs.error=Output file "{0}" has already been registered by "{1}" #java build.message.0.was.used.to.compile.1={0} was used to compile [{1}] diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ChunkBuildOutputConsumerImpl.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ChunkBuildOutputConsumerImpl.java index 506c2a177b57..1c8915c10bbb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ChunkBuildOutputConsumerImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ChunkBuildOutputConsumerImpl.java @@ -1,28 +1,38 @@ // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.jps.incremental; +import com.intellij.openapi.util.io.FileUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.builders.BuildTarget; +import org.jetbrains.jps.builders.JpsBuildBundle; import org.jetbrains.jps.builders.impl.BuildOutputConsumerImpl; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; import java.io.File; import java.io.IOException; import java.util.*; -/** -* @author Eugene Zhuravlev -*/ final class ChunkBuildOutputConsumerImpl implements ModuleLevelBuilder.OutputConsumer { private final CompileContext myContext; private final Map, BuildOutputConsumerImpl> myTarget2Consumer = new HashMap<>(); private final Map myClasses = new HashMap<>(); private final Map, Collection> myTargetToClassesMap = new HashMap<>(); - + private final Int2ObjectMap myOutputToBuilderNameMap = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); + private volatile String myCurrentBuilderName; + ChunkBuildOutputConsumerImpl(CompileContext context) { myContext = context; } + public void setCurrentBuilderName(String builderName) { + myCurrentBuilderName = builderName; + } + @Override public Collection getTargetCompiledClasses(@NotNull BuildTarget target) { final Collection classes = myTargetToClassesMap.get(target); @@ -65,6 +75,16 @@ final class ChunkBuildOutputConsumerImpl implements ModuleLevelBuilder.OutputCon @Override public void registerOutputFile(@NotNull BuildTarget target, File outputFile, Collection sourcePaths) throws IOException { + final String currentBuilder = myCurrentBuilderName; + if (currentBuilder != null) { + final String previousBuilder = myOutputToBuilderNameMap.put(FileUtil.fileHashCode(outputFile), currentBuilder); + if (previousBuilder != null && !previousBuilder.equals(currentBuilder)) { + final String source = sourcePaths.isEmpty()? null : sourcePaths.iterator().next(); + myContext.processMessage(new CompilerMessage( + currentBuilder, BuildMessage.Kind.ERROR, JpsBuildBundle.message("build.message.conflicting.outputs.error", outputFile.getAbsolutePath(), previousBuilder), source + )); + } + } BuildOutputConsumerImpl consumer = myTarget2Consumer.get(target); if (consumer == null) { consumer = new BuildOutputConsumerImpl(target, myContext); @@ -91,5 +111,6 @@ final class ChunkBuildOutputConsumerImpl implements ModuleLevelBuilder.OutputCon myTarget2Consumer.clear(); myClasses.clear(); myTargetToClassesMap.clear(); + myOutputToBuilderNameMap.clear(); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 3901ffed3442..92b1fa6f0c69 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -1509,6 +1509,7 @@ public final class IncProjectBuilder { try { for (ModuleLevelBuilder builder : builders) { + outputConsumer.setCurrentBuilderName(builder.getPresentableName()); processDeletedPaths(context, chunk.getTargets()); long start = System.nanoTime(); int processedSourcesBefore = outputConsumer.getNumberOfProcessedSources(); @@ -1556,6 +1557,7 @@ public final class IncProjectBuilder { } } finally { + outputConsumer.setCurrentBuilderName(null); final boolean moreToCompile = JavaBuilderUtil.updateMappingsOnRoundCompletion(context, dirtyFilesHolder, chunk); if (moreToCompile) { nextPassRequired = true;