Make single-file classes tolerant to having many main()'s
This commit is contained in:
+19
-7
@@ -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
|
||||
|
||||
+1
-5
@@ -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()));
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// FILE: a.kt
|
||||
fun main(args: Array<String>) {}
|
||||
|
||||
// FILE: b.kt
|
||||
fun main(args: Array<String>) {}
|
||||
+4
@@ -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
|
||||
+8
@@ -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")) }
|
||||
+5
@@ -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
|
||||
+11
@@ -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>)<!> {}
|
||||
+4
@@ -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");
|
||||
|
||||
+12
@@ -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)
|
||||
|
||||
+6
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user