publicField -> JvmField

Effectively drop publicField and introduce JvmField (which has the same effect for now)
Implement frontend checks for @JvmField
Replace publicField -> JvmField in test data
This commit is contained in:
Pavel V. Talanov
2015-10-07 20:19:05 +03:00
committed by Michael Bogdanov
parent bfaf806f47
commit 6cf9bfdb70
25 changed files with 342 additions and 109 deletions
@@ -17,8 +17,13 @@
package org.jetbrains.kotlin.resolve.jvm.annotations
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
public fun DeclarationDescriptor.hasJvmOverloadsAnnotation(): Boolean {
return getAnnotations().findAnnotation(FqName("kotlin.jvm.JvmOverloads")) != null
}
public fun DeclarationDescriptor.findJvmFieldAnnotation(): AnnotationDescriptor? {
return annotations.findAnnotation(FqName("kotlin.jvm.JvmField"))
}
@@ -0,0 +1,92 @@
/*
* 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.jvm.checkers
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
import org.jetbrains.kotlin.resolve.jvm.checkers.JvmFieldApplicabilityChecker.Problem.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class JvmFieldApplicabilityChecker : DeclarationChecker {
enum class Problem(val errorMessage: String) {
NOT_A_PROPERTY("JvmField can only be applied to a property"),
NOT_FINAL("JvmField can only be applied to final property"),
CUSTOM_ACCESSOR("JvmField cannot be applied to a property with a custom accessor"),
NO_BACKING_FIELD("JvmField can only be applied to a property with backing field"),
OVERRIDES("JvmField cannot be applied to a property that overrides some other property"),
LATEINIT("JvmField cannot be applied to lateinit property"),
CONST("JvmField cannot be applied to const property"),
INSIDE_COMPANION_OF_INTERFACE("JvmField cannot be applied to a property defined in companion object of interface"),
TOP_LEVEL_PROPERTY_OF_MULTIFILE_FACADE("JvmField cannot be applied to top level property of a file annotated with ${JvmFileClassUtil.JVM_MULTIFILE_CLASS_SHORT}")
}
override fun check(
declaration: JetDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
val annotation = descriptor.findJvmFieldAnnotation() ?: return
val problem = when {
descriptor !is PropertyDescriptor -> NOT_A_PROPERTY
descriptor.modality.isOverridable -> NOT_FINAL
!descriptor.hasBackingField(bindingContext) -> NO_BACKING_FIELD
descriptor.hasCustomAccessor() -> CUSTOM_ACCESSOR
descriptor.overriddenDescriptors.isNotEmpty() -> OVERRIDES
descriptor.isLateInit -> LATEINIT
descriptor.isConst -> CONST
descriptor.isInsideCompanionObjectOfInterface() -> INSIDE_COMPANION_OF_INTERFACE
DescriptorUtils.isTopLevelDeclaration(descriptor) && declaration.isInsideJvmMultifileClassFile() ->
TOP_LEVEL_PROPERTY_OF_MULTIFILE_FACADE
else -> return
}
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_FIELD.on(annotationEntry, problem.errorMessage))
}
private fun JetDeclaration.isInsideJvmMultifileClassFile() = JvmFileClassUtil.findAnnotationEntryOnFileNoResolve(
getContainingJetFile(),
JvmFileClassUtil.JVM_MULTIFILE_CLASS_SHORT
) != null
private fun PropertyDescriptor.hasCustomAccessor()
= !(getter?.isDefault ?: true) || !(setter?.isDefault ?: true)
private fun PropertyDescriptor.hasBackingField(bindingContext: BindingContext)
= bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, this) ?: false
private fun PropertyDescriptor.isInsideCompanionObjectOfInterface(): Boolean {
val containingClass = containingDeclaration as? ClassDescriptor ?: return false
if (!DescriptorUtils.isCompanionObject(containingClass)) return false
val outerClassForObject = containingClass.containingDeclaration as? ClassDescriptor ?: return false
return DescriptorUtils.isInterface(outerClassForObject)
}
}
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeclarationChecker
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
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
@@ -159,27 +158,6 @@ 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 = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry))
}
if (descriptor is PropertyDescriptor
&& !bindingContext.get<PropertyDescriptor, Boolean>(BindingContext.BACKING_FIELD_REQUIRED, descriptor)!!) {
report()
}
}
}
public class TypeParameterBoundIsNotArrayChecker : DeclarationChecker {
override fun check(
declaration: JetDeclaration,
@@ -74,8 +74,6 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
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");
MAP.put(ErrorsJvm.JAVA_CLASS_ON_COMPANION,
"The resulting type of this ''javaClass'' call is {0} and not {1}. " +
"Please use the more clear ''::class.java'' syntax to avoid confusion",
@@ -88,6 +86,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(ErrorsJvm.DUPLICATE_CLASS_NAMES, "Duplicate JVM class name ''{0}'' generated from: {1}", Renderers.TO_STRING, Renderers.TO_STRING);
MAP.put(ErrorsJvm.UPPER_BOUND_CANNOT_BE_ARRAY, "Upper bound of a type parameter cannot be an array");
MAP.put(ErrorsJvm.INAPPLICABLE_JVM_FIELD, "{0}", Renderers.TO_STRING);
}
@NotNull
@@ -48,6 +48,8 @@ public interface ErrorsJvm {
DiagnosticFactory0<PsiElement> INAPPLICABLE_JVM_NAME = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetAnnotationEntry> ILLEGAL_JVM_NAME = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<JetAnnotationEntry, String> INAPPLICABLE_JVM_FIELD = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<JetDeclaration> OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory0<JetDeclaration> OVERLOADS_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<JetDeclaration> OVERLOADS_PRIVATE = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
@@ -65,8 +67,6 @@ public interface ErrorsJvm {
DiagnosticFactory0<JetElement> INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetElement> INAPPLICABLE_PUBLIC_FIELD = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetElement> NO_REFLECTION_IN_CLASS_PATH = DiagnosticFactory0.create(WARNING);
DiagnosticFactory2<JetElement, JetType, JetType> JAVA_CLASS_ON_COMPANION = DiagnosticFactory2.create(WARNING);
@@ -35,7 +35,7 @@ public object JvmPlatformConfigurator : PlatformConfigurator(
ReifiedTypeParameterAnnotationChecker(),
NativeFunChecker(),
OverloadsAnnotationChecker(),
PublicFieldAnnotationChecker(),
JvmFieldApplicabilityChecker(),
TypeParameterBoundIsNotArrayChecker()
),