Correct handling of local class / anonymous object cases for KT-10445 / KT-10042
This commit is contained in:
@@ -391,20 +391,48 @@ public class ControlFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should return KtDeclarationWithBody or KtClassOrObject
|
||||||
|
@Nullable
|
||||||
|
private static KtDeclaration getElementParentDeclaration(@NotNull KtElement element) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return PsiTreeUtil.getParentOfType(element, KtDeclarationWithBody.class, KtClassOrObject.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private DeclarationDescriptor getDeclarationDescriptor(@Nullable KtDeclaration declaration) {
|
||||||
|
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
|
||||||
|
if (descriptor instanceof ClassDescriptor) {
|
||||||
|
// For a class primary constructor, we cannot directly get ConstructorDescriptor by KtClassInitializer,
|
||||||
|
// so we have to do additional conversion: KtClassInitializer -> KtClassOrObject -> ClassDescriptor -> ConstructorDescriptor
|
||||||
|
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
|
||||||
|
return classDescriptor.getUnsubstitutedPrimaryConstructor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isCapturedWrite(
|
private boolean isCapturedWrite(
|
||||||
@NotNull VariableDescriptor variableDescriptor,
|
@NotNull VariableDescriptor variableDescriptor,
|
||||||
@NotNull WriteValueInstruction writeValueInstruction
|
@NotNull WriteValueInstruction writeValueInstruction
|
||||||
) {
|
) {
|
||||||
DeclarationDescriptor containingDeclarationDescriptor = variableDescriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDeclarationDescriptor = variableDescriptor.getContainingDeclaration();
|
||||||
if (containingDeclarationDescriptor instanceof ClassDescriptor) return false;
|
// Do not consider member / top-level properties
|
||||||
KtElement ownerElement = writeValueInstruction.getOwner().getCorrespondingElement();
|
if (containingDeclarationDescriptor instanceof ClassOrPackageFragmentDescriptor) return false;
|
||||||
DeclarationDescriptor writeOwnerDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ownerElement);
|
KtDeclaration parentDeclaration = getElementParentDeclaration(writeValueInstruction.getElement());
|
||||||
if (containingDeclarationDescriptor.equals(writeOwnerDescriptor)) return false;
|
while (true) {
|
||||||
if (writeOwnerDescriptor instanceof ClassDescriptor) {
|
DeclarationDescriptor parentDescriptor = getDeclarationDescriptor(parentDeclaration);
|
||||||
ClassDescriptor writeOwnerClass = (ClassDescriptor) writeOwnerDescriptor;
|
if (containingDeclarationDescriptor.equals(parentDescriptor)) {
|
||||||
if (containingDeclarationDescriptor.equals(writeOwnerClass.getUnsubstitutedPrimaryConstructor())) return false;
|
return false;
|
||||||
|
}
|
||||||
|
else if (parentDeclaration instanceof KtObjectDeclaration) {
|
||||||
|
// anonymous object counts here the same as its owner
|
||||||
|
parentDeclaration = getElementParentDeclaration(parentDeclaration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkValReassignment(
|
private boolean checkValReassignment(
|
||||||
|
|||||||
+69
@@ -1,3 +1,5 @@
|
|||||||
|
// !DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
var x: String
|
var x: String
|
||||||
class A {
|
class A {
|
||||||
@@ -19,3 +21,70 @@ fun bar() {
|
|||||||
// Ok
|
// Ok
|
||||||
x.length
|
x.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun gav() {
|
||||||
|
val x: String
|
||||||
|
class B {
|
||||||
|
init {
|
||||||
|
// Error! See KT-10445
|
||||||
|
<!CAPTURED_VAL_INITIALIZATION!>x<!> = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Error! See KT-10042
|
||||||
|
<!UNINITIALIZED_VARIABLE!>x<!>.length
|
||||||
|
val y: String
|
||||||
|
class C(val s: String) {
|
||||||
|
constructor(): this("") {
|
||||||
|
// Error!
|
||||||
|
<!VAL_REASSIGNMENT!>y<!> = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<!UNINITIALIZED_VARIABLE!>y<!>.length
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Gau(val s: String)
|
||||||
|
|
||||||
|
fun gau() {
|
||||||
|
val x: String
|
||||||
|
object: Any() {
|
||||||
|
init {
|
||||||
|
// Ok
|
||||||
|
x = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ok
|
||||||
|
x.length
|
||||||
|
val y: String
|
||||||
|
fun local() {
|
||||||
|
object: Any() {
|
||||||
|
init {
|
||||||
|
// Error!
|
||||||
|
<!CAPTURED_VAL_INITIALIZATION!>y<!> = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val z: String
|
||||||
|
object: Gau(if (true) {
|
||||||
|
z = ""
|
||||||
|
z
|
||||||
|
}
|
||||||
|
else "") {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class My {
|
||||||
|
init {
|
||||||
|
val x: String
|
||||||
|
class Your {
|
||||||
|
init {
|
||||||
|
// Error! See KT-10445
|
||||||
|
<!CAPTURED_VAL_INITIALIZATION!>x<!> = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<!MUST_BE_INITIALIZED!>val top: Int<!>
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
<!VAL_REASSIGNMENT!>top<!> = 1
|
||||||
|
}
|
||||||
|
|||||||
+19
@@ -1,4 +1,23 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
|
public val top: kotlin.Int
|
||||||
public fun bar(): kotlin.Unit
|
public fun bar(): kotlin.Unit
|
||||||
public fun foo(): kotlin.Unit
|
public fun foo(): kotlin.Unit
|
||||||
|
public fun gau(): kotlin.Unit
|
||||||
|
public fun gav(): kotlin.Unit
|
||||||
|
public fun init(): kotlin.Unit
|
||||||
|
|
||||||
|
public open class Gau {
|
||||||
|
public constructor Gau(/*0*/ s: kotlin.String)
|
||||||
|
public final val s: 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
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class My {
|
||||||
|
public constructor My()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user