diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 92f7788567b..366bd61b692 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor @@ -485,7 +484,7 @@ fun generateBridgeForMainFunctionIfNecessary( ) { val originElement = origin.element ?: return if (functionDescriptor.name.asString() != "main" || !DescriptorUtils.isTopLevelDeclaration(functionDescriptor)) return - if (!MainFunctionDetector.isMain(functionDescriptor.unwrapInitialDescriptorForSuspendFunction(), false, true)) return + if (!state.mainFunctionDetector.isMain(functionDescriptor.unwrapInitialDescriptorForSuspendFunction(), false, true)) return if (!functionDescriptor.isSuspend) return diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index 56f84053f1f..8999f8fb0ca 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion import org.jetbrains.kotlin.modules.TargetId @@ -180,6 +181,7 @@ class GenerationState private constructor( filter = if (wantsDiagnostics) BindingTraceFilter.ACCEPT_ALL else BindingTraceFilter.NO_DIAGNOSTICS ) val bindingContext: BindingContext = bindingTrace.bindingContext + val mainFunctionDetector = MainFunctionDetector(bindingContext) private val isIrBackend = configuration.get(JVMConfigurationKeys.IR) ?: false val typeMapper: KotlinTypeMapper = KotlinTypeMapper( this.bindingContext, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt b/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt index b9abec86e8c..a1367d9ed8b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt @@ -35,7 +35,7 @@ class MainFunctionDetector { constructor(bindingContext: BindingContext) { this.getFunctionDescriptor = { function -> bindingContext.get(BindingContext.FUNCTION, function) - ?: throw IllegalStateException("No descriptor resolved for " + function + " " + function.text) + ?: throw IllegalStateException("No descriptor resolved for " + function + " " + function.text) } } @@ -79,6 +79,47 @@ class MainFunctionDetector { return isMain(functionDescriptor, checkJvmStaticAnnotation) } + fun isMain( + descriptor: DeclarationDescriptor, + checkJvmStaticAnnotation: Boolean = true, + checkReturnType: Boolean = true + ): Boolean { + if (descriptor !is FunctionDescriptor) return false + + if (getJVMFunctionName(descriptor) != "main") { + return false + } + + val parameters = descriptor.valueParameters.mapTo(mutableListOf()) { it.type } + descriptor.extensionReceiverParameter?.type?.let { parameters += it } + + if (parameters.size != 1 || !descriptor.typeParameters.isEmpty()) return false + + val parameterType = parameters[0] + if (!KotlinBuiltIns.isArray(parameterType)) return false + + val typeArguments = parameterType.arguments + if (typeArguments.size != 1) return false + + val typeArgument = typeArguments[0].type + if (!KotlinBuiltIns.isString(typeArgument)) { + return false + } + if (typeArguments[0].projectionKind === Variance.IN_VARIANCE) { + return false + } + + if (checkReturnType && !isMainReturnType(descriptor)) return false + + if (DescriptorUtils.isTopLevelDeclaration(descriptor)) return true + + val containingDeclaration = descriptor.containingDeclaration + return containingDeclaration is ClassDescriptor + && containingDeclaration.kind.isSingleton + && (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation) + } + + fun getMainFunction(module: ModuleDescriptor): FunctionDescriptor? = getMainFunction(module, module.getPackage(FqName.ROOT)) private fun getMainFunction(module: ModuleDescriptor, packageView: PackageViewDescriptor): FunctionDescriptor? { @@ -100,48 +141,7 @@ class MainFunctionDetector { declarations.filterIsInstance().find { isMain(it) } companion object { - - fun isMain( - descriptor: DeclarationDescriptor, - checkJvmStaticAnnotation: Boolean = true, - checkReturnType: Boolean = true - ): Boolean { - if (descriptor !is FunctionDescriptor) return false - - if (getJVMFunctionName(descriptor) != "main") { - return false - } - - val parameters = descriptor.valueParameters.mapTo(mutableListOf()) { it.type } - descriptor.extensionReceiverParameter?.type?.let { parameters += it } - - if (parameters.size != 1 || !descriptor.typeParameters.isEmpty()) return false - - val parameterType = parameters[0] - if (!KotlinBuiltIns.isArray(parameterType)) return false - - val typeArguments = parameterType.arguments - if (typeArguments.size != 1) return false - - val typeArgument = typeArguments[0].type - if (!KotlinBuiltIns.isString(typeArgument)) { - return false - } - if (typeArguments[0].projectionKind === Variance.IN_VARIANCE) { - return false - } - - if (checkReturnType && !isMainReturnType(descriptor)) return false - - if (DescriptorUtils.isTopLevelDeclaration(descriptor)) return true - - val containingDeclaration = descriptor.containingDeclaration - return containingDeclaration is ClassDescriptor - && containingDeclaration.kind.isSingleton - && (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation) - } - - fun isMainReturnType(descriptor: FunctionDescriptor): Boolean { + private fun isMainReturnType(descriptor: FunctionDescriptor): Boolean { val returnType = descriptor.returnType return returnType != null && KotlinBuiltIns.isUnit(returnType) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt index 570a95fc4f3..c1226f4edd7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverloadResolver.kt @@ -34,6 +34,8 @@ class OverloadResolver( private val overloadChecker: OverloadChecker ) { + private val mainFunctionDetector = MainFunctionDetector(trace.bindingContext) + fun checkOverloads(c: BodiesResolveContext) { val inClasses = findConstructorsInNestedClassesAndTypeAliases(c) @@ -268,7 +270,7 @@ class OverloadResolver( } private fun isTopLevelMainInDifferentFiles(member1: DeclarationDescriptor, member2: DeclarationDescriptor): Boolean { - if (!MainFunctionDetector.isMain(member1) || !MainFunctionDetector.isMain(member2)) { + if (!mainFunctionDetector.isMain(member1) || !mainFunctionDetector.isMain(member2)) { return false } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/MainFunctionReturnUnitInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/MainFunctionReturnUnitInspection.kt index 651e1b04177..49e9d05c440 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/MainFunctionReturnUnitInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/MainFunctionReturnUnitInspection.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.setType import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.name.FqName @@ -35,7 +36,7 @@ class MainFunctionReturnUnitInspection : AbstractKotlinInspection() { val descriptor = function.descriptor as? FunctionDescriptor ?: return if (isMain) { - if (!MainFunctionDetector.isMain(descriptor, checkReturnType = false)) return + if (!MainFunctionDetector { it.resolveToDescriptorIfAny() }.isMain(descriptor, checkReturnType = false)) return } else { val junitTestFqNames = listOf(FqName("org.junit.Test"), FqName("org.junit.jupiter.api.Test")) if (testAnnotations.none { it.fqName() in junitTestFqNames }) return @@ -71,4 +72,4 @@ private class ChangeMainFunctionReturnTypeToUnitFix(private val hasExplicitRetur function.setType(KotlinBuiltIns.FQ_NAMES.unit.asString()) } } -} \ No newline at end of file +} diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt index 99335d72bd6..b062eae4374 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt @@ -77,7 +77,7 @@ class UnusedReceiverParameterInspection : AbstractKotlinInspection() { val callable = callableDeclaration.descriptor ?: return - if (MainFunctionDetector.isMain(callable)) return + if (MainFunctionDetector { it.resolveToDescriptorIfAny() }.isMain(callable)) return val containingDeclaration = callable.containingDeclaration if (containingDeclaration != null && containingDeclaration == receiverTypeDeclaration) { @@ -175,4 +175,4 @@ fun isUsageOfDescriptor(descriptor: DeclarationDescriptor, resolvedCall: Resolve } return false -} \ No newline at end of file +}