UNNECESSARY_LATEINIT warning introduced #KT-13295 Fixed
(cherry picked from commit 88f9938)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
b0ed6adce3
commit
4da9a101cf
@@ -407,6 +407,7 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> UNNECESSARY_LATEINIT = DiagnosticFactory0.create(WARNING, LATEINIT_MODIFIER);
|
||||
|
||||
DiagnosticFactory0<KtExpression> EXTENSION_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtExpression> PROPERTY_INITIALIZER_NO_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
|
||||
@@ -827,7 +828,7 @@ public interface Errors {
|
||||
INVISIBLE_MEMBER, NON_PUBLIC_CALL_FROM_PUBLIC_INLINE, INVISIBLE_REFERENCE, INVISIBLE_SETTER);
|
||||
ImmutableSet<? extends DiagnosticFactory<?>> UNUSED_ELEMENT_DIAGNOSTICS = ImmutableSet.of(
|
||||
UNUSED_VARIABLE, UNUSED_PARAMETER, ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE, VARIABLE_WITH_REDUNDANT_INITIALIZER,
|
||||
UNUSED_LAMBDA_EXPRESSION, USELESS_CAST, UNUSED_VALUE, USELESS_ELVIS);
|
||||
UNUSED_LAMBDA_EXPRESSION, USELESS_CAST, UNUSED_VALUE, USELESS_ELVIS, UNNECESSARY_LATEINIT);
|
||||
ImmutableSet<? extends DiagnosticFactory<?>> TYPE_INFERENCE_ERRORS = ImmutableSet.of(
|
||||
TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS,
|
||||
TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR,
|
||||
|
||||
@@ -201,6 +201,8 @@ object PositioningStrategies {
|
||||
|
||||
@JvmField val PRIVATE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.PRIVATE_KEYWORD)
|
||||
|
||||
@JvmField val LATEINIT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.LATEINIT_KEYWORD)
|
||||
|
||||
@JvmField val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
|
||||
|
||||
@JvmField val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
|
||||
+1
@@ -229,6 +229,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(BACKING_FIELD_IN_INTERFACE, "Property in an interface cannot have a backing field");
|
||||
MAP.put(MUST_BE_INITIALIZED, "Property must be initialized");
|
||||
MAP.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract");
|
||||
MAP.put(UNNECESSARY_LATEINIT, "Lateinit is unnecessary: definitely initialized in constructors");
|
||||
MAP.put(PROPERTY_INITIALIZER_IN_INTERFACE, "Property initializers are not allowed in interfaces");
|
||||
MAP.put(PRIVATE_PROPERTY_IN_INTERFACE, "Abstract property in an interface cannot be private");
|
||||
MAP.put(EXTENSION_PROPERTY_WITH_BACKING_FIELD, "Extension property cannot be initialized because it has no backing field");
|
||||
|
||||
@@ -657,8 +657,8 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit &&
|
||||
trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false) {
|
||||
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
|
||||
if (backingFieldRequired && !inTrait && !propertyDescriptor.isLateInit && isUninitialized) {
|
||||
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
|
||||
trace.report(MUST_BE_INITIALIZED.on(property))
|
||||
}
|
||||
@@ -669,6 +669,9 @@ class DeclarationsChecker(
|
||||
else if (property.typeReference == null) {
|
||||
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
|
||||
}
|
||||
if (backingFieldRequired && !inTrait && propertyDescriptor.isLateInit && !isUninitialized) {
|
||||
trace.report(UNNECESSARY_LATEINIT.on(property))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
constructor(baz: Int) {
|
||||
bar = ""
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo(/*0*/ baz: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var x: String
|
||||
|
||||
constructor() {
|
||||
x = "Foo"
|
||||
}
|
||||
|
||||
constructor(x: String, y: String): <!NONE_APPLICABLE!>this<!>(y.hashCode())
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ x: kotlin.String, /*1*/ y: kotlin.String)
|
||||
public final lateinit var x: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
init {
|
||||
bar = ""
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
constructor() {
|
||||
bar = ""
|
||||
}
|
||||
|
||||
constructor(baz: Int) {
|
||||
bar = ""
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ baz: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
constructor() {
|
||||
bar = ""
|
||||
}
|
||||
|
||||
constructor(a: Int) : this() {
|
||||
}
|
||||
|
||||
constructor(a: Int, b: Int) : this(a) {
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ a: kotlin.Int)
|
||||
public constructor Foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
// Erroneous case: after lateinit removal, we'll have error at 'bar += baz', not here
|
||||
// However, looks like we must have error at 'bar += baz' even with lateinit
|
||||
// because nobody can initialize this 'bar' before constructor is called
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
constructor(baz: Int) {
|
||||
bar += baz
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo(/*0*/ baz: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo() {
|
||||
lateinit var bar: String
|
||||
|
||||
constructor(baz: Int) : this() {
|
||||
bar = ""
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ baz: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
lateinit var bar: String
|
||||
|
||||
fun init() {
|
||||
bar = ""
|
||||
}
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun init(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
lateinit var x: String
|
||||
|
||||
constructor(y: String) {
|
||||
x = y
|
||||
}
|
||||
|
||||
constructor()
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ y: kotlin.String)
|
||||
public final lateinit var x: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
constructor() {
|
||||
bar = ""
|
||||
}
|
||||
|
||||
constructor(a: Int) : <!CYCLIC_CONSTRUCTOR_DELEGATION_CALL!>this<!>(a) {
|
||||
bar = "a"
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ a: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class Foo {
|
||||
<!UNNECESSARY_LATEINIT!>lateinit<!> var bar: String
|
||||
|
||||
constructor() {
|
||||
bar = ""
|
||||
}
|
||||
|
||||
constructor(a: Int) : <!CYCLIC_CONSTRUCTOR_DELEGATION_CALL!>this<!>(a, 0, 0) {
|
||||
}
|
||||
|
||||
constructor(a: Int, b: Int) : <!CYCLIC_CONSTRUCTOR_DELEGATION_CALL!>this<!>(a) {
|
||||
}
|
||||
|
||||
constructor(a: Int, b: Int, c: Int) : <!CYCLIC_CONSTRUCTOR_DELEGATION_CALL!>this<!>(a, b) {
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
public final class Foo {
|
||||
public constructor Foo()
|
||||
public constructor Foo(/*0*/ a: kotlin.Int)
|
||||
public constructor Foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int)
|
||||
public constructor Foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int, /*2*/ c: kotlin.Int)
|
||||
public final lateinit var bar: kotlin.String
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -3881,6 +3881,81 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class UnnecessaryLateinit extends AbstractDiagnosticsTest {
|
||||
public void testAllFilesPresentInUnnecessaryLateinit() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithConstructor.kt")
|
||||
public void testLateinitWithConstructor() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithErroneousDelegation.kt")
|
||||
public void testLateinitWithErroneousDelegation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithErroneousDelegation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithInit.kt")
|
||||
public void testLateinitWithInit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithMultipleConstructors.kt")
|
||||
public void testLateinitWithMultipleConstructors() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithMultipleConstructorsAndDelegation.kt")
|
||||
public void testLateinitWithMultipleConstructorsAndDelegation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithPlusAssign.kt")
|
||||
public void testLateinitWithPlusAssign() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitWithPrimaryConstructorAndConstructor.kt")
|
||||
public void testLateinitWithPrimaryConstructorAndConstructor() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPrimaryConstructorAndConstructor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("normalLateinit.kt")
|
||||
public void testNormalLateinit() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/normalLateinit.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("normalLateinitWithTwoConstructors.kt")
|
||||
public void testNormalLateinitWithTwoConstructors() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/normalLateinitWithTwoConstructors.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("secondaryConstructorDelegateItself.kt")
|
||||
public void testSecondaryConstructorDelegateItself() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("secondaryConstructorDelegateLoop.kt")
|
||||
public void testSecondaryConstructorDelegateLoop() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateLoop.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures")
|
||||
|
||||
Reference in New Issue
Block a user