Make single-file classes tolerant to having many main()'s

This commit is contained in:
Michael Nedzelsky
2015-10-15 00:26:37 +03:00
parent 416dda95ce
commit 890ae3e914
22 changed files with 186 additions and 13 deletions
@@ -19,20 +19,23 @@ package org.jetbrains.kotlin.codegen.state
import com.intellij.psi.PsiElement
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.SignatureCollectingClassBuilderFactory
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
import java.util.*
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider
import org.jetbrains.kotlin.fileClasses.isInsideJvmMultifileClassFile
import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
private val EXTERNAL_SOURCES_KINDS = arrayOf(
JvmDeclarationOriginKind.DELEGATION_TO_DEFAULT_IMPLS,
@@ -61,9 +64,18 @@ class BuilderFactoryForDuplicateSignatureDiagnostics(
else {
for (origin in data.signatureOrigins) {
var element = origin.element
// TODO Remove this code after dropping package facades
val descriptor = origin.descriptor
if (descriptor != null && element is JetDeclaration && DescriptorUtils.isTopLevelMainFunction(descriptor) &&
!element.isInsideJvmMultifileClassFile()) {
return
}
if (element == null || origin.originKind in EXTERNAL_SOURCES_KINDS) {
element = data.classOrigin.element
}
elements.addIfNotNull(element)
}
}
@@ -135,4 +135,9 @@ public val JetFile.javaFileFacadeFqName: FqName
else JvmFileClassUtil.getFileClassInfoNoResolve(this).facadeClassFqName
CachedValueProvider.Result(facadeFqName, this)
}
}
}
public fun JetDeclaration.isInsideJvmMultifileClassFile() = JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(
getContainingJetFile(),
JvmFileClassUtil.JVM_MULTIFILE_CLASS_SHORT
) != null
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.isInsideJvmMultifileClassFile
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeclarationChecker
@@ -74,11 +75,6 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_FIELD.on(annotationEntry, problem.errorMessage))
}
private fun JetDeclaration.isInsideJvmMultifileClassFile() = JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(
getContainingJetFile(),
JvmFileClassUtil.JVM_MULTIFILE_CLASS_SHORT
) != null
private fun PropertyDescriptor.hasCustomAccessor()
= !(getter?.isDefault ?: true) || !(setter?.isDefault ?: true)
@@ -195,6 +195,8 @@ public class OverloadResolver {
@NotNull Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations) {
for (Pair<JetDeclaration, CallableMemberDescriptor> redeclaration : redeclarations) {
CallableMemberDescriptor memberDescriptor = redeclaration.getSecond();
if (DescriptorUtils.isTopLevelMainFunction(memberDescriptor)) break;
JetDeclaration jetDeclaration = redeclaration.getFirst();
if (memberDescriptor instanceof PropertyDescriptor) {
trace.report(Errors.REDECLARATION.on(jetDeclaration, memberDescriptor.getName().asString()));
+21
View File
@@ -0,0 +1,21 @@
package test
class A {}
fun getMain(className: String): java.lang.reflect.Method {
val classLoader = A().javaClass.classLoader
return classLoader.loadClass(className).getDeclaredMethod("main", Array<String>::class.java)
}
fun box(): String {
val bMain = getMain("pkg.AKt")
val cMain = getMain("pkg.BKt")
val args = Array(1, { "" })
bMain.invoke(null, args)
cMain.invoke(null, args)
return args[0]
}
@@ -0,0 +1,5 @@
package pkg
fun main(args: Array<String>) {
args[0] += "O"
}
@@ -0,0 +1,5 @@
package pkg
fun main(args: Array<String>) {
args[0] += "K"
}
@@ -0,0 +1,5 @@
// FILE: a.kt
fun main(args: Array<String>) {}
// FILE: b.kt
fun main(args: Array<String>) {}
@@ -0,0 +1,4 @@
package
public fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
public fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
@@ -0,0 +1,8 @@
// FILE: a.kt
fun main(args: Array<String>) {}
// FILE: b.kt
fun main(args: Array<String>) {}
// FILE: c.kt
fun foo() { <!OVERLOAD_RESOLUTION_AMBIGUITY!>main<!>(arrayOf("a", "b")) }
@@ -0,0 +1,5 @@
package
public fun foo(): kotlin.Unit
public fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
public fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
@@ -0,0 +1,11 @@
// FILE: a.kt
@file:JvmName("Util")
@file:JvmMultifileClass
<!CONFLICTING_JVM_DECLARATIONS!>fun main(args: Array<String>)<!> {}
// FILE: b.kt
@file:JvmName("Util")
@file:JvmMultifileClass
<!CONFLICTING_JVM_DECLARATIONS!>fun main(args: Array<String>)<!> {}
@@ -0,0 +1,4 @@
package
public fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
public fun main(/*0*/ args: kotlin.Array<kotlin.String>): kotlin.Unit
@@ -0,0 +1,5 @@
package pkg
fun main(args : Array<String>) {
println("A.main Ok")
}
@@ -0,0 +1,5 @@
package pkg
fun main(args : Array<String>) {
println("B.main Ok")
}
@@ -0,0 +1,12 @@
OUT:
Buildfile: [TestData]/build.xml
build:
[kotlinc] Compiling [[TestData]] => [[Temp]/hello.jar]
[java] A.main Ok
[java] B.main Ok
BUILD SUCCESSFUL
Total time: [time]
Return code: 0
@@ -0,0 +1,23 @@
<project name="Ant Task Test" default="build">
<taskdef resource="org/jetbrains/kotlin/ant/antlib.xml" classpath="${kotlin.lib}/kotlin-ant.jar"/>
<target name="build">
<kotlinc output="${temp}/hello.jar">
<src path="${test.data}"/>
</kotlinc>
<java classname="pkg.AKt" fork="true">
<classpath>
<pathelement location="${temp}/hello.jar"/>
<pathelement location="${kotlin.runtime.jar}"/>
</classpath>
</java>
<java classname="pkg.BKt" fork="true">
<classpath>
<pathelement location="${temp}/hello.jar"/>
<pathelement location="${kotlin.runtime.jar}"/>
</classpath>
</java>
</target>
</project>
@@ -11802,6 +11802,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("RedeclarationMainInMultiFile.kt")
public void testRedeclarationMainInMultiFile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/redeclarations/RedeclarationMainInMultiFile.kt");
doTest(fileName);
}
@TestMetadata("Redeclarations.kt")
public void testRedeclarations() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/redeclarations/Redeclarations.kt");
@@ -35,6 +35,12 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("CallToMainRedeclaredInMultiFile.kt")
public void testCallToMainRedeclaredInMultiFile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/CallToMainRedeclaredInMultiFile.kt");
doTest(fileName);
}
@TestMetadata("commonCollections.kt")
public void testCommonCollections() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/commonCollections.kt");
@@ -77,6 +83,12 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic
doTest(fileName);
}
@TestMetadata("RedeclarationMainInMultiFileClass.kt")
public void testRedeclarationMainInMultiFileClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/RedeclarationMainInMultiFileClass.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -89,6 +89,12 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg
doTestMultiFile(fileName);
}
@TestMetadata("mainInFiles")
public void testMainInFiles() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/mainInFiles/");
doTestMultiFile(fileName);
}
@TestMetadata("multifileClassPartsInitialization")
public void testMultifileClassPartsInitialization() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/multifileClassPartsInitialization/");
@@ -71,6 +71,12 @@ public class AntTaskTestGenerated extends AbstractAntTaskTest {
doTest(fileName);
}
@TestMetadata("mainInFiles")
public void testMainInFiles() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/integration/ant/jvm/mainInFiles/");
doTest(fileName);
}
@TestMetadata("moduleName")
public void testModuleName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/integration/ant/jvm/moduleName/");
@@ -630,6 +630,21 @@ public class DescriptorUtils {
return SourceFile.NO_SOURCE_FILE;
}
public static boolean isTopLevelMainFunction(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof FunctionDescriptor) ||
!isTopLevelDeclaration(descriptor) ||
!"main".equals(descriptor.getName().asString())) return false;
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters();
if (valueParameterDescriptors.size() != 1) return false;
JetType type = valueParameterDescriptors.get(0).getType();
return KotlinBuiltIns.isArray(type) && type.getArguments().size() == 1 && KotlinBuiltIns.isString(type.getArguments().get(0).getType());
}
private static void getSubPackagesFqNames(PackageViewDescriptor packageView, Set<FqName> result) {
FqName fqName = packageView.getFqName();
if (!fqName.isRoot()) {