Smart completion for for loop range to use loop variable type if defined

This commit is contained in:
Valentin Kipyatkov
2015-01-16 19:50:43 +03:00
parent f057445f6e
commit a32029f1fc
5 changed files with 32 additions and 5 deletions
@@ -377,14 +377,23 @@ class SmartCompletion(
val smartCastTypes: (VariableDescriptor) -> Collection<JetType> = 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<LookupElement> {
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))
}
@@ -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);
@@ -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<JetType, Boolean>()
@@ -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 {
@@ -0,0 +1,8 @@
fun foo(p1: Collection<String>, p2: Collection<Int>, p3: Collection<String?>) {
for (i: Any in <caret>)
}
// EXIST: p1
// EXIST: p2
// ABSENT: p3
// EXIST: { lookupString:"listOf", itemText: "listOf", tailText: "(vararg values: T) (kotlin)", typeText:"List<T>" }
@@ -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);
}
}
}