Check lateinit applicability for local variables
TODO probably should be refactored together with DeclarationsChecker
This commit is contained in:
@@ -576,27 +576,19 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPropertyLateInit(property: KtCallableDeclaration, propertyDescriptor: PropertyDescriptor) {
|
private fun checkPropertyLateInit(property: KtCallableDeclaration, propertyDescriptor: PropertyDescriptor) {
|
||||||
val modifierList = property.modifierList ?: return
|
val modifier = property.modifierList?.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return
|
||||||
val modifier = modifierList.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return
|
|
||||||
|
|
||||||
if (!propertyDescriptor.isVar) {
|
if (!propertyDescriptor.isVar) {
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable properties"))
|
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable properties"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnTypeIsNullable = true
|
val returnType = propertyDescriptor.type
|
||||||
var returnTypeIsPrimitive = true
|
|
||||||
|
|
||||||
val returnType = propertyDescriptor.returnType
|
if (TypeUtils.isNullableType(returnType)) {
|
||||||
if (returnType != null) {
|
|
||||||
returnTypeIsNullable = TypeUtils.isNullableType(returnType)
|
|
||||||
returnTypeIsPrimitive = KotlinBuiltIns.isPrimitiveType(returnType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnTypeIsNullable) {
|
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on nullable properties"))
|
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on nullable properties"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnTypeIsPrimitive) {
|
if (KotlinBuiltIns.isPrimitiveType(returnType)) {
|
||||||
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primitive type properties"))
|
trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primitive type properties"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
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.*
|
||||||
@@ -24,9 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.*
|
|||||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
|
||||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
@@ -35,6 +34,7 @@ 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
|
||||||
|
|
||||||
@@ -120,13 +120,42 @@ class LocalVariableResolver(
|
|||||||
typeInfo = noTypeInfo(context)
|
typeInfo = noTypeInfo(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor)
|
checkLocalVariableDeclaration(context, propertyDescriptor, property)
|
||||||
|
|
||||||
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor)
|
|
||||||
identifierChecker.checkDeclaration(property, context.trace)
|
|
||||||
return Pair(typeInfo.replaceType(dataFlowAnalyzer.checkStatementType(property, context)), propertyDescriptor)
|
return Pair(typeInfo.replaceType(dataFlowAnalyzer.checkStatementType(property, context)), propertyDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkLocalVariableDeclaration(context: ExpressionTypingContext, descriptor: VariableDescriptor, ktProperty: KtProperty) {
|
||||||
|
ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, descriptor)
|
||||||
|
|
||||||
|
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(ktProperty, descriptor)
|
||||||
|
identifierChecker.checkDeclaration(ktProperty, context.trace)
|
||||||
|
|
||||||
|
checkLocalVariableLateinit(context.trace, descriptor, ktProperty)
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
variable: KtVariableDeclaration,
|
variable: KtVariableDeclaration,
|
||||||
|
|||||||
Vendored
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VALUE -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
object Delegate {
|
||||||
|
operator fun getValue(instance: Any?, property: KProperty<*>) : String = ""
|
||||||
|
operator fun setValue(instance: Any?, property: KProperty<*>, value: String) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> val test0: Any
|
||||||
|
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> var test1: Int
|
||||||
|
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> var test2: Any?
|
||||||
|
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> var test3: String = ""
|
||||||
|
<!INAPPLICABLE_LATEINIT_MODIFIER!>lateinit<!> var test4 by Delegate
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test(): kotlin.Unit
|
||||||
|
|
||||||
|
public object Delegate {
|
||||||
|
private constructor Delegate()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final operator fun getValue(/*0*/ instance: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final operator fun setValue(/*0*/ instance: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>, /*2*/ value: kotlin.String): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -16263,6 +16263,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/properties/localLateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/properties/localLateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inapplicableLateinitModifier.kt")
|
||||||
|
public void testInapplicableLateinitModifier() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localLateinit.kt")
|
@TestMetadata("localLateinit.kt")
|
||||||
public void testLocalLateinit() throws Exception {
|
public void testLocalLateinit() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/localLateinit.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/localLateinit.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user