From 8849d7d10a6f974918b81408ad1bd5055992f352 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 17 Jul 2015 22:43:07 +0300 Subject: [PATCH] Check @param target applicability --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../resolve/AnnotationUseSiteTargetChecker.kt | 46 +++++++++++++------ .../kotlin/resolve/ModifiersChecker.java | 4 +- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 66de61eb6ac..06cf0fc7e57 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -139,6 +139,7 @@ public interface Errors { DiagnosticFactory0 INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INAPPLICABLE_RECEIVER_TARGET = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INAPPLICABLE_SPARAM_TARGET = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 INAPPLICABLE_PARAM_TARGET = DiagnosticFactory0.create(ERROR); // Classes and traits diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index df8dc780cd5..9ebdbf85681 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -132,6 +132,7 @@ public class DefaultErrorMessages { MAP.put(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, "Property must be mutable"); MAP.put(INAPPLICABLE_RECEIVER_TARGET, "''@receiver:'' annotations could be applied only to extension function or extension property declarations"); MAP.put(INAPPLICABLE_SPARAM_TARGET, "''@sparam:'' annotations could be applied only to property declarations"); + MAP.put(INAPPLICABLE_PARAM_TARGET, "''@param:'' annotations could be applied only to primary constructor parameters"); MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING); MAP.put(ABSTRACT_MODIFIER_IN_TRAIT, "Modifier ''abstract'' is redundant in interface"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt index fbc58170eff..2a098a6f286 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt @@ -17,27 +17,34 @@ package org.jetbrains.kotlin.resolve import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 -import org.jetbrains.kotlin.psi.JetDeclaration -import org.jetbrains.kotlin.psi.JetProperty import org.jetbrains.kotlin.diagnostics.Errors.* -import org.jetbrains.kotlin.psi.JetAnnotationEntry +import org.jetbrains.kotlin.psi.* public object AnnotationUseSiteTargetChecker { - public fun BindingTrace.check(modifierListOwner: JetDeclaration, descriptor: DeclarationDescriptor) { - for (annotationWithTarget in descriptor.getAnnotations().getUseSiteTargetedAnnotations()) { + public fun check(annotated: JetAnnotated, descriptor: DeclarationDescriptor, trace: BindingTrace) { + trace.checkDeclaration(annotated, descriptor) + + if (annotated is JetFunction) { + for (parameter in annotated.valueParameters) { + val parameterDescriptor = trace.bindingContext[BindingContext.VALUE_PARAMETER, parameter] ?: continue + trace.checkDeclaration(parameter, parameterDescriptor) + } + } + + } + + private fun BindingTrace.checkDeclaration(annotated: JetAnnotated, descriptor: DeclarationDescriptor) { + for (annotationWithTarget in descriptor.annotations.getUseSiteTargetedAnnotations()) { val annotation = annotationWithTarget.annotation val target = annotationWithTarget.target ?: continue when (target) { - AnnotationUseSiteTarget.FIELD -> checkFieldTargetApplicability(modifierListOwner, descriptor, annotation) + AnnotationUseSiteTarget.FIELD -> checkFieldTargetApplicability(annotated, descriptor, annotation) AnnotationUseSiteTarget.PROPERTY -> checkIfPropertyDescriptor(descriptor, annotation, INAPPLICABLE_PROPERTY_TARGET) AnnotationUseSiteTarget.PROPERTY_GETTER -> checkIfPropertyDescriptor(descriptor, annotation, INAPPLICABLE_GET_TARGET) AnnotationUseSiteTarget.PROPERTY_SETTER -> checkMutableProperty(descriptor, annotation, INAPPLICABLE_SET_TARGET) @@ -45,10 +52,21 @@ public object AnnotationUseSiteTargetChecker { if (descriptor !is FunctionDescriptor && descriptor !is PropertyDescriptor) { report(annotation, INAPPLICABLE_RECEIVER_TARGET) } - else if ((descriptor as CallableMemberDescriptor).getExtensionReceiverParameter() == null) { + else if ((descriptor as CallableMemberDescriptor).extensionReceiverParameter == null) { report(annotation, INAPPLICABLE_RECEIVER_TARGET) } } + AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> { + if (annotated !is JetParameter) { + report(annotation, INAPPLICABLE_PARAM_TARGET) + } + else { + val containingDeclaration = bindingContext[BindingContext.VALUE_PARAMETER, annotated]?.containingDeclaration + if (containingDeclaration !is ConstructorDescriptor || !containingDeclaration.isPrimary) { + report(annotation, INAPPLICABLE_PARAM_TARGET) + } + } + } AnnotationUseSiteTarget.SETTER_PARAMETER -> checkMutableProperty(descriptor, annotation, INAPPLICABLE_SPARAM_TARGET) AnnotationUseSiteTarget.FILE -> throw IllegalArgumentException("@file annotations are not allowed here") } @@ -56,7 +74,7 @@ public object AnnotationUseSiteTargetChecker { } private fun BindingTrace.checkFieldTargetApplicability( - modifierListOwner: JetDeclaration, + modifierListOwner: JetAnnotated, descriptor: DeclarationDescriptor, annotation: AnnotationDescriptor) { if (checkIfPropertyDescriptor(descriptor, annotation, INAPPLICABLE_FIELD_TARGET)) return @@ -76,7 +94,7 @@ public object AnnotationUseSiteTargetChecker { checkIfPropertyDescriptor(descriptor, annotation, diagnosticFactory) if (descriptor is PropertyDescriptor) { - if (!descriptor.isVar()) { + if (!descriptor.isVar) { report(annotation, INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE) } } @@ -94,7 +112,7 @@ public object AnnotationUseSiteTargetChecker { } private fun BindingTrace.report(annotation: AnnotationDescriptor, diagnosticFactory: DiagnosticFactory0) { - val annotationEntry = get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation) ?: return + val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return report(diagnosticFactory.on(annotationEntry)) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index 03d1cee2eac..99f46456168 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -177,7 +177,7 @@ public class ModifiersChecker { checkNestedClassAllowed(modifierListOwner, descriptor); ModifierCheckerCore.INSTANCE$.check(modifierListOwner, trace, descriptor); checkTypeParametersModifiers(modifierListOwner); - AnnotationUseSiteTargetChecker.INSTANCE$.check(trace, modifierListOwner, descriptor); + AnnotationUseSiteTargetChecker.INSTANCE$.check(modifierListOwner, descriptor, trace); runDeclarationCheckers(modifierListOwner, descriptor); ClassDescriptor classDescriptor = descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null; annotationChecker.check(modifierListOwner, trace, classDescriptor); @@ -187,7 +187,7 @@ public class ModifiersChecker { @NotNull JetDeclaration modifierListOwner, @NotNull DeclarationDescriptor descriptor ) { - AnnotationUseSiteTargetChecker.INSTANCE$.check(trace, modifierListOwner, descriptor); + AnnotationUseSiteTargetChecker.INSTANCE$.check(modifierListOwner, descriptor, trace); runDeclarationCheckers(modifierListOwner, descriptor); annotationChecker.check(modifierListOwner, trace, descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);