From ddba8e7691865461c0fdb563ac362b17dc82731e Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Wed, 4 Mar 2020 17:35:45 +0100 Subject: [PATCH] Extend incremental analysis to object declaration Fixed #KT-37250 --- .../KotlinCodeBlockModificationListener.kt | 39 +++++++++++------- .../InClassPrivateFunctionReturnType.kt | 10 +++++ .../InClassPrivateFunctionWithoutInference.kt | 12 ++++++ .../outOfBlock/InClassPrivatePropertyType.kt | 9 +++++ .../codeInsight/outOfBlock/InFunInObject.kt | 8 ++++ .../InObjectPrivateFunctionReturnType.kt | 10 +++++ ...InObjectPrivateFunctionWithoutInference.kt | 12 ++++++ .../outOfBlock/InObjectPrivatePropertyType.kt | 9 +++++ .../outOfBlock/InitBlockInObject.kt | 8 ++++ .../OutOfBlockModificationTestGenerated.java | 40 +++++++++++++++++++ 10 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionReturnType.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionWithoutInference.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InClassPrivatePropertyType.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InFunInObject.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionReturnType.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionWithoutInference.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InObjectPrivatePropertyType.kt create mode 100644 idea/testData/codeInsight/outOfBlock/InitBlockInObject.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt index 49cadb34f86..59b2a8a2a9c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt @@ -223,6 +223,7 @@ class KotlinCodeBlockModificationListener( val blockDeclaration = KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) as? KtDeclaration ?: return null +// KtPsiUtil.getTopmostParentOfType(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 {......}` 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 // } // } diff --git a/idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionReturnType.kt b/idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionReturnType.kt new file mode 100644 index 00000000000..2651c8d20d4 --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionReturnType.kt @@ -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(): = foo() +} + +// SKIP_ANALYZE_CHECK \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionWithoutInference.kt b/idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionWithoutInference.kt new file mode 100644 index 00000000000..997df05352d --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InClassPrivateFunctionWithoutInference.kt @@ -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() + +} + +// TYPE: 1 +// SKIP_ANALYZE_CHECK \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InClassPrivatePropertyType.kt b/idea/testData/codeInsight/outOfBlock/InClassPrivatePropertyType.kt new file mode 100644 index 00000000000..c9f624b3bf3 --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InClassPrivatePropertyType.kt @@ -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 : = 0 +} + +// SKIP_ANALYZE_CHECK \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InFunInObject.kt b/idea/testData/codeInsight/outOfBlock/InFunInObject.kt new file mode 100644 index 00000000000..d29ebc383a6 --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InFunInObject.kt @@ -0,0 +1,8 @@ +// OUT_OF_CODE_BLOCK: FALSE +// ERROR: Unresolved reference: call + +object Foo { + fun foo() { + cll() + } +} \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionReturnType.kt b/idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionReturnType.kt new file mode 100644 index 00000000000..d6e4a86c0cc --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionReturnType.kt @@ -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(): = foo() +} + +// SKIP_ANALYZE_CHECK \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionWithoutInference.kt b/idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionWithoutInference.kt new file mode 100644 index 00000000000..5b1000b01f9 --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InObjectPrivateFunctionWithoutInference.kt @@ -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() + +} + +// TYPE: 1 +// SKIP_ANALYZE_CHECK \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InObjectPrivatePropertyType.kt b/idea/testData/codeInsight/outOfBlock/InObjectPrivatePropertyType.kt new file mode 100644 index 00000000000..43418c7bbaf --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InObjectPrivatePropertyType.kt @@ -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 : = 0 +} + +// SKIP_ANALYZE_CHECK \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InitBlockInObject.kt b/idea/testData/codeInsight/outOfBlock/InitBlockInObject.kt new file mode 100644 index 00000000000..da6c07e6f1b --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InitBlockInObject.kt @@ -0,0 +1,8 @@ +// OUT_OF_CODE_BLOCK: FALSE +// ERROR: Unresolved reference: call + +object Foo { + init { + cll() + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java index dc9c07178aa..c7b35523ad2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java @@ -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");