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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
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.diagnostics.DiagnosticFactory1;
|
||||||
import org.jetbrains.kotlin.lexer.JetKeywordToken;
|
import org.jetbrains.kotlin.lexer.JetKeywordToken;
|
||||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
|
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.diagnostics.Errors.NESTED_CLASS_NOT_ALLOWED;
|
||||||
import static org.jetbrains.kotlin.lexer.JetTokens.*;
|
import static org.jetbrains.kotlin.lexer.JetTokens.*;
|
||||||
import static org.jetbrains.kotlin.psi.JetStubbedPsiUtil.getContainingDeclaration;
|
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 {
|
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;
|
private static final Set<JetModifierKeywordToken> MODIFIERS_ILLEGAL_ON_PARAMETERS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -190,7 +177,7 @@ public class ModifiersChecker {
|
|||||||
checkNestedClassAllowed(modifierListOwner, descriptor);
|
checkNestedClassAllowed(modifierListOwner, descriptor);
|
||||||
ModifierCheckerCore.INSTANCE$.check(modifierListOwner, trace, descriptor);
|
ModifierCheckerCore.INSTANCE$.check(modifierListOwner, trace, descriptor);
|
||||||
checkTypeParametersModifiers(modifierListOwner);
|
checkTypeParametersModifiers(modifierListOwner);
|
||||||
checkAnnotationUseSiteTargetApplicability(modifierListOwner, descriptor);
|
AnnotationUseSiteTargetChecker.INSTANCE$.check(trace, modifierListOwner, descriptor);
|
||||||
runDeclarationCheckers(modifierListOwner, descriptor);
|
runDeclarationCheckers(modifierListOwner, descriptor);
|
||||||
ClassDescriptor classDescriptor = descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
|
ClassDescriptor classDescriptor = descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null;
|
||||||
annotationChecker.check(modifierListOwner, trace, classDescriptor);
|
annotationChecker.check(modifierListOwner, trace, classDescriptor);
|
||||||
@@ -200,7 +187,7 @@ public class ModifiersChecker {
|
|||||||
@NotNull JetDeclaration modifierListOwner,
|
@NotNull JetDeclaration modifierListOwner,
|
||||||
@NotNull DeclarationDescriptor descriptor
|
@NotNull DeclarationDescriptor descriptor
|
||||||
) {
|
) {
|
||||||
checkAnnotationUseSiteTargetApplicability(modifierListOwner, descriptor);
|
AnnotationUseSiteTargetChecker.INSTANCE$.check(trace, modifierListOwner, descriptor);
|
||||||
runDeclarationCheckers(modifierListOwner, descriptor);
|
runDeclarationCheckers(modifierListOwner, descriptor);
|
||||||
annotationChecker.check(modifierListOwner, trace,
|
annotationChecker.check(modifierListOwner, trace,
|
||||||
descriptor instanceof ClassDescriptor ? (ClassDescriptor) descriptor : null);
|
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
|
@NotNull
|
||||||
public Map<JetModifierKeywordToken, PsiElement> getTokensCorrespondingToModifiers(
|
public Map<JetModifierKeywordToken, PsiElement> getTokensCorrespondingToModifiers(
|
||||||
@NotNull JetModifierList modifierList,
|
@NotNull JetModifierList modifierList,
|
||||||
|
|||||||
Reference in New Issue
Block a user