From 1c74bab1cca9862f1b551753eaff8461abd206b1 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 17 Dec 2015 20:55:55 +0300 Subject: [PATCH] Iterate Intention: Fix detection of extension iterators #KT-8616 Fixed --- .../testData/handlers/smart/ForLoopRange.kt | 6 ++--- .../handlers/smart/ForLoopRange.kt.after | 6 ++--- .../testData/handlers/smart/ForLoopRange2.kt | 6 ++--- .../handlers/smart/ForLoopRange2.kt.after | 6 ++--- .../forLoopRange/ExtensionIteratorMethod.kt | 6 ++--- .../idea/core/IterableTypesDetection.kt | 6 ++++- .../iterateExpression/extensionIterator.kt | 8 +++++++ .../extensionIterator.kt.after | 10 ++++++++ ...tensionIteratorWithPartialSubstitution1.kt | 8 +++++++ ...nIteratorWithPartialSubstitution1.kt.after | 10 ++++++++ ...tensionIteratorWithPartialSubstitution2.kt | 9 +++++++ .../iterateExpression/mapIterator.kt | 4 ++++ .../iterateExpression/mapIterator.kt.after | 6 +++++ .../intentions/IntentionTestGenerated.java | 24 +++++++++++++++++++ 14 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 idea/testData/intentions/iterateExpression/extensionIterator.kt create mode 100644 idea/testData/intentions/iterateExpression/extensionIterator.kt.after create mode 100644 idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt create mode 100644 idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt.after create mode 100644 idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution2.kt create mode 100644 idea/testData/intentions/iterateExpression/mapIterator.kt create mode 100644 idea/testData/intentions/iterateExpression/mapIterator.kt.after diff --git a/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt b/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt index 84755bdd1de..5c15073bc5d 100644 --- a/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt +++ b/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt @@ -1,9 +1,9 @@ interface X interface Y -fun X.iterator(): Y -fun Y.next(): Int -fun Y.hasNext(): Boolean +operator fun X.iterator(): Y +operator fun Y.next(): Int +operator fun Y.hasNext(): Boolean fun foo(x: X) { diff --git a/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt.after b/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt.after index 86ea756379c..2b9abfd0cb6 100644 --- a/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt.after +++ b/idea/idea-completion/testData/handlers/smart/ForLoopRange.kt.after @@ -1,9 +1,9 @@ interface X interface Y -fun X.iterator(): Y -fun Y.next(): Int -fun Y.hasNext(): Boolean +operator fun X.iterator(): Y +operator fun Y.next(): Int +operator fun Y.hasNext(): Boolean fun foo(x: X) { diff --git a/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt b/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt index dc3888f6c6e..3199c083e03 100644 --- a/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt +++ b/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt @@ -1,9 +1,9 @@ interface X interface Y -fun X.iterator(): Y -fun Y.next(): Int -fun Y.hasNext(): Boolean +operator fun X.iterator(): Y +operator fun Y.next(): Int +operator fun Y.hasNext(): Boolean fun foo(x: X?) { diff --git a/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt.after b/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt.after index ab183745d8a..e12a66a37e2 100644 --- a/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt.after +++ b/idea/idea-completion/testData/handlers/smart/ForLoopRange2.kt.after @@ -1,9 +1,9 @@ interface X interface Y -fun X.iterator(): Y -fun Y.next(): Int -fun Y.hasNext(): Boolean +operator fun X.iterator(): Y +operator fun Y.next(): Int +operator fun Y.hasNext(): Boolean fun foo(x: X?) { diff --git a/idea/idea-completion/testData/smart/forLoopRange/ExtensionIteratorMethod.kt b/idea/idea-completion/testData/smart/forLoopRange/ExtensionIteratorMethod.kt index 468f58140ef..6a88294a9e0 100644 --- a/idea/idea-completion/testData/smart/forLoopRange/ExtensionIteratorMethod.kt +++ b/idea/idea-completion/testData/smart/forLoopRange/ExtensionIteratorMethod.kt @@ -1,9 +1,9 @@ interface X interface Y -fun X.iterator(): Y -fun Y.next(): Int -fun Y.hasNext(): Boolean +operator fun X.iterator(): Y +operator fun Y.next(): Int +operator fun Y.hasNext(): Boolean fun foo(x: X, y: Y) { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt index 1127d8d6fd9..41eec20996d 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/IterableTypesDetection.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.idea.core import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name @@ -79,7 +80,10 @@ public class IterableTypesDetection( private fun canBeIterable(type: FuzzyType): Boolean { return type.type.memberScope.getContributedFunctions(iteratorName, NoLookupLocation.FROM_IDE).isNotEmpty() || - typesWithExtensionIterator.any { type.checkIsSubtypeOf(it) != null } + typesWithExtensionIterator.any { + val freeParams = it.arguments.mapNotNull { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } + type.checkIsSubtypeOf(FuzzyType(it, freeParams)) != null + } } } } diff --git a/idea/testData/intentions/iterateExpression/extensionIterator.kt b/idea/testData/intentions/iterateExpression/extensionIterator.kt new file mode 100644 index 00000000000..3e4d13d5014 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/extensionIterator.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +class T + +operator fun T.iterator(): Iterator = listOf().iterator() + +fun test() { + T() +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/extensionIterator.kt.after b/idea/testData/intentions/iterateExpression/extensionIterator.kt.after new file mode 100644 index 00000000000..daa3bbc3302 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/extensionIterator.kt.after @@ -0,0 +1,10 @@ +// WITH_RUNTIME +class T + +operator fun T.iterator(): Iterator = listOf().iterator() + +fun test() { + for (i in T()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt b/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt new file mode 100644 index 00000000000..eac83d46b88 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +class T + +operator fun T.iterator(): Iterator = listOf().iterator() + +fun test() { + T() +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt.after b/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt.after new file mode 100644 index 00000000000..b3b36c29653 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt.after @@ -0,0 +1,10 @@ +// WITH_RUNTIME +class T + +operator fun T.iterator(): Iterator = listOf().iterator() + +fun test() { + for (i in T()) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution2.kt b/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution2.kt new file mode 100644 index 00000000000..efc16450ed3 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution2.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +class T + +operator fun T.iterator(): Iterator = listOf().iterator() + +fun test() { + T() +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/mapIterator.kt b/idea/testData/intentions/iterateExpression/mapIterator.kt new file mode 100644 index 00000000000..d4d6c9586c1 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/mapIterator.kt @@ -0,0 +1,4 @@ +// WITH_RUNTIME +fun test() { + mapOf(1 to "1", 2 to "2") +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/mapIterator.kt.after b/idea/testData/intentions/iterateExpression/mapIterator.kt.after new file mode 100644 index 00000000000..a200ba53ff1 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/mapIterator.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +fun test() { + for (entry in mapOf(1 to "1", 2 to "2")) { + + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 1fc7787e75c..c682aebaa06 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -5817,12 +5817,36 @@ public class IntentionTestGenerated extends AbstractIntentionTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/iterateExpression"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); } + @TestMetadata("extensionIterator.kt") + public void testExtensionIterator() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/extensionIterator.kt"); + doTest(fileName); + } + + @TestMetadata("extensionIteratorWithPartialSubstitution1.kt") + public void testExtensionIteratorWithPartialSubstitution1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution1.kt"); + doTest(fileName); + } + + @TestMetadata("extensionIteratorWithPartialSubstitution2.kt") + public void testExtensionIteratorWithPartialSubstitution2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/extensionIteratorWithPartialSubstitution2.kt"); + doTest(fileName); + } + @TestMetadata("functionCall.kt") public void testFunctionCall() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/functionCall.kt"); doTest(fileName); } + @TestMetadata("mapIterator.kt") + public void testMapIterator() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/mapIterator.kt"); + doTest(fileName); + } + @TestMetadata("nameSuggestion.kt") public void testNameSuggestion() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/nameSuggestion.kt");