diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt new file mode 100644 index 00000000000..fbc58170eff --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUseSiteTargetChecker.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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.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 + +public object AnnotationUseSiteTargetChecker { + + public fun BindingTrace.check(modifierListOwner: JetDeclaration, descriptor: DeclarationDescriptor) { + for (annotationWithTarget in descriptor.getAnnotations().getUseSiteTargetedAnnotations()) { + val annotation = annotationWithTarget.annotation + val target = annotationWithTarget.target ?: continue + + when (target) { + AnnotationUseSiteTarget.FIELD -> checkFieldTargetApplicability(modifierListOwner, 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) + AnnotationUseSiteTarget.RECEIVER -> { + if (descriptor !is FunctionDescriptor && descriptor !is PropertyDescriptor) { + report(annotation, INAPPLICABLE_RECEIVER_TARGET) + } + else if ((descriptor as CallableMemberDescriptor).getExtensionReceiverParameter() == null) { + report(annotation, INAPPLICABLE_RECEIVER_TARGET) + } + } + AnnotationUseSiteTarget.SETTER_PARAMETER -> checkMutableProperty(descriptor, annotation, INAPPLICABLE_SPARAM_TARGET) + AnnotationUseSiteTarget.FILE -> throw IllegalArgumentException("@file annotations are not allowed here") + } + } + } + + private fun BindingTrace.checkFieldTargetApplicability( + modifierListOwner: JetDeclaration, + descriptor: DeclarationDescriptor, + annotation: AnnotationDescriptor) { + if (checkIfPropertyDescriptor(descriptor, annotation, INAPPLICABLE_FIELD_TARGET)) return + + descriptor as PropertyDescriptor + val hasDelegate = modifierListOwner is JetProperty && modifierListOwner.hasDelegate() + + if (!hasDelegate && !(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) ?: false)) { + report(annotation, INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD) + } + } + + private fun BindingTrace.checkMutableProperty( + descriptor: DeclarationDescriptor, + annotation: AnnotationDescriptor, + diagnosticFactory: DiagnosticFactory0) { + checkIfPropertyDescriptor(descriptor, annotation, diagnosticFactory) + + if (descriptor is PropertyDescriptor) { + if (!descriptor.isVar()) { + report(annotation, INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE) + } + } + } + + private fun BindingTrace.checkIfPropertyDescriptor( + descriptor: DeclarationDescriptor, + annotation: AnnotationDescriptor, + diagnosticFactory: DiagnosticFactory0): Boolean { + if (descriptor !is PropertyDescriptor) { + report(annotation, diagnosticFactory) + return true + } + return false + } + + private fun BindingTrace.report(annotation: AnnotationDescriptor, diagnosticFactory: DiagnosticFactory0) { + val annotationEntry = get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation) ?: return + report(diagnosticFactory.on(annotationEntry)) + } + +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index b2e6f00188a..03d1cee2eac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -23,10 +23,6 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; -import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget; -import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1; import org.jetbrains.kotlin.lexer.JetKeywordToken; import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; @@ -38,17 +34,8 @@ import java.util.*; import static org.jetbrains.kotlin.diagnostics.Errors.NESTED_CLASS_NOT_ALLOWED; import static org.jetbrains.kotlin.lexer.JetTokens.*; import static org.jetbrains.kotlin.psi.JetStubbedPsiUtil.getContainingDeclaration; -import static org.jetbrains.kotlin.resolve.BindingContext.BACKING_FIELD_REQUIRED; -import static org.jetbrains.kotlin.diagnostics.Errors.INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD; -import static org.jetbrains.kotlin.diagnostics.Errors.INAPPLICABLE_FIELD_TARGET; public class ModifiersChecker { - private static final Collection MODALITY_MODIFIERS = - Lists.newArrayList(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD, OVERRIDE_KEYWORD, SEALED_KEYWORD); - - private static final Collection VISIBILITY_MODIFIERS = - Lists.newArrayList(PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD); - private static final Set MODIFIERS_ILLEGAL_ON_PARAMETERS; static { @@ -190,7 +177,7 @@ public class ModifiersChecker { checkNestedClassAllowed(modifierListOwner, descriptor); ModifierCheckerCore.INSTANCE$.check(modifierListOwner, trace, descriptor); checkTypeParametersModifiers(modifierListOwner); - checkAnnotationUseSiteTargetApplicability(modifierListOwner, descriptor); + AnnotationUseSiteTargetChecker.INSTANCE$.check(trace, modifierListOwner, descriptor); runDeclarationCheckers(modifierListOwner, descriptor); ClassDescriptor classDescriptor = descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null; annotationChecker.check(modifierListOwner, trace, classDescriptor); @@ -200,7 +187,7 @@ public class ModifiersChecker { @NotNull JetDeclaration modifierListOwner, @NotNull DeclarationDescriptor descriptor ) { - checkAnnotationUseSiteTargetApplicability(modifierListOwner, descriptor); + AnnotationUseSiteTargetChecker.INSTANCE$.check(trace, modifierListOwner, descriptor); runDeclarationCheckers(modifierListOwner, descriptor); annotationChecker.check(modifierListOwner, trace, descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null); @@ -218,98 +205,6 @@ public class ModifiersChecker { } } - - private void checkAnnotationUseSiteTargetApplicability( - @NotNull JetDeclaration modifierListOwner, - @NotNull DeclarationDescriptor descriptor - ) { - for (AnnotationWithTarget annotationWithTarget : descriptor.getAnnotations().getUseSiteTargetedAnnotations()) { - AnnotationDescriptor annotation = annotationWithTarget.getAnnotation(); - AnnotationUseSiteTarget target = annotationWithTarget.getTarget(); - if (target == null) return; - - switch (target) { - case FIELD: - checkFieldTargetApplicability(modifierListOwner, descriptor, annotation); - break; - case FILE: - throw new IllegalArgumentException("@file annotations are not allowed here"); - case PROPERTY: - reportIfNotPropertyDescriptor(descriptor, annotation, INAPPLICABLE_PROPERTY_TARGET); - break; - case PROPERTY_GETTER: - reportIfNotPropertyDescriptor(descriptor, annotation, INAPPLICABLE_GET_TARGET); - break; - case PROPERTY_SETTER: { - reportIfNotMutableProperty(descriptor, annotation, INAPPLICABLE_SET_TARGET); - break; - } - case RECEIVER: { - if (!(descriptor instanceof FunctionDescriptor) && !(descriptor instanceof PropertyDescriptor)) { - reportAnnotationTargetNotApplicable(annotation, INAPPLICABLE_RECEIVER_TARGET); - break; - } - - if (((CallableMemberDescriptor) descriptor).getExtensionReceiverParameter() == null) { - reportAnnotationTargetNotApplicable(annotation, INAPPLICABLE_RECEIVER_TARGET); - } - break; - } - case SETTER_PARAMETER: { - reportIfNotMutableProperty(descriptor, annotation, INAPPLICABLE_SPARAM_TARGET); - break; - } - } - } - } - - private void reportIfNotMutableProperty( - DeclarationDescriptor descriptor, - AnnotationDescriptor annotation, - DiagnosticFactory0 diagnosticFactory - ) { - reportIfNotPropertyDescriptor(descriptor, annotation, diagnosticFactory); - - if (descriptor instanceof PropertyDescriptor) { - if (!((PropertyDescriptor) descriptor).isVar()) { - reportAnnotationTargetNotApplicable(annotation, INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE); - } - } - } - - private void checkFieldTargetApplicability( - JetDeclaration modifierListOwner, - DeclarationDescriptor descriptor, - AnnotationDescriptor annotation - ) { - if (reportIfNotPropertyDescriptor(descriptor, annotation, INAPPLICABLE_FIELD_TARGET)) return; - - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; - boolean hasDelegate = modifierListOwner instanceof JetProperty && ((JetProperty) modifierListOwner).hasDelegate(); - - if (!hasDelegate && Boolean.FALSE.equals(trace.getBindingContext().get(BACKING_FIELD_REQUIRED, propertyDescriptor))) { - reportAnnotationTargetNotApplicable(annotation, INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD); - } - } - - private boolean reportIfNotPropertyDescriptor( - DeclarationDescriptor descriptor, - AnnotationDescriptor annotation, - DiagnosticFactory0 diagnosticFactory - ) { - if (!(descriptor instanceof PropertyDescriptor)) { - reportAnnotationTargetNotApplicable(annotation, diagnosticFactory); - return true; - } - return false; - } - - private void reportAnnotationTargetNotApplicable(AnnotationDescriptor annotation, DiagnosticFactory0 diagnosticFactory) { - JetAnnotationEntry annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation); - if (annotationEntry == null) return; - trace.report(diagnosticFactory.on(annotationEntry)); - } - @NotNull public Map getTokensCorrespondingToModifiers( @NotNull JetModifierList modifierList,