Move annotation use-site checks to AnnotationUseSiteTargetChecker

This commit is contained in:
Yan Zhulanow
2015-07-17 21:37:33 +03:00
parent 8741b2d083
commit e72ce555e0
2 changed files with 103 additions and 107 deletions
@@ -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<PsiElement>) {
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<PsiElement>): Boolean {
if (descriptor !is PropertyDescriptor) {
report(annotation, diagnosticFactory)
return true
}
return false
}
private fun BindingTrace.report(annotation: AnnotationDescriptor, diagnosticFactory: DiagnosticFactory0<PsiElement>) {
val annotationEntry = get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation) ?: return
report(diagnosticFactory.on(annotationEntry))
}
}
@@ -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<JetModifierKeywordToken> MODALITY_MODIFIERS =
Lists.newArrayList(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD, OVERRIDE_KEYWORD, SEALED_KEYWORD);
private static final Collection<JetModifierKeywordToken> VISIBILITY_MODIFIERS =
Lists.newArrayList(PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD);
private static final Set<JetModifierKeywordToken> 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<PsiElement> 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<PsiElement> diagnosticFactory
) {
if (!(descriptor instanceof PropertyDescriptor)) {
reportAnnotationTargetNotApplicable(annotation, diagnosticFactory);
return true;
}
return false;
}
private void reportAnnotationTargetNotApplicable(AnnotationDescriptor annotation, DiagnosticFactory0<PsiElement> diagnosticFactory) {
JetAnnotationEntry annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation);
if (annotationEntry == null) return;
trace.report(diagnosticFactory.on(annotationEntry));
}
@NotNull
public Map<JetModifierKeywordToken, PsiElement> getTokensCorrespondingToModifiers(
@NotNull JetModifierList modifierList,