Make changes in super call lambda not cause out-of-block modification (KT-13474)
#KT-13474 Fixed
This commit is contained in:
@@ -104,6 +104,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
|||||||
- [`KT-13589`](https://youtrack.jetbrains.com/issue/KT-13589) Use TODO() consistently in implementation stubs
|
- [`KT-13589`](https://youtrack.jetbrains.com/issue/KT-13589) Use TODO() consistently in implementation stubs
|
||||||
- [`KT-13630`](https://youtrack.jetbrains.com/issue/KT-13630) Do not show Change Signature dialog when applying "Remove parameter" quick-fix
|
- [`KT-13630`](https://youtrack.jetbrains.com/issue/KT-13630) Do not show Change Signature dialog when applying "Remove parameter" quick-fix
|
||||||
- Re-highlight only single function after local modifications
|
- Re-highlight only single function after local modifications
|
||||||
|
- [`KT-13474`](https://youtrack.jetbrains.com/issue/KT-13474) Fix performance of typing super call lambda
|
||||||
|
|
||||||
#### Intention actions, inspections and quickfixes
|
#### Intention actions, inspections and quickfixes
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ fun KtElement.getModificationStamp(): Long {
|
|||||||
return when (this) {
|
return when (this) {
|
||||||
is KtFile -> this.modificationStamp
|
is KtFile -> this.modificationStamp
|
||||||
is KtDeclarationStub<*> -> this.modificationStamp
|
is KtDeclarationStub<*> -> this.modificationStamp
|
||||||
|
is KtSuperTypeList -> this.modificationStamp
|
||||||
else -> (parent as KtElement).getModificationStamp()
|
else -> (parent as KtElement).getModificationStamp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,11 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public class KtSuperTypeList extends KtElementImplStub<KotlinPlaceHolderStub<KtSuperTypeList>> {
|
public class KtSuperTypeList extends KtElementImplStub<KotlinPlaceHolderStub<KtSuperTypeList>> {
|
||||||
|
private final AtomicLong modificationStamp = new AtomicLong();
|
||||||
|
|
||||||
public KtSuperTypeList(@NotNull ASTNode node) {
|
public KtSuperTypeList(@NotNull ASTNode node) {
|
||||||
super(node);
|
super(node);
|
||||||
}
|
}
|
||||||
@@ -66,4 +69,15 @@ public class KtSuperTypeList extends KtElementImplStub<KotlinPlaceHolderStub<KtS
|
|||||||
public List<KtSuperTypeListEntry> getEntries() {
|
public List<KtSuperTypeListEntry> getEntries() {
|
||||||
return Arrays.asList(getStubOrPsiChildren(KtStubElementTypes.SUPER_TYPE_LIST_ENTRIES, KtSuperTypeListEntry.ARRAY_FACTORY));
|
return Arrays.asList(getStubOrPsiChildren(KtStubElementTypes.SUPER_TYPE_LIST_ENTRIES, KtSuperTypeListEntry.ARRAY_FACTORY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void subtreeChanged() {
|
||||||
|
super.subtreeChanged();
|
||||||
|
modificationStamp.getAndIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getModificationStamp() {
|
||||||
|
return modificationStamp.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -68,7 +68,13 @@ class KotlinCodeBlockModificationListener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isInsideCodeBlock(element: PsiElement): Boolean {
|
private fun isInsideCodeBlock(element: PsiElement): Boolean {
|
||||||
//TODO: other types
|
val lambda = KtPsiUtil.getTopmostParentOfTypes(element, KtLambdaExpression::class.java)
|
||||||
|
if (lambda is KtLambdaExpression) {
|
||||||
|
if (KtPsiUtil.getTopmostParentOfTypes(lambda, KtSuperTypeCallEntry::class.java) != null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val blockDeclaration = KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) ?: return false
|
val blockDeclaration = KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) ?: return false
|
||||||
if (blockDeclaration.parents.any { it !is KtClassBody && it !is KtClassOrObject && it !is KtFile }) return false // should not be local declaration
|
if (blockDeclaration.parents.any { it !is KtClassBody && it !is KtClassOrObject && it !is KtFile }) return false // should not be local declaration
|
||||||
|
|
||||||
|
|||||||
@@ -60,12 +60,15 @@ class ResolveElementCache(
|
|||||||
|
|
||||||
private fun modificationStamp(resolveElement: KtElement): Long? {
|
private fun modificationStamp(resolveElement: KtElement): Long? {
|
||||||
val file = resolveElement.containingFile
|
val file = resolveElement.containingFile
|
||||||
return if (!file.isPhysical) // for non-physical file we don't get OUT_OF_CODE_BLOCK_MODIFICATION_COUNT increased and must reset data on any modification of the file
|
return when {
|
||||||
file.modificationStamp
|
// for non-physical file we don't get OUT_OF_CODE_BLOCK_MODIFICATION_COUNT increased and must reset
|
||||||
else if (resolveElement is KtDeclaration && KotlinCodeBlockModificationListener.isBlockDeclaration(resolveElement))
|
// data on any modification of the file
|
||||||
resolveElement.getModificationStamp()
|
!file.isPhysical -> file.modificationStamp
|
||||||
else
|
|
||||||
null
|
resolveElement is KtDeclaration && KotlinCodeBlockModificationListener.isBlockDeclaration(resolveElement) -> resolveElement.getModificationStamp()
|
||||||
|
resolveElement is KtSuperTypeList -> resolveElement.modificationStamp
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// FALSE
|
||||||
|
|
||||||
|
// Navigation from "class B: A()" should move to valid constructor even after changing type in lambda
|
||||||
|
|
||||||
|
open class A(l: String) {
|
||||||
|
constructor(x: Int) : this("$x")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> foo(l: () -> T) = l()
|
||||||
|
|
||||||
|
class B: A(foo { "1"<caret> })
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// FALSE
|
||||||
|
|
||||||
|
open class A(a: () -> Unit)
|
||||||
|
|
||||||
|
class B: A({ "1"<caret> })
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// TRUE
|
||||||
|
// Can't result to false as there's no body expression, so it's considered to be changes in JavaCodeBlockModificationListener.
|
||||||
|
|
||||||
|
open class A(a: () -> Unit) {
|
||||||
|
constructor(f: (String) -> Unit) : this({ -> f("") })
|
||||||
|
}
|
||||||
|
|
||||||
|
class B: A({ s<caret> -> "1" })
|
||||||
|
|
||||||
|
// SKIP_ANALYZE_CHECK
|
||||||
+18
@@ -191,6 +191,24 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InSuperTypeCallCallInLambdaInCall.kt")
|
||||||
|
public void testInSuperTypeCallCallInLambdaInCall() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InSuperTypeCallCallInLambdaInCall.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InSuperTypeCallInLambaInBody.kt")
|
||||||
|
public void testInSuperTypeCallInLambaInBody() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InSuperTypeCallInLambaInBody.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InSuperTypeCallInLambdaParameters.kt")
|
||||||
|
public void testInSuperTypeCallInLambdaParameters() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InSuperTypeCallInLambdaParameters.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InitBlock.kt")
|
@TestMetadata("InitBlock.kt")
|
||||||
public void testInitBlock() throws Exception {
|
public void testInitBlock() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InitBlock.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InitBlock.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user