Smart completion for for loop range to use loop variable type if defined
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user