Unify code for lateinit properties and local variables checking
This commit is contained in:
@@ -441,7 +441,7 @@ class DeclarationsChecker(
|
|||||||
for (parameter in declaration.valueParameters) {
|
for (parameter in declaration.valueParameters) {
|
||||||
trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let {
|
trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let {
|
||||||
modifiersChecker.checkModifiersForDeclaration(parameter, it)
|
modifiersChecker.checkModifiersForDeclaration(parameter, it)
|
||||||
checkPropertyLateInit(parameter, it)
|
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, parameter, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +539,7 @@ class DeclarationsChecker(
|
|||||||
if (containingDeclaration is ClassDescriptor) {
|
if (containingDeclaration is ClassDescriptor) {
|
||||||
checkMemberProperty(property, propertyDescriptor, containingDeclaration)
|
checkMemberProperty(property, propertyDescriptor, containingDeclaration)
|
||||||
}
|
}
|
||||||
checkPropertyLateInit(property, propertyDescriptor)
|
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, property, propertyDescriptor)
|
||||||
checkPropertyInitializer(property, propertyDescriptor)
|
checkPropertyInitializer(property, propertyDescriptor)
|
||||||
checkAccessors(property, propertyDescriptor)
|
checkAccessors(property, propertyDescriptor)
|
||||||
checkTypeParameterConstraints(property)
|
checkTypeParameterConstraints(property)
|
||||||
@@ -575,56 +575,6 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPropertyLateInit(property: KtCallableDeclaration, propertyDescriptor: PropertyDescriptor) {
|
|
||||||
val modifier = property.modifierList?.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return
|
|
||||||
|
|
||||||
if (!propertyDescriptor.isVar) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable properties"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val returnType = propertyDescriptor.type
|
|
||||||
|
|
||||||
if (TypeUtils.isNullableType(returnType)) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on nullable properties"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KotlinBuiltIns.isPrimitiveType(returnType)) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primitive type properties"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val isAbstract = propertyDescriptor.modality == Modality.ABSTRACT
|
|
||||||
if (isAbstract) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on abstract properties"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (property is KtParameter) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primary constructor parameters"))
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasDelegateExpressionOrInitializer = false
|
|
||||||
if (property is KtProperty && property.hasDelegateExpressionOrInitializer()) {
|
|
||||||
hasDelegateExpressionOrInitializer = true
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier,
|
|
||||||
"is not allowed on properties with initializer or on delegated properties"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasAccessorImplementation = propertyDescriptor.hasAccessorImplementation()
|
|
||||||
|
|
||||||
if (!hasDelegateExpressionOrInitializer && hasAccessorImplementation) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on properties with a custom getter or setter"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasBackingField = trace.bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false
|
|
||||||
|
|
||||||
if (!isAbstract && !hasAccessorImplementation && !hasDelegateExpressionOrInitializer && !hasBackingField) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on properties without backing field"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyDescriptor.extensionReceiverParameter != null) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on extension properties"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkMemberProperty(
|
private fun checkMemberProperty(
|
||||||
property: KtProperty,
|
property: KtProperty,
|
||||||
propertyDescriptor: PropertyDescriptor,
|
propertyDescriptor: PropertyDescriptor,
|
||||||
@@ -967,7 +917,7 @@ class DeclarationsChecker(
|
|||||||
return !modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
return !modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PropertyDescriptor.hasAccessorImplementation(): Boolean {
|
fun PropertyDescriptor.hasAccessorImplementation(): Boolean {
|
||||||
getter?.let { if (it.hasBody()) return true }
|
getter?.let { if (it.hasBody()) return true }
|
||||||
setter?.let { if (it.hasBody()) return true }
|
setter?.let { if (it.hasBody()) return true }
|
||||||
return false
|
return false
|
||||||
|
|||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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 org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
import org.jetbrains.kotlin.resolve.DeclarationsChecker.Companion.hasAccessorImplementation
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
|
object LateinitModifierApplicabilityChecker {
|
||||||
|
fun checkLateinitModifierApplicability(trace: BindingTrace, ktDeclaration: KtCallableDeclaration, descriptor: VariableDescriptor) {
|
||||||
|
val modifier = ktDeclaration.modifierList?.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return
|
||||||
|
|
||||||
|
val variables = when (descriptor) {
|
||||||
|
is PropertyDescriptor -> "properties"
|
||||||
|
is LocalVariableDescriptor -> "local variables"
|
||||||
|
else -> throw AssertionError("Should be a property or a local variable: $descriptor")
|
||||||
|
}
|
||||||
|
|
||||||
|
val type = descriptor.type
|
||||||
|
|
||||||
|
if (!descriptor.isVar) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable $variables"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeUtils.isNullableType(type)) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on $variables of nullable types"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (KotlinBuiltIns.isPrimitiveType(type)) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on $variables of primitive types"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ktDeclaration is KtProperty) {
|
||||||
|
if (ktDeclaration.hasDelegateExpression()) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on delegated properties"))
|
||||||
|
}
|
||||||
|
else if (ktDeclaration.hasInitializer()) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on $variables with initializer"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor is PropertyDescriptor) {
|
||||||
|
val isAbstract = descriptor.modality == Modality.ABSTRACT
|
||||||
|
val hasDelegateExpressionOrInitializer = ktDeclaration is KtProperty && ktDeclaration.hasDelegateExpressionOrInitializer()
|
||||||
|
val hasAccessorImplementation = descriptor.hasAccessorImplementation()
|
||||||
|
val hasBackingField = trace.bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) ?: false
|
||||||
|
|
||||||
|
if (ktDeclaration is KtParameter) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primary constructor parameters"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAbstract) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on abstract properties"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDelegateExpressionOrInitializer) {
|
||||||
|
if (hasAccessorImplementation) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on properties with a custom getter or setter"))
|
||||||
|
}
|
||||||
|
else if (!isAbstract && !hasBackingField) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on properties without backing field"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor.extensionReceiverParameter != null) {
|
||||||
|
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on extension properties"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
@@ -34,7 +33,6 @@ import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
|
||||||
import org.jetbrains.kotlin.types.expressions.*
|
import org.jetbrains.kotlin.types.expressions.*
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||||
|
|
||||||
@@ -131,29 +129,7 @@ class LocalVariableResolver(
|
|||||||
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(ktProperty, descriptor)
|
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(ktProperty, descriptor)
|
||||||
identifierChecker.checkDeclaration(ktProperty, context.trace)
|
identifierChecker.checkDeclaration(ktProperty, context.trace)
|
||||||
|
|
||||||
checkLocalVariableLateinit(context.trace, descriptor, ktProperty)
|
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(context.trace, ktProperty, descriptor)
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkLocalVariableLateinit(trace: BindingTrace, descriptor: VariableDescriptor, ktProperty: KtProperty) {
|
|
||||||
val modifierList = ktProperty.modifierList ?: return
|
|
||||||
val modifier = modifierList.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return
|
|
||||||
val returnType = descriptor.type
|
|
||||||
|
|
||||||
if (!descriptor.isVar) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable local variables"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeUtils.isNullableType(returnType)) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on local variables of nullable types"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KotlinBuiltIns.isPrimitiveType(returnType)) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on local variables of primitive types"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ktProperty.hasDelegateExpressionOrInitializer()) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on variables with initializer or on local delegated properties"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveLocalVariableDescriptor(
|
private fun resolveLocalVariableDescriptor(
|
||||||
|
|||||||
Reference in New Issue
Block a user