Rewrite out-of-block modifier increment algorithm
1. Search the top-level function or property (only they can produce blocks that won't affect other declarations)
2. Check if current position is hidden by this declaration
O^2 behaviour is removed
This commit is contained in:
+22
-62
@@ -107,81 +107,41 @@ public class KotlinCodeBlockModificationListener(modificationTracker: PsiModific
|
||||
if (element is PsiFileSystemItem) return false
|
||||
if (element == null || element.getParent() == null) return true
|
||||
|
||||
var parent = element
|
||||
while (parent !is PsiFile && parent !is PsiDirectory && parent != null) {
|
||||
if (parent is JetClass) return false // anonymous or local class
|
||||
val blockDeclarationCandidate = JetPsiUtil.getTopmostParentOfTypes(
|
||||
element,
|
||||
javaClass<JetProperty>(),
|
||||
javaClass<JetNamedFunction>())
|
||||
|
||||
if (parent is JetBlockExpression) {
|
||||
if (!shouldChangeModificationCount(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
parent = parent!!.getParent()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public fun shouldChangeModificationCount(place: PsiElement): Boolean {
|
||||
// false -> inside code block
|
||||
// true -> means nothing, parent will be checked
|
||||
|
||||
val declaration = PsiTreeUtil.getParentOfType<JetDeclaration>(place, javaClass<JetDeclaration>(), true)
|
||||
if (declaration == null) return true
|
||||
|
||||
return when (declaration) {
|
||||
when (blockDeclarationCandidate) {
|
||||
is JetNamedFunction -> {
|
||||
val function: JetNamedFunction = declaration
|
||||
if (function.hasDeclaredReturnType() || function.hasBlockBody()) {
|
||||
takePartInDeclarationTypeInference(function)
|
||||
val function = blockDeclarationCandidate : JetNamedFunction
|
||||
if (function.hasBlockBody() && function.getBodyExpression().isAncestorOf(element)) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
shouldChangeModificationCount(function)
|
||||
|
||||
if (function.hasDeclaredReturnType() && function.getInitializer().isAncestorOf(element)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
is JetPropertyAccessor -> {
|
||||
takePartInDeclarationTypeInference(declaration)
|
||||
}
|
||||
is JetProperty -> {
|
||||
val property = declaration as JetProperty
|
||||
if (property.getTypeReference() != null) {
|
||||
takePartInDeclarationTypeInference(property)
|
||||
}
|
||||
else {
|
||||
shouldChangeModificationCount(property)
|
||||
}
|
||||
}
|
||||
is JetMultiDeclaration, is JetMultiDeclarationEntry, is JetFunctionLiteral -> {
|
||||
shouldChangeModificationCount(declaration)
|
||||
}
|
||||
else -> {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun takePartInDeclarationTypeInference(place: PsiElement): Boolean {
|
||||
val declaration = PsiTreeUtil.getParentOfType<JetDeclaration>(place, javaClass<JetDeclaration>(), true)
|
||||
if (declaration != null) {
|
||||
if (declaration is JetNamedFunction) {
|
||||
val function = declaration as JetNamedFunction
|
||||
if (!function.hasDeclaredReturnType() && !function.hasBlockBody()) {
|
||||
val property = blockDeclarationCandidate : JetProperty
|
||||
val typeReference = property.getTypeReference()
|
||||
if (typeReference != null && property.getInitializer().isAncestorOf(element)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
else if (declaration is JetProperty) {
|
||||
val property = declaration as JetProperty
|
||||
if (property.getTypeReference() == null) {
|
||||
return true
|
||||
|
||||
for (accessor in property.getAccessors()) {
|
||||
when {
|
||||
accessor.getInitializer().isAncestorOf(element) -> return true
|
||||
accessor.getBodyExpression().isAncestorOf(element) -> return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return takePartInDeclarationTypeInference(declaration)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun PsiElement?.isAncestorOf(element: PsiElement) = PsiTreeUtil.isAncestor(this, element, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// FALSE
|
||||
|
||||
class Test {
|
||||
class Other {
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// FALSE
|
||||
|
||||
class Test {
|
||||
class Other {
|
||||
fun test() {
|
||||
val a<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// FALSE
|
||||
fun test() {
|
||||
class Test {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// TRUE
|
||||
// (Investigation starts from parent)
|
||||
|
||||
fun test() : Int = <caret>12
|
||||
@@ -0,0 +1,3 @@
|
||||
// FALSE
|
||||
|
||||
fun test() : Int = 12 + <caret>12
|
||||
@@ -0,0 +1,6 @@
|
||||
// TRUE
|
||||
class Test {
|
||||
class Other {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// TRUE
|
||||
|
||||
val a = 1
|
||||
fun test() = if (a) {
|
||||
fun hello() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// FALSE
|
||||
fun test() {
|
||||
val some = if () {
|
||||
fun other() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// FALSE
|
||||
trait Some
|
||||
|
||||
fun test() {
|
||||
val foo = object: Some {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// FALSE
|
||||
trait Some
|
||||
|
||||
fun test() {
|
||||
object : Some {
|
||||
fun test(<caret>) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// FALSE
|
||||
object Some {
|
||||
fun test() {
|
||||
<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// FALSE
|
||||
|
||||
object Some {
|
||||
fun test() {
|
||||
if (<caret>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// TRUE
|
||||
|
||||
// TODO: Investigate
|
||||
|
||||
val test = "so<caret>me"
|
||||
@@ -0,0 +1,3 @@
|
||||
// FALSE
|
||||
|
||||
val test: String = "<caret>"
|
||||
+84
@@ -36,6 +36,18 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/codeInsight/outOfBlock"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("Class_Class_FunNoType_Block.kt")
|
||||
public void testClass_Class_FunNoType_Block() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/Class_Class_FunNoType_Block.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Class_Class_FunNoType_Block_Expression.kt")
|
||||
public void testClass_Class_FunNoType_Block_Expression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/Class_Class_FunNoType_Block_Expression.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunInFun.kt")
|
||||
public void testFunInFun() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/FunInFun.kt");
|
||||
@@ -48,6 +60,24 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunNoType_Block_Class.kt")
|
||||
public void testFunNoType_Block_Class() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/FunNoType_Block_Class.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunWithType_Initializer.kt")
|
||||
public void testFunWithType_Initializer() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/FunWithType_Initializer.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunWithType_Initializer_Expression.kt")
|
||||
public void testFunWithType_Initializer_Expression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/FunWithType_Initializer_Expression.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InAntonymsObjectDeclaration.kt")
|
||||
public void testInAntonymsObjectDeclaration() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InAntonymsObjectDeclaration.kt");
|
||||
@@ -60,6 +90,12 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InClassInClass.kt")
|
||||
public void testInClassInClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InClassInClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InClassPropertyAccessor.kt")
|
||||
public void testInClassPropertyAccessor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InClassPropertyAccessor.kt");
|
||||
@@ -72,12 +108,36 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFunInFunctionInitializerInFun.kt")
|
||||
public void testInFunInFunctionInitializerInFun() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InFunInFunctionInitializerInFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFunInMultiDeclaration.kt")
|
||||
public void testInFunInMultiDeclaration() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InFunInMultiDeclaration.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFunInProperty.kt")
|
||||
public void testInFunInProperty() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InFunInProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFunInPropertyInObjectLiteral.kt")
|
||||
public void testInFunInPropertyInObjectLiteral() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InFunInPropertyInObjectLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFunObjectLiteral.kt")
|
||||
public void testInFunObjectLiteral() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InFunObjectLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InFunWithInference.kt")
|
||||
public void testInFunWithInference() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InFunWithInference.kt");
|
||||
@@ -119,4 +179,28 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/InPropertyWithInference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Object_FunNoType_Block.kt")
|
||||
public void testObject_FunNoType_Block() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/Object_FunNoType_Block.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Object_FunNoType_Block_Expression.kt")
|
||||
public void testObject_FunNoType_Block_Expression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/Object_FunNoType_Block_Expression.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyNoType_Initializer_String.kt")
|
||||
public void testPropertyNoType_Initializer_String() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/PropertyNoType_Initializer_String.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyWithType_Initializer_String.kt")
|
||||
public void testPropertyWithType_Initializer_String() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/codeInsight/outOfBlock/PropertyWithType_Initializer_String.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user