diff --git a/idea/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt b/idea/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt index de5ee19072c..d65da01ec52 100644 --- a/idea/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt +++ b/idea/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt @@ -377,14 +377,23 @@ class SmartCompletion( val smartCastTypes: (VariableDescriptor) -> Collection = TypesWithSmartCasts(bindingContext).calculate(expressionWithType, receiver) val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType) - val iterableDetector = IterableTypesDetector(project, moduleDescriptor, scope) + + val loopVar = forExpression.getLoopParameter() + val loopVarType = if (loopVar != null && loopVar.getTypeReference() != null) { + val type = (resolutionFacade.resolveToDescriptor(loopVar) as VariableDescriptor).getType() + if (type.isError()) null else type + } + else { + null + } + + val iterableDetector = IterableTypesDetector(project, moduleDescriptor, scope, loopVarType) fun filterDeclaration(descriptor: DeclarationDescriptor): Collection { val types = descriptor.fuzzyTypes(smartCastTypes) fun createLookupElement() = lookupElementFactory.createLookupElement(descriptor, resolutionFacade, bindingContext, true) - //TODO: use type of variable if declared if (types.any { iterableDetector.isIterable(it.type) }) { return listOf(createLookupElement().addTail(Tail.RPARENTH)) } diff --git a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseJetVariableMacro.java b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseJetVariableMacro.java index 4f309d84592..72c0dd8e5c5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseJetVariableMacro.java +++ b/idea/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseJetVariableMacro.java @@ -71,7 +71,7 @@ public abstract class BaseJetVariableMacro extends Macro { return null; } - IterableTypesDetector iterableTypesDetector = new IterableTypesDetector(project, analysisResult.getModuleDescriptor(), scope); + IterableTypesDetector iterableTypesDetector = new IterableTypesDetector(project, analysisResult.getModuleDescriptor(), scope, null); DataFlowInfo dataFlowInfo = getDataFlowInfo(bindingContext, contextExpression); diff --git a/idea/src/org/jetbrains/kotlin/idea/util/IterableTypesDetector.kt b/idea/src/org/jetbrains/kotlin/idea/util/IterableTypesDetector.kt index 68206ed6823..31bb2be9f6f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/IterableTypesDetector.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/IterableTypesDetector.kt @@ -34,7 +34,9 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf public class IterableTypesDetector( private val project: Project, private val moduleDescriptor: ModuleDescriptor, - private val scope: JetScope) { + private val scope: JetScope, + private val loopVarType: JetType? = null +) { private val injector = InjectorForMacros(project, moduleDescriptor) private val cache = HashMap() @@ -56,7 +58,9 @@ public class IterableTypesDetector( val expression = JetPsiFactory(project).createExpression("fake") val expressionReceiver = ExpressionReceiver(expression, type) val context = ExpressionTypingContext.newContext(injector.getExpressionTypingServices(), BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE) - return injector.getExpressionTypingComponents().getForLoopConventionsChecker().checkIterableConvention(expressionReceiver, context) != null + val elementType = injector.getExpressionTypingComponents().getForLoopConventionsChecker().checkIterableConvention(expressionReceiver, context) + if (elementType == null) return false + return loopVarType == null || elementType.isSubtypeOf(loopVarType) } private fun canBeIterable(type: JetType): Boolean { diff --git a/idea/testData/completion/smart/forLoopRange/TypedLoopVar.kt b/idea/testData/completion/smart/forLoopRange/TypedLoopVar.kt new file mode 100644 index 00000000000..24ec662a145 --- /dev/null +++ b/idea/testData/completion/smart/forLoopRange/TypedLoopVar.kt @@ -0,0 +1,8 @@ +fun foo(p1: Collection, p2: Collection, p3: Collection) { + for (i: Any in ) +} + +// EXIST: p1 +// EXIST: p2 +// ABSENT: p3 +// EXIST: { lookupString:"listOf", itemText: "listOf", tailText: "(vararg values: T) (kotlin)", typeText:"List" } diff --git a/idea/tests/org/jetbrains/kotlin/completion/JvmSmartCompletionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/completion/JvmSmartCompletionTestGenerated.java index 86ff7361efd..575ca8a5568 100644 --- a/idea/tests/org/jetbrains/kotlin/completion/JvmSmartCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/completion/JvmSmartCompletionTestGenerated.java @@ -980,5 +980,11 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/forLoopRange/SmartCasts.kt"); doTest(fileName); } + + @TestMetadata("TypedLoopVar.kt") + public void testTypedLoopVar() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/forLoopRange/TypedLoopVar.kt"); + doTest(fileName); + } } }