Move annotation use-site checks to AnnotationUseSiteTargetChecker
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user