Use KotlinJvmCheckerProvider to check @publicField

This commit is contained in:
Yan Zhulanow
2015-07-03 21:47:46 +03:00
parent 3bcdee2a20
commit 9c8ea54946
11 changed files with 89 additions and 42 deletions
@@ -26,10 +26,8 @@ import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNullable
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeFunChecker
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.AdditionalCheckerProvider
import org.jetbrains.kotlin.resolve.DeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.annotations.findPublicFieldAnnotation
import org.jetbrains.kotlin.resolve.annotations.hasInlineAnnotation
import org.jetbrains.kotlin.resolve.annotations.hasIntrinsicAnnotation
import org.jetbrains.kotlin.resolve.annotations.hasPlatformStaticAnnotation
@@ -57,7 +55,8 @@ public class KotlinJvmCheckerProvider(private val module: ModuleDescriptor) : Ad
LocalFunInlineChecker(),
ReifiedTypeParameterAnnotationChecker(),
NativeFunChecker(),
OverloadsAnnotationChecker()),
OverloadsAnnotationChecker(),
PublicFieldAnnotationChecker()),
additionalCallCheckers = listOf(NeedSyntheticChecker(), JavaAnnotationCallChecker(),
JavaAnnotationMethodCallChecker(), TraitDefaultMethodCallChecker()),
@@ -68,7 +67,11 @@ public class KotlinJvmCheckerProvider(private val module: ModuleDescriptor) : Ad
public class LocalFunInlineChecker : DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext) {
if (descriptor.hasInlineAnnotation() &&
declaration is JetNamedFunction &&
descriptor is FunctionDescriptor &&
@@ -80,7 +83,12 @@ public class LocalFunInlineChecker : DeclarationChecker {
public class PlatformStaticAnnotationChecker : DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor.hasPlatformStaticAnnotation()) {
if (declaration is JetNamedFunction || declaration is JetProperty || declaration is JetPropertyAccessor) {
checkDeclaration(declaration, descriptor, diagnosticHolder)
@@ -119,7 +127,12 @@ public class PlatformStaticAnnotationChecker : DeclarationChecker {
}
public class OverloadsAnnotationChecker: DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor.getAnnotations().findAnnotation(FqName("kotlin.jvm.jvmOverloads")) != null) {
checkDeclaration(declaration, descriptor, diagnosticHolder)
}
@@ -142,9 +155,37 @@ public class OverloadsAnnotationChecker: DeclarationChecker {
}
}
public class PublicFieldAnnotationChecker: DeclarationChecker {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
val annotation = descriptor.findPublicFieldAnnotation() ?: return
fun report() {
val annotationEntry = bindingContext.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation) ?: return
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry))
}
if (descriptor !is PropertyDescriptor) {
report()
}
else if (!bindingContext.get<PropertyDescriptor, Boolean>(BindingContext.BACKING_FIELD_REQUIRED, descriptor)) {
report()
}
}
}
public class ReifiedTypeParameterAnnotationChecker : DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor.hasIntrinsicAnnotation()) return
if (descriptor is CallableDescriptor && !descriptor.hasInlineAnnotation()) {
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.psi.JetDeclarationWithBody
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.annotations.hasInlineAnnotation
import org.jetbrains.kotlin.resolve.diagnostics.SuppressDiagnosticsByAnnotations
import org.jetbrains.kotlin.resolve.diagnostics.FUNCTION_NO_BODY_ERRORS
@@ -41,7 +42,12 @@ public fun DeclarationDescriptor.hasNativeAnnotation(): Boolean {
public class SuppressNoBodyErrorsForNativeDeclarations : SuppressDiagnosticsByAnnotations(FUNCTION_NO_BODY_ERRORS, NATIVE_ANNOTATION_CLASS_NAME)
public class NativeFunChecker : DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (!descriptor.hasNativeAnnotation()) return
if (DescriptorUtils.isTrait(descriptor.getContainingDeclaration())) {
@@ -68,6 +68,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(ErrorsJvm.TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER, "Interfaces can't call Java default methods via super");
MAP.put(ErrorsJvm.WHEN_ENUM_CAN_BE_NULL_IN_JAVA, "Enum argument can be null in Java, but exhaustive when contains no null branch");
MAP.put(ErrorsJvm.INAPPLICABLE_PUBLIC_FIELD, "publicField annotation is not applicable to this declaration");
}
@NotNull
@@ -56,6 +56,8 @@ public interface ErrorsJvm {
DiagnosticFactory0<JetElement> TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetElement> INAPPLICABLE_PUBLIC_FIELD = DiagnosticFactory0.create(ERROR);
// TODO: make this a warning
DiagnosticFactory1<JetExpression, JetExpression> NO_REFLECTION_IN_CLASS_PATH = DiagnosticFactory1.create(ERROR);
@@ -114,7 +114,6 @@ public interface Errors {
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, JetModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory0<PsiElement> INAPPLICABLE_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PLATFORM_NAME = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PUBLIC_FIELD = DiagnosticFactory0.create(ERROR);
// Annotations
@@ -137,7 +137,6 @@ public class DefaultErrorMessages {
MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING);
MAP.put(INAPPLICABLE_ANNOTATION, "This annotation is only applicable to top level functions");
MAP.put(INAPPLICABLE_PLATFORM_NAME, "platformName annotation is not applicable to this declaration");
MAP.put(INAPPLICABLE_PUBLIC_FIELD, "publicField annotation is not applicable to this declaration");
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");
@@ -23,7 +23,12 @@ import org.jetbrains.kotlin.builtins.*
public class DataClassAnnotationChecker : DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor !is ClassDescriptor) return
if (declaration !is JetClassOrObject) return
@@ -20,8 +20,12 @@ import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
public trait DeclarationChecker {
public interface DeclarationChecker {
public fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink);
public fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext);
}
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.StringValue;
@@ -150,7 +149,6 @@ public class ModifiersChecker {
checkVarargsModifiers(modifierListOwner, descriptor);
}
checkPlatformNameApplicability(descriptor);
checkPublicFieldApplicability(descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
}
@@ -164,7 +162,6 @@ public class ModifiersChecker {
reportIllegalModalityModifiers(modifierListOwner);
reportIllegalVisibilityModifiers(modifierListOwner);
checkPlatformNameApplicability(descriptor);
checkPublicFieldApplicability(descriptor);
runDeclarationCheckers(modifierListOwner, descriptor);
}
@@ -323,24 +320,6 @@ public class ModifiersChecker {
}
private void checkPublicFieldApplicability(@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = AnnotationsPackage.findPublicFieldAnnotation(descriptor);
if (annotation == null) return;
JetAnnotationEntry annotationEntry = trace.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation);
if (annotationEntry == null) return;
if (!(descriptor instanceof PropertyDescriptor)) {
trace.report(INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry));
return;
}
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (Boolean.FALSE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) {
trace.report(INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry));
}
}
private static boolean isRenamableDeclaration(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
@@ -442,7 +421,7 @@ public class ModifiersChecker {
private void runDeclarationCheckers(@NotNull JetDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
for (DeclarationChecker checker : additionalCheckerProvider.getDeclarationCheckers()) {
checker.check(declaration, descriptor, trace);
checker.check(declaration, descriptor, trace, trace.getBindingContext());
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.TypeUtils
@@ -35,9 +36,13 @@ private abstract class AbstractNativeAnnotationsChecker(private val requiredAnno
open fun additionalCheck(declaration: JetNamedFunction, descriptor: FunctionDescriptor, diagnosticHolder: DiagnosticSink) {}
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
val annotationDescriptor = descriptor.getAnnotations().findAnnotation(requiredAnnotation.fqName)
if (annotationDescriptor == null) return
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
val annotationDescriptor = descriptor.getAnnotations().findAnnotation(requiredAnnotation.fqName) ?: return
if (declaration !is JetNamedFunction || descriptor !is FunctionDescriptor) {
diagnosticHolder.report(ErrorsJs.NATIVE_ANNOTATIONS_ALLOWED_ONLY_ON_MEMBER_OR_EXTENSION_FUN.on(declaration, annotationDescriptor.getType()))
@@ -26,12 +26,17 @@ import org.jetbrains.kotlin.diagnostics.rendering.renderKindWithName
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorUtils
class ClassDeclarationChecker : DeclarationChecker {
override fun check(declaration: JetDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (declaration !is JetClassOrObject || declaration is JetObjectDeclaration || declaration is JetEnumEntry) return
// hack to avoid to get diagnostics when compile kotlin builtins