Introduce DeclarationCheckerContext, remove SimpleDeclarationChecker

This commit is contained in:
Alexander Udalov
2018-01-03 12:55:59 +01:00
parent 4cb5483c13
commit 8cd7686535
33 changed files with 249 additions and 527 deletions
@@ -17,55 +17,50 @@
package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class ExternalFunChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class ExternalFunChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is MemberDescriptor || !descriptor.isExternal) return
val trace = context.trace
if (descriptor !is FunctionDescriptor) {
val target = when (descriptor) {
is PropertyDescriptor -> "property"
is ClassDescriptor -> "class"
else -> "non-function declaration"
}
diagnosticHolder.report(Errors.WRONG_MODIFIER_TARGET.on(declaration, KtTokens.EXTERNAL_KEYWORD, target))
trace.report(Errors.WRONG_MODIFIER_TARGET.on(declaration, KtTokens.EXTERNAL_KEYWORD, target))
return
}
if (DescriptorUtils.isInterface(descriptor.containingDeclaration)) {
diagnosticHolder.report(ErrorsJvm.EXTERNAL_DECLARATION_IN_INTERFACE.on(declaration))
trace.report(ErrorsJvm.EXTERNAL_DECLARATION_IN_INTERFACE.on(declaration))
}
else if (descriptor.modality == Modality.ABSTRACT) {
if (declaration is KtPropertyAccessor) {
diagnosticHolder.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT.on(declaration.property))
trace.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT.on(declaration.property))
}
else {
diagnosticHolder.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT.on(declaration))
trace.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT.on(declaration))
}
}
if (descriptor !is ConstructorDescriptor && declaration is KtDeclarationWithBody && declaration.hasBody()) {
diagnosticHolder.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_HAVE_BODY.on(declaration))
trace.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_HAVE_BODY.on(declaration))
}
if (InlineUtil.isInline(descriptor)) {
diagnosticHolder.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_INLINED.on(declaration))
trace.report(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_INLINED.on(declaration))
}
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.isInsideJvmMultifileClassFile
import org.jetbrains.kotlin.psi.KtDeclaration
@@ -25,12 +24,13 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmFieldApplicabilityChecker.Problem.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class JvmFieldApplicabilityChecker : SimpleDeclarationChecker {
class JvmFieldApplicabilityChecker : DeclarationChecker {
internal enum class Problem(val errorMessage: String) {
NOT_FINAL("JvmField can only be applied to final property"),
@@ -44,18 +44,13 @@ class JvmFieldApplicabilityChecker : SimpleDeclarationChecker {
DELEGATE("JvmField cannot be applied to delegated property")
}
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val annotation = descriptor.findJvmFieldAnnotation() ?: return
val problem = when {
descriptor !is PropertyDescriptor -> return
declaration is KtProperty && declaration.hasDelegate() -> DELEGATE
!descriptor.hasBackingField(bindingContext) -> return
!descriptor.hasBackingField(context.trace.bindingContext) -> return
descriptor.isOverridable -> NOT_FINAL
Visibilities.isPrivate(descriptor.visibility) -> PRIVATE
descriptor.hasCustomAccessor() -> CUSTOM_ACCESSOR
@@ -69,7 +64,7 @@ class JvmFieldApplicabilityChecker : SimpleDeclarationChecker {
}
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_FIELD.on(annotationEntry, problem.errorMessage))
context.trace.report(ErrorsJvm.INAPPLICABLE_JVM_FIELD.on(annotationEntry, problem.errorMessage))
}
private fun PropertyDescriptor.hasCustomAccessor()
@@ -18,27 +18,20 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.annotations.findJvmSyntheticAnnotation
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class JvmSyntheticApplicabilityChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class JvmSyntheticApplicabilityChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val annotation = descriptor.findJvmSyntheticAnnotation() ?: return
if (declaration is KtProperty && descriptor is VariableDescriptor && declaration.hasDelegate()) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
diagnosticHolder.report(ErrorsJvm.JVM_SYNTHETIC_ON_DELEGATE.on(annotationEntry))
context.trace.report(ErrorsJvm.JVM_SYNTHETIC_ON_DELEGATE.on(annotationEntry))
}
}
}
@@ -18,26 +18,20 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.annotations.findStrictfpAnnotation
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class StrictfpApplicabilityChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class StrictfpApplicabilityChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val annotation = descriptor.findStrictfpAnnotation() ?: return
if (declaration is KtClassOrObject && descriptor is ClassDescriptor) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
diagnosticHolder.report(ErrorsJvm.STRICTFP_ON_CLASS.on(annotationEntry))
context.trace.report(ErrorsJvm.STRICTFP_ON_CLASS.on(annotationEntry))
}
}
}
@@ -27,52 +27,39 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class LocalFunInlineChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class LocalFunInlineChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (InlineUtil.isInline(descriptor) &&
declaration is KtNamedFunction &&
descriptor is FunctionDescriptor &&
descriptor.visibility == Visibilities.LOCAL) {
diagnosticHolder.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(declaration, "Local inline functions"))
context.trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(declaration, "Local inline functions"))
}
}
}
class JvmStaticChecker(jvmTarget: JvmTarget, languageVersionSettings: LanguageVersionSettings) : SimpleDeclarationChecker {
class JvmStaticChecker(jvmTarget: JvmTarget, languageVersionSettings: LanguageVersionSettings) : DeclarationChecker {
private val isLessJVM18 = jvmTarget.bytecodeVersion < JvmTarget.JVM_1_8.bytecodeVersion
private val supportJvmStaticInInterface = languageVersionSettings.supportsFeature(LanguageFeature.JvmStaticInInterface)
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor.hasJvmStaticAnnotation()) {
if (declaration is KtNamedFunction ||
declaration is KtProperty ||
declaration is KtPropertyAccessor ||
declaration is KtParameter) {
checkDeclaration(declaration, descriptor, diagnosticHolder)
checkDeclaration(declaration, descriptor, context.trace)
}
}
}
@@ -130,24 +117,15 @@ class JvmStaticChecker(jvmTarget: JvmTarget, languageVersionSettings: LanguageVe
}
}
class JvmNameAnnotationChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class JvmNameAnnotationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val platformNameAnnotation = DescriptorUtils.getJvmNameAnnotation(descriptor)
if (platformNameAnnotation != null) {
checkDeclaration(descriptor, platformNameAnnotation, diagnosticHolder)
checkDeclaration(descriptor, platformNameAnnotation, context.trace)
}
}
private fun checkDeclaration(
descriptor: DeclarationDescriptor,
annotation: AnnotationDescriptor,
diagnosticHolder: DiagnosticSink
) {
private fun checkDeclaration(descriptor: DeclarationDescriptor, annotation: AnnotationDescriptor, diagnosticHolder: DiagnosticSink) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
if (descriptor is FunctionDescriptor && !isRenamableFunction(descriptor)) {
@@ -173,55 +151,38 @@ class JvmNameAnnotationChecker : SimpleDeclarationChecker {
}
}
class VolatileAnnotationChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class VolatileAnnotationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val volatileAnnotation = DescriptorUtils.getVolatileAnnotation(descriptor)
if (volatileAnnotation != null) {
if (descriptor is PropertyDescriptor && !descriptor.isVar) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(volatileAnnotation) ?: return
diagnosticHolder.report(ErrorsJvm.VOLATILE_ON_VALUE.on(annotationEntry))
context.trace.report(ErrorsJvm.VOLATILE_ON_VALUE.on(annotationEntry))
}
if (declaration is KtProperty && declaration.hasDelegate()) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(volatileAnnotation) ?: return
diagnosticHolder.report(ErrorsJvm.VOLATILE_ON_DELEGATE.on(annotationEntry))
context.trace.report(ErrorsJvm.VOLATILE_ON_DELEGATE.on(annotationEntry))
}
}
}
}
class SynchronizedAnnotationChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class SynchronizedAnnotationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val synchronizedAnnotation = DescriptorUtils.getSynchronizedAnnotation(descriptor)
if (synchronizedAnnotation != null && descriptor is FunctionDescriptor && descriptor.modality == Modality.ABSTRACT) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(synchronizedAnnotation) ?: return
diagnosticHolder.report(ErrorsJvm.SYNCHRONIZED_ON_ABSTRACT.on(annotationEntry))
context.trace.report(ErrorsJvm.SYNCHRONIZED_ON_ABSTRACT.on(annotationEntry))
}
}
}
class OverloadsAnnotationChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class OverloadsAnnotationChecker: DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
descriptor.findJvmOverloadsAnnotation()?.let { annotation ->
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation)
if (annotationEntry != null) {
checkDeclaration(annotationEntry, descriptor, diagnosticHolder)
checkDeclaration(annotationEntry, descriptor, context.trace)
}
}
}
@@ -244,13 +205,8 @@ class OverloadsAnnotationChecker : SimpleDeclarationChecker {
}
}
class TypeParameterBoundIsNotArrayChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class TypeParameterBoundIsNotArrayChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val typeParameters = (descriptor as? CallableDescriptor)?.typeParameters
?: (descriptor as? ClassDescriptor)?.declaredTypeParameters
?: return
@@ -258,8 +214,8 @@ class TypeParameterBoundIsNotArrayChecker : SimpleDeclarationChecker {
for (typeParameter in typeParameters) {
if (typeParameter.upperBounds.any { KotlinBuiltIns.isArray(it) || KotlinBuiltIns.isPrimitiveArray(it) }) {
val element = DescriptorToSourceUtils.descriptorToDeclaration(typeParameter) ?: declaration
diagnosticHolder.report(ErrorsJvm.UPPER_BOUND_CANNOT_BE_ARRAY.on(element))
context.trace.report(ErrorsJvm.UPPER_BOUND_CANNOT_BE_ARRAY.on(element))
}
}
}
}
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker;
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext;
import org.jetbrains.kotlin.resolve.checkers.PublishedApiUsageChecker;
import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker;
@@ -276,12 +277,11 @@ public class ModifiersChecker {
}
public void runDeclarationCheckers(
@NotNull KtDeclaration declaration,
@NotNull DeclarationDescriptor descriptor
) {
public void runDeclarationCheckers(@NotNull KtDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
DeclarationCheckerContext context =
new DeclarationCheckerContext(trace, languageVersionSettings, deprecationResolver, expectActualTracker);
for (DeclarationChecker checker : declarationCheckers) {
checker.check(declaration, descriptor, trace, trace.getBindingContext(), languageVersionSettings, expectActualTracker);
checker.check(declaration, descriptor, context);
}
OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageVersionSettings);
PublishedApiUsageChecker.INSTANCE.check(declaration, descriptor, trace);
@@ -296,28 +296,24 @@ public class ModifiersChecker {
}
}
@NotNull
private final AnnotationChecker annotationChecker;
@NotNull
private final Iterable<DeclarationChecker> declarationCheckers;
@NotNull
private final LanguageVersionSettings languageVersionSettings;
@NotNull
private final ExpectActualTracker expectActualTracker;
private final DeprecationResolver deprecationResolver;
public ModifiersChecker(
@NotNull AnnotationChecker annotationChecker,
@NotNull Iterable<DeclarationChecker> declarationCheckers,
@NotNull LanguageVersionSettings languageVersionSettings,
@NotNull ExpectActualTracker expectActualTracker
@NotNull ExpectActualTracker expectActualTracker,
@NotNull DeprecationResolver deprecationResolver
) {
this.annotationChecker = annotationChecker;
this.declarationCheckers = declarationCheckers;
this.languageVersionSettings = languageVersionSettings;
this.expectActualTracker = expectActualTracker;
this.deprecationResolver = deprecationResolver;
}
@NotNull
@@ -19,28 +19,21 @@ package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.isError
object ConstModifierChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
object ConstModifierChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is VariableDescriptor || !declaration.hasModifier(KtTokens.CONST_KEYWORD)) return
val constModifierPsiElement = declaration.modifierList!!.getModifier(KtTokens.CONST_KEYWORD)!!
val diagnostic = checkCanBeConst(declaration, constModifierPsiElement, descriptor).diagnostic
if (diagnostic != null) {
diagnosticHolder.report(diagnostic)
context.trace.report(diagnostic)
}
}
@@ -18,39 +18,32 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
class DataClassDeclarationChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class DataClassDeclarationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is ClassDescriptor) return
if (declaration !is KtClassOrObject) return
if (descriptor.isData) {
if (descriptor.unsubstitutedPrimaryConstructor == null && descriptor.constructors.isNotEmpty()) {
declaration.nameIdentifier?.let { diagnosticHolder.report(Errors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS.on(it)) }
declaration.nameIdentifier?.let { context.trace.report(Errors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS.on(it)) }
}
val primaryConstructor = declaration.primaryConstructor
val parameters = primaryConstructor?.valueParameters ?: emptyList()
if (parameters.isEmpty()) {
(primaryConstructor?.valueParameterList ?: declaration.nameIdentifier)?.let {
diagnosticHolder.report(Errors.DATA_CLASS_WITHOUT_PARAMETERS.on(it))
context.trace.report(Errors.DATA_CLASS_WITHOUT_PARAMETERS.on(it))
}
}
for (parameter in parameters) {
if (parameter.isVarArg) {
diagnosticHolder.report(Errors.DATA_CLASS_VARARG_PARAMETER.on(parameter))
context.trace.report(Errors.DATA_CLASS_VARARG_PARAMETER.on(parameter))
}
if (!parameter.hasValOrVar()) {
diagnosticHolder.report(Errors.DATA_CLASS_NOT_PROPERTY_PARAMETER.on(parameter))
context.trace.report(Errors.DATA_CLASS_NOT_PROPERTY_PARAMETER.on(parameter))
}
}
}
@@ -18,37 +18,18 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeprecationResolver
interface DeclarationChecker {
// TODO: Think about encapsulating these parameters into specific class like CheckerParameters when you're about to add another one
fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
)
fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext)
}
interface SimpleDeclarationChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
) = check(declaration, descriptor, diagnosticHolder, bindingContext)
fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
)
}
class DeclarationCheckerContext(
override val trace: BindingTrace,
override val languageVersionSettings: LanguageVersionSettings,
override val deprecationResolver: DeprecationResolver,
val expectActualTracker: ExpectActualTracker
) : CheckerContext
@@ -16,14 +16,12 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
@@ -33,24 +31,17 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.OverridingUtil
class DelegationChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
) {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is ClassDescriptor) return
if (declaration !is KtClassOrObject) return
for (specifier in declaration.superTypeListEntries) {
if (specifier is KtDelegatedSuperTypeEntry) {
val superType = specifier.typeReference?.let { bindingContext.get(BindingContext.TYPE, it) } ?: continue
val superType = specifier.typeReference?.let { context.trace.get(BindingContext.TYPE, it) } ?: continue
val superTypeDescriptor = superType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
for ((delegated, delegatedTo) in DelegationResolver.getDelegates(descriptor, superTypeDescriptor)) {
checkDescriptor(declaration, delegated, delegatedTo, diagnosticHolder)
checkDescriptor(declaration, delegated, delegatedTo, context.trace)
}
}
}
@@ -18,29 +18,22 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
import org.jetbrains.kotlin.types.isDynamic
object DynamicReceiverChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
object DynamicReceiverChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is CallableDescriptor || declaration !is KtCallableDeclaration || descriptor.hasDynamicExtensionAnnotation()) return
// function expression
if (declaration is KtNamedFunction && declaration.name == null) return
if (descriptor.extensionReceiverParameter?.value?.type?.isDynamic() == true) {
diagnosticHolder.report(Errors.DYNAMIC_RECEIVER_NOT_ALLOWED.on(declaration))
context.trace.report(Errors.DYNAMIC_RECEIVER_NOT_ALLOWED.on(declaration))
}
}
}
}
@@ -20,7 +20,6 @@ import com.intellij.openapi.vfs.VfsUtilCore
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.AnalysisFlag
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
@@ -32,7 +31,6 @@ import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Compatible
@@ -56,24 +54,17 @@ import org.jetbrains.kotlin.utils.keysToMap
import java.io.File
object ExpectedActualDeclarationChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) return
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) return
if (declaration !is KtNamedDeclaration) return
if (descriptor !is MemberDescriptor || DescriptorUtils.isEnumEntry(descriptor)) return
if (descriptor.isExpect) {
checkExpectedDeclarationHasActual(declaration, descriptor, diagnosticHolder, descriptor.module, expectActualTracker)
checkExpectedDeclarationHasActual(declaration, descriptor, context.trace, descriptor.module, context.expectActualTracker)
} else {
val checkActual = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckActual)
checkActualDeclarationHasExpected(declaration, descriptor, diagnosticHolder, checkActual)
val checkActual = !context.languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckActual)
checkActualDeclarationHasExpected(declaration, descriptor, context.trace, checkActual)
}
}
@@ -18,22 +18,14 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.util.CheckResult
import org.jetbrains.kotlin.util.InfixChecks
class InfixModifierChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class InfixModifierChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
if (!functionDescriptor.isInfix) return
val modifier = declaration.modifierList?.getModifier(KtTokens.INFIX_KEYWORD) ?: return
@@ -41,6 +33,6 @@ class InfixModifierChecker : SimpleDeclarationChecker {
val checkResult = InfixChecks.check(functionDescriptor)
if (checkResult !is CheckResult.IllegalSignature) return
diagnosticHolder.report(Errors.INAPPLICABLE_INFIX_MODIFIER.on(modifier, checkResult.error))
context.trace.report(Errors.INAPPLICABLE_INFIX_MODIFIER.on(modifier, checkResult.error))
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
@@ -29,22 +28,20 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext
object InlineParameterChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
) {
object InlineParameterChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration is KtFunction) {
val inline = declaration.hasModifier(KtTokens.INLINE_KEYWORD)
for (parameter in declaration.valueParameters) {
val parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, parameter)
val parameterDescriptor = context.trace.get(BindingContext.VALUE_PARAMETER, parameter)
if (!inline || (parameterDescriptor != null && !parameterDescriptor.type.isBuiltinFunctionalType)) {
parameter.reportIncorrectInline(KtTokens.NOINLINE_KEYWORD, diagnosticHolder)
parameter.reportIncorrectInline(KtTokens.CROSSINLINE_KEYWORD, diagnosticHolder)
parameter.reportIncorrectInline(KtTokens.NOINLINE_KEYWORD, context.trace)
parameter.reportIncorrectInline(KtTokens.CROSSINLINE_KEYWORD, context.trace)
}
if (inline && !parameter.hasModifier(KtTokens.NOINLINE_KEYWORD) &&
parameterDescriptor?.type?.isSuspendFunctionType == true) {
diagnosticHolder.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter))
context.trace.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter))
}
}
}
@@ -18,23 +18,16 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
object KClassWithIncorrectTypeArgumentChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
object KClassWithIncorrectTypeArgumentChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is CallableMemberDescriptor || descriptor.visibility == Visibilities.LOCAL) return
if (declaration !is KtCallableDeclaration || declaration.typeReference != null) return
@@ -58,11 +51,8 @@ object KClassWithIncorrectTypeArgumentChecker : SimpleDeclarationChecker {
}
if (typeParameterWithoutNotNullableUpperBound != null) {
diagnosticHolder.report(
Errors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE.on(
declaration,
typeParameterWithoutNotNullableUpperBound!!
)
context.trace.report(
Errors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE.on(declaration, typeParameterWithoutNotNullableUpperBound!!)
)
}
}
@@ -22,10 +22,8 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.RequireKotlinNames
import org.jetbrains.kotlin.resolve.SINCE_KOTLIN_FQ_NAME
import org.jetbrains.kotlin.resolve.source.getPsi
@@ -33,26 +31,15 @@ import org.jetbrains.kotlin.resolve.source.getPsi
abstract class KotlinVersionStringAnnotationValueChecker(
private val annotationFqName: FqName
) : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
) {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val annotation = descriptor.annotations.findAnnotation(annotationFqName) ?: return
val version = annotation.allValueArguments.values.singleOrNull()?.value as? String ?: return
if (!version.matches(VERSION_REGEX)) {
diagnosticHolder.report(
Errors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE.on(
annotation.source.getPsi() ?: declaration, annotationFqName
)
)
context.trace.report(Errors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE.on(annotation.source.getPsi() ?: declaration, annotationFqName))
return
}
extraCheck(declaration, annotation, version, diagnosticHolder, languageVersionSettings)
extraCheck(declaration, annotation, version, context.trace, context.languageVersionSettings)
}
open fun extraCheck(
@@ -25,25 +25,18 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.inline.InlineUtil
class ReifiedTypeParameterAnnotationChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
class ReifiedTypeParameterAnnotationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor is CallableDescriptor &&
!(InlineUtil.isInline(descriptor) || InlineUtil.isPropertyWithAllAccessorsAreInline(descriptor))) {
checkTypeParameterDescriptorsAreNotReified(descriptor.typeParameters, diagnosticHolder)
checkTypeParameterDescriptorsAreNotReified(descriptor.typeParameters, context.trace)
}
if (descriptor is ClassDescriptor) {
checkTypeParameterDescriptorsAreNotReified(descriptor.declaredTypeParameters, diagnosticHolder)
checkTypeParameterDescriptorsAreNotReified(descriptor.declaredTypeParameters, context.trace)
}
}
@@ -18,29 +18,22 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.util.OperatorNameConventions
object SuspendOperatorsCheckers : SimpleDeclarationChecker {
object SuspendOperatorsCheckers : DeclarationChecker {
private val UNSUPPORTED_OPERATOR_NAMES = setOf(
OperatorNameConventions.CONTAINS,
OperatorNameConventions.GET, OperatorNameConventions.SET
)
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor is FunctionDescriptor && descriptor.isSuspend && descriptor.isOperator &&
descriptor.name in UNSUPPORTED_OPERATOR_NAMES) {
declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD)?.let {
diagnosticHolder.report(Errors.UNSUPPORTED.on(it, "suspend operator \"${descriptor.name}\""))
context.trace.report(Errors.UNSUPPORTED.on(it, "suspend operator \"${descriptor.name}\""))
}
}
}
@@ -24,12 +24,9 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
object UnderscoreChecker : DeclarationChecker {
@JvmOverloads
fun checkIdentifier(
identifier: PsiElement?,
@@ -61,29 +58,22 @@ object UnderscoreChecker : DeclarationChecker {
checkIdentifier(declaration.nameIdentifier, diagnosticHolder, languageVersionSettings, allowSingleUnderscore)
}
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
) {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration is KtProperty && descriptor !is VariableDescriptor) return
if (declaration is KtCallableDeclaration) {
for (parameter in declaration.valueParameters) {
checkNamed(
parameter, diagnosticHolder, languageVersionSettings,
parameter, context.trace, context.languageVersionSettings,
allowSingleUnderscore = descriptor is FunctionExpressionDescriptor
)
}
}
if (declaration is KtTypeParameterListOwner) {
for (typeParameter in declaration.typeParameters) {
checkNamed(typeParameter, diagnosticHolder, languageVersionSettings)
checkNamed(typeParameter, context.trace, context.languageVersionSettings)
}
}
if (declaration !is KtNamedDeclaration) return
checkNamed(declaration, diagnosticHolder, languageVersionSettings)
checkNamed(declaration, context.trace, context.languageVersionSettings)
}
}