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:
Nikolay Krasko
2014-10-21 18:27:51 +04:00
parent 40bd9fbdf3
commit 5cdd5f580d
16 changed files with 204 additions and 62 deletions
@@ -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>"
@@ -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);
}
}