org.jetbrains.kotlin.resolve.checkers.FunInterfaceDeclarationChecker.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.sam.getAbstractMembers
import org.jetbrains.kotlin.resolve.source.getPsi
class FunInterfaceDeclarationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration !is KtClass) return
if (descriptor !is ClassDescriptor || !descriptor.isFun) return
val funKeyword = declaration.getFunKeyword() ?: return
val abstractMembers = getAbstractMembers(descriptor)
for (abstractMember in abstractMembers) {
if (abstractMember !is PropertyDescriptor) continue
val reportOnProperty = abstractMember.containingDeclaration == descriptor
val reportOn = if (reportOnProperty) {
(abstractMember.source.getPsi() as? KtProperty)?.valOrVarKeyword ?: funKeyword
} else {
funKeyword
}
context.trace.report(Errors.FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES.on(reportOn))
if (!reportOnProperty) return // It's enough to report only once if abstract properties are in the base class
}
val abstractMember = abstractMembers.filterIsInstance().singleOrNull()
if (abstractMember == null) {
context.trace.report(Errors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS.on(funKeyword))
return
}
checkSingleAbstractMember(abstractMember, funKeyword, context)
}
private fun checkSingleAbstractMember(
abstractMember: FunctionDescriptor,
funInterfaceKeyword: PsiElement,
context: DeclarationCheckerContext,
) {
val ktFunction = abstractMember.source.getPsi() as? KtNamedFunction
if (abstractMember.typeParameters.isNotEmpty()) {
val reportOn = ktFunction?.typeParameterList ?: ktFunction?.funKeyword ?: funInterfaceKeyword
context.trace.report(Errors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS.on(reportOn))
return
}
for (parameter in abstractMember.valueParameters) {
if (parameter.hasDefaultValue()) {
val reportOn = parameter.source.getPsi() ?: ktFunction?.funKeyword ?: funInterfaceKeyword
context.trace.report(Errors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE.on(reportOn))
return
}
}
}
}