diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index b5f4aeb7381..38753e4e0cf 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -18,7 +18,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.psi.PsiFile; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NotNull; @@ -269,11 +269,11 @@ public class CodegenUtil { return ((ImplementationBodyCodegen) classBodyCodegen.getParentCodegen()); } - static int getPathHashCode(@NotNull PsiFile file) { + static int getPathHashCode(@NotNull VirtualFile file) { // Conversion to system-dependent name seems to be unnecessary, but it's hard to check now: // it was introduced when fixing KT-2839, which appeared again (KT-3639). // If you try to remove it, run tests on Windows. - return FileUtil.toSystemDependentName(file.getVirtualFile().getPath()).hashCode(); + return FileUtil.toSystemDependentName(file.getPath()).hashCode(); } @Nullable diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 7f21b86a083..3ba136af3e6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -186,7 +186,7 @@ public class NamespaceCodegen extends MemberCodegen { if (!generateSrcClass) return null; - Type packageFragmentType = getNamespacePartType(getPackageClassFqName(name), file); + Type packageFragmentType = getNamespacePartType(getPackageClassFqName(name), file.getVirtualFile()); ClassBuilder builder = state.getFactory().forPackageFragment(packageFragmentType, file); new NamespacePartCodegen(builder, file, packageFragmentType, packageFragmentContext, state).generate(); @@ -247,7 +247,7 @@ public class NamespaceCodegen extends MemberCodegen { } @NotNull - private static Type getNamespacePartType(@NotNull FqName facadeFqName, @NotNull PsiFile file) { + public static Type getNamespacePartType(@NotNull FqName facadeFqName, @NotNull VirtualFile file) { String fileName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.getName())); // path hashCode to prevent same name / different path collision @@ -267,6 +267,6 @@ public class NamespaceCodegen extends MemberCodegen { @NotNull public static String getNamespacePartInternalName(@NotNull JetFile file) { FqName packageFqName = JetPsiUtil.getFQName(file); - return getNamespacePartType(getPackageClassFqName(packageFqName), file).getInternalName(); + return getNamespacePartType(getPackageClassFqName(packageFqName), file.getVirtualFile()).getInternalName(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java index 000f9c000a0..573adaea586 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.codegen; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.MethodVisitor; @@ -134,11 +135,12 @@ public class SamWrapperCodegen extends ParentCodegenAwareImpl { private String getWrapperName(@NotNull JetFile containingFile) { NamespaceDescriptor namespace = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, containingFile); - assert namespace != null : "couldn't find namespace for file: " + containingFile.getVirtualFile(); + VirtualFile virtualFile = containingFile.getVirtualFile(); + assert namespace != null : "couldn't find namespace for file: " + virtualFile; FqName fqName = DescriptorUtils.getFQName(namespace).toSafe(); String packageInternalName = JvmClassName.byFqNameWithoutInnerClasses( PackageClassUtils.getPackageClassFqName(fqName)).getInternalName(); return packageInternalName + "$sam$" + samInterface.getName().asString() + "$" + - Integer.toHexString(CodegenUtil.getPathHashCode(containingFile) * 31 + DescriptorUtils.getFQName(samInterface).hashCode()); + Integer.toHexString(CodegenUtil.getPathHashCode(virtualFile) * 31 + DescriptorUtils.getFQName(samInterface).hashCode()); } } diff --git a/jps-plugin/jps-plugin.iml b/jps-plugin/jps-plugin.iml index 83efc10247f..c3a06774179 100644 --- a/jps-plugin/jps-plugin.iml +++ b/jps-plugin/jps-plugin.iml @@ -14,6 +14,8 @@ + + diff --git a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java index 7b72857b7c6..70e32c89e5e 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java +++ b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java @@ -34,6 +34,7 @@ import org.jetbrains.jet.compiler.runner.SimpleOutputItem; import org.jetbrains.jet.jps.JpsKotlinCompilerSettings; import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.jps.ModuleChunk; +import org.jetbrains.jps.builders.BuildTarget; import org.jetbrains.jps.builders.DirtyFilesHolder; import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; import org.jetbrains.jps.incremental.*; @@ -47,10 +48,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.*; import static org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.runK2JsCompiler; @@ -165,9 +163,20 @@ public class KotlinBuilder extends ModuleLevelBuilder { runK2JvmCompiler(commonSettings, k2JvmSettings, messageCollector, environment, moduleFile, outputItemCollector); } + // If there's only one target, this map is empty: get() always returns null, and the representativeTarget will be used below + Map> sourceToTarget = new HashMap>(); + if (chunk.getTargets().size() > 1) { + for (ModuleBuildTarget target : chunk.getTargets()) { + for (File file : KotlinSourceFileCollector.getAllKotlinSourceFiles(target)) { + sourceToTarget.put(file, target); + } + } + } + for (SimpleOutputItem outputItem : outputItemCollector.getOutputs()) { + BuildTarget target = sourceToTarget.get(outputItem.getSourceFiles().iterator().next()); outputConsumer.registerOutputFile( - representativeTarget, + target != null ? target : representativeTarget, outputItem.getOutputFile(), paths(outputItem.getSourceFiles())); } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTestCase.java b/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTestCase.java index 1a7320ee144..ac6b16c4fde 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTestCase.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTestCase.java @@ -18,7 +18,10 @@ package org.jetbrains.jet.jps.build; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.jet.codegen.NamespaceCodegen; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jps.builders.BuildResult; import org.jetbrains.jps.model.java.JpsJavaDependencyScope; import org.jetbrains.jps.model.java.JpsJavaExtensionService; @@ -26,6 +29,7 @@ import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.util.JpsPathUtil; import java.io.File; +import java.io.IOException; public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { private static final String PROJECT_NAME = "kotlinProject"; @@ -36,6 +40,7 @@ public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { super.setUp(); File sourceFilesRoot = new File(TEST_DATA_PATH + getTestName(false)); workDir = copyTestDataToTmpDir(sourceFilesRoot); + getOrCreateProjectDir(); } @Override @@ -44,6 +49,11 @@ public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { super.tearDown(); } + @Override + protected File doGetProjectDir() throws IOException { + return workDir; + } + private void initProject() { addJdk(JDK_NAME); loadProject(workDir.getAbsolutePath() + File.separator + PROJECT_NAME + ".ipr"); @@ -62,6 +72,15 @@ public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { public void testKotlinProject() { doTest(); + + assertOutputDeleted("src/test1.kt", "_DefaultPackage", "kotlinProject"); + } + + public void testKotlinProjectTwoFilesInOnePackage() { + doTest(); + + assertOutputDeleted("src/test1.kt", "_DefaultPackage", "kotlinProject"); + assertOutputDeleted("src/test2.kt", "_DefaultPackage", "kotlinProject"); } public void testKotlinJavaProject() { @@ -106,14 +125,9 @@ public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { } } result.assertSuccessful(); - } - public void testTestDependencyLibrary() throws Throwable { - initProject(); - addKotlinRuntimeDependency(JpsJavaDependencyScope.TEST, myProject.getModules(), false); - makeAll().assertSuccessful(); - change(workDir + "/src/src.kt", "fun foo() { println() }"); - makeAll().assertFailed(); + assertOutputDeleted("src/kt2.kt", "kt2.Kt2Package", "kotlinProject"); + assertOutputDeleted("module2/src/kt1.kt", "kt1.Kt1Package", "module2"); } public void testReexportedDependency() { @@ -133,7 +147,10 @@ public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { assertNotNull(outputUrl); File outputDir = new File(JpsPathUtil.urlToPath(outputUrl)); File outputFile = new File(outputDir, relativePath); - assertTrue("Output not written: " + outputFile.getAbsolutePath() + "\n Directory contents: \n" + dirContents(outputFile.getParentFile()), + assertTrue("Output not written: " + + outputFile.getAbsolutePath() + + "\n Directory contents: \n" + + dirContents(outputFile.getParentFile()), outputFile.exists()); } @@ -148,4 +165,25 @@ public class KotlinJpsBuildTestCase extends AbstractKotlinJpsBuildTestCase { } return builder.toString(); } + + private void assertOutputDeleted(String sourceFileName, String packageClassFqName, String moduleName) { + File file = new File(workDir, sourceFileName); + change(file.getAbsolutePath()); + makeAll(); + + String outputDirPrefix = "out/production/" + moduleName + "/"; + assertDeleted(outputDirPrefix + packageClassFqName.replace('.', '/') + ".class", + outputDirPrefix + getInternalNameForPackagePartClass(file, packageClassFqName) + ".class"); + } + + private static String getInternalNameForPackagePartClass(File sourceFile, String packageClassFqName) { + LightVirtualFile fakeVirtualFile = new LightVirtualFile(sourceFile.getPath()) { + @Override + public String getPath() { + // strip extra "/" from the beginning + return super.getPath().substring(1); + } + }; + return NamespaceCodegen.getNamespacePartType(new FqName(packageClassFqName), fakeVirtualFile).getInternalName(); + } } diff --git a/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/kotlinProject.iml b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/kotlinProject.iml new file mode 100644 index 00000000000..a0cbe548242 --- /dev/null +++ b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/kotlinProject.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/kotlinProject.ipr b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/kotlinProject.ipr new file mode 100644 index 00000000000..90747786771 --- /dev/null +++ b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/kotlinProject.ipr @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/src/test1.kt b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/src/test1.kt new file mode 100644 index 00000000000..a2c4e958bb5 --- /dev/null +++ b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/src/test1.kt @@ -0,0 +1,3 @@ +fun foo() { + +} \ No newline at end of file diff --git a/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/src/test2.kt b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/src/test2.kt new file mode 100644 index 00000000000..6ec77d22887 --- /dev/null +++ b/jps-plugin/testData/KotlinProjectTwoFilesInOnePackage/src/test2.kt @@ -0,0 +1,3 @@ +fun bar() { + +} \ No newline at end of file