Extend incremental analysis to object declaration

Fixed #KT-37250
This commit is contained in:
Vladimir Dolzhenko
2020-03-04 17:35:45 +01:00
parent ae208f58a4
commit ddba8e7691
10 changed files with 142 additions and 15 deletions
@@ -223,6 +223,7 @@ class KotlinCodeBlockModificationListener(
val blockDeclaration =
KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) as? KtDeclaration ?: return null
// KtPsiUtil.getTopmostParentOfType<KtClassOrObject>(element) as? KtDeclaration ?: return null
// should not be local declaration
if (KtPsiUtil.isLocal(blockDeclaration))
@@ -230,6 +231,11 @@ class KotlinCodeBlockModificationListener(
when (blockDeclaration) {
is KtNamedFunction -> {
// if (blockDeclaration.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) {
// topClassLikeDeclaration(blockDeclaration)?.let {
// return BlockModificationScopeElement(it, it)
// }
// }
if (blockDeclaration.hasBlockBody()) {
// case like `fun foo(): String {...<caret>...}`
return blockDeclaration.bodyExpression
@@ -244,18 +250,23 @@ class KotlinCodeBlockModificationListener(
}
is KtProperty -> {
// if (blockDeclaration.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) {
// topClassLikeDeclaration(blockDeclaration)?.let {
// return BlockModificationScopeElement(it, it)
// }
// }
if (blockDeclaration.typeReference != null) {
val accessors =
blockDeclaration.accessors.map { it.initializer ?: it.bodyExpression } + blockDeclaration.initializer
for (accessor in accessors) {
accessor?.takeIf {
it.isAncestor(element) &&
// adding annotations to accessor is the same as change contract of property
(element !is KtAnnotated || element.annotationEntries.isEmpty())
}
it.isAncestor(element) &&
// adding annotations to accessor is the same as change contract of property
(element !is KtAnnotated || element.annotationEntries.isEmpty())
}
?.let { expression ->
val declaration =
KtPsiUtil.getTopmostParentOfTypes(blockDeclaration, KtClass::class.java) as? KtElement ?:
KtPsiUtil.getTopmostParentOfTypes(blockDeclaration, KtClassOrObject::class.java) as? KtElement ?:
// ktFile to check top level property declarations
return null
return BlockModificationScopeElement(declaration, expression)
@@ -277,7 +288,7 @@ class KotlinCodeBlockModificationListener(
blockDeclaration
.takeIf { it.isAncestor(element) }
?.let { ktClassInitializer ->
(PsiTreeUtil.getParentOfType(blockDeclaration, KtClass::class.java) as? KtElement)?.let {
(PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java))?.let {
return BlockModificationScopeElement(it, ktClassInitializer)
}
}
@@ -287,20 +298,18 @@ class KotlinCodeBlockModificationListener(
blockDeclaration
?.takeIf {
it.bodyExpression?.isAncestor(element) ?: false || it.getDelegationCallOrNull()?.isAncestor(element) ?: false
}
?.let { ktConstructor ->
(PsiTreeUtil.getParentOfType(blockDeclaration, KtClass::class.java) as? KtElement)?.let {
}?.let { ktConstructor ->
PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java)?.let {
return BlockModificationScopeElement(it, ktConstructor)
}
}
}
// TODO: still under consideration - is it worth to track changes of private properties / methods
// problem could be in diagnostics - it is worth to manage it with modTracker
// is KtClass -> {
// is KtClassOrObject -> {
// return when (element) {
// is KtProperty -> if (element.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) blockDeclaration else null
// is KtNamedFunction -> if (element.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) blockDeclaration else null
// is KtProperty, is KtNamedFunction -> {
// if ((element as? KtModifierListOwner)?.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE)
// BlockModificationScopeElement(blockDeclaration, blockDeclaration) else null
// }
// else -> null
// }
// }
@@ -0,0 +1,10 @@
// OUT_OF_CODE_BLOCK: TRUE
// TYPE: 'Int'
// TODO: changes in private functions is still subject to OOCB
class A {
fun foo(): Int = 12
private fun bar(): <caret> = foo()
}
// SKIP_ANALYZE_CHECK
@@ -0,0 +1,12 @@
// OUT_OF_CODE_BLOCK: TRUE
// as it's a class body not a named function body
class A {
fun foo(): Int = 12
private fun bar(): Int = foo() + <caret>
}
// TYPE: 1
// SKIP_ANALYZE_CHECK
@@ -0,0 +1,9 @@
// OUT_OF_CODE_BLOCK: TRUE
// TYPE: 'Int'
// TODO: changes in private properties is still subject to OOCB
class Test {
val more : Int = 0
private val test : <caret> = 0
}
// SKIP_ANALYZE_CHECK
+8
View File
@@ -0,0 +1,8 @@
// OUT_OF_CODE_BLOCK: FALSE
// ERROR: Unresolved reference: call
object Foo {
fun foo() {
c<caret>ll()
}
}
@@ -0,0 +1,10 @@
// OUT_OF_CODE_BLOCK: TRUE
// TYPE: 'Int'
// TODO: changes in private functions is still subject to OOCB
object A {
fun foo(): Int = 12
private fun bar(): <caret> = foo()
}
// SKIP_ANALYZE_CHECK
@@ -0,0 +1,12 @@
// OUT_OF_CODE_BLOCK: TRUE
// as it's a object body not a named function body
object A {
fun foo(): Int = 12
private fun bar(): Int = foo() + <caret>
}
// TYPE: 1
// SKIP_ANALYZE_CHECK
@@ -0,0 +1,9 @@
// OUT_OF_CODE_BLOCK: TRUE
// TYPE: 'Int'
// TODO: changes in private properties is still subject to OOCB
object Test {
val more : Int = 0
private val test : <caret> = 0
}
// SKIP_ANALYZE_CHECK
@@ -0,0 +1,8 @@
// OUT_OF_CODE_BLOCK: FALSE
// ERROR: Unresolved reference: call
object Foo {
init {
c<caret>ll()
}
}
@@ -93,6 +93,21 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
runTest("idea/testData/codeInsight/outOfBlock/InClassInUninitializedPropertyAccessor.kt");
}
@TestMetadata("InClassPrivateFunctionReturnType.kt")
public void testInClassPrivateFunctionReturnType() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionReturnType.kt");
}
@TestMetadata("InClassPrivateFunctionWithoutInference.kt")
public void testInClassPrivateFunctionWithoutInference() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionWithoutInference.kt");
}
@TestMetadata("InClassPrivatePropertyType.kt")
public void testInClassPrivatePropertyType() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InClassPrivatePropertyType.kt");
}
@TestMetadata("InClassPropertyAccessor.kt")
public void testInClassPropertyAccessor() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InClassPropertyAccessor.kt");
@@ -138,6 +153,11 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
runTest("idea/testData/codeInsight/outOfBlock/InFunInMultiDeclaration.kt");
}
@TestMetadata("InFunInObject.kt")
public void testInFunInObject() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InFunInObject.kt");
}
@TestMetadata("InFunInProperty.kt")
public void testInFunInProperty() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InFunInProperty.kt");
@@ -198,6 +218,21 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
runTest("idea/testData/codeInsight/outOfBlock/InNestedClassFunNoTypeBlockExpression.kt");
}
@TestMetadata("InObjectPrivateFunctionReturnType.kt")
public void testInObjectPrivateFunctionReturnType() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionReturnType.kt");
}
@TestMetadata("InObjectPrivateFunctionWithoutInference.kt")
public void testInObjectPrivateFunctionWithoutInference() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionWithoutInference.kt");
}
@TestMetadata("InObjectPrivatePropertyType.kt")
public void testInObjectPrivatePropertyType() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InObjectPrivatePropertyType.kt");
}
@TestMetadata("InPrimaryConstructor.kt")
public void testInPrimaryConstructor() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InPrimaryConstructor.kt");
@@ -293,6 +328,11 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
runTest("idea/testData/codeInsight/outOfBlock/InitBlockInLocalClass.kt");
}
@TestMetadata("InitBlockInObject.kt")
public void testInitBlockInObject() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/InitBlockInObject.kt");
}
@TestMetadata("LocalFunWithBody.kt")
public void testLocalFunWithBody() throws Exception {
runTest("idea/testData/codeInsight/outOfBlock/LocalFunWithBody.kt");