Smart completion: heuristic parameter types for some methods like Collection.contains()
This commit is contained in:
Generated
+1
@@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="valentin">
|
<dictionary name="valentin">
|
||||||
<words>
|
<words>
|
||||||
|
<w>funs</w>
|
||||||
<w>initializers</w>
|
<w>initializers</w>
|
||||||
<w>inserter</w>
|
<w>inserter</w>
|
||||||
<w>pparent</w>
|
<w>pparent</w>
|
||||||
|
|||||||
@@ -23,20 +23,17 @@ import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap;
|
|||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingComponents;
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingComponents;
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallResolver;
|
import org.jetbrains.kotlin.resolve.calls.CallResolver;
|
||||||
|
import org.jetbrains.kotlin.resolve.TypeResolver;
|
||||||
import org.jetbrains.kotlin.context.GlobalContext;
|
import org.jetbrains.kotlin.context.GlobalContext;
|
||||||
import org.jetbrains.kotlin.storage.StorageManager;
|
import org.jetbrains.kotlin.storage.StorageManager;
|
||||||
import org.jetbrains.kotlin.resolve.AdditionalCheckerProvider.DefaultProvider;
|
import org.jetbrains.kotlin.resolve.AdditionalCheckerProvider.DefaultProvider;
|
||||||
import org.jetbrains.kotlin.resolve.AnnotationResolver;
|
import org.jetbrains.kotlin.resolve.AnnotationResolver;
|
||||||
import org.jetbrains.kotlin.resolve.TypeResolver;
|
|
||||||
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver;
|
|
||||||
import org.jetbrains.kotlin.resolve.TypeResolver.FlexibleTypeCapabilitiesProvider;
|
|
||||||
import org.jetbrains.kotlin.context.LazinessToken;
|
|
||||||
import org.jetbrains.kotlin.types.DynamicTypesSettings;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
|
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorResolver;
|
import org.jetbrains.kotlin.resolve.DescriptorResolver;
|
||||||
import org.jetbrains.kotlin.resolve.DelegatedPropertyResolver;
|
import org.jetbrains.kotlin.resolve.DelegatedPropertyResolver;
|
||||||
import org.jetbrains.kotlin.resolve.StatementFilter;
|
import org.jetbrains.kotlin.resolve.StatementFilter;
|
||||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils;
|
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils;
|
||||||
|
import org.jetbrains.kotlin.types.DynamicTypesSettings;
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
|
||||||
import org.jetbrains.kotlin.types.expressions.ForLoopConventionsChecker;
|
import org.jetbrains.kotlin.types.expressions.ForLoopConventionsChecker;
|
||||||
import org.jetbrains.kotlin.types.expressions.LocalClassifierAnalyzer;
|
import org.jetbrains.kotlin.types.expressions.LocalClassifierAnalyzer;
|
||||||
@@ -45,6 +42,9 @@ import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.CallCompleter;
|
import org.jetbrains.kotlin.resolve.calls.CallCompleter;
|
||||||
import org.jetbrains.kotlin.resolve.calls.CandidateResolver;
|
import org.jetbrains.kotlin.resolve.calls.CandidateResolver;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TaskPrioritizer;
|
import org.jetbrains.kotlin.resolve.calls.tasks.TaskPrioritizer;
|
||||||
|
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver;
|
||||||
|
import org.jetbrains.kotlin.resolve.TypeResolver.FlexibleTypeCapabilitiesProvider;
|
||||||
|
import org.jetbrains.kotlin.context.LazinessToken;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
@@ -59,20 +59,17 @@ public class InjectorForMacros {
|
|||||||
private final ExpressionTypingServices expressionTypingServices;
|
private final ExpressionTypingServices expressionTypingServices;
|
||||||
private final ExpressionTypingComponents expressionTypingComponents;
|
private final ExpressionTypingComponents expressionTypingComponents;
|
||||||
private final CallResolver callResolver;
|
private final CallResolver callResolver;
|
||||||
|
private final TypeResolver typeResolver;
|
||||||
private final GlobalContext globalContext;
|
private final GlobalContext globalContext;
|
||||||
private final StorageManager storageManager;
|
private final StorageManager storageManager;
|
||||||
private final DefaultProvider defaultProvider;
|
private final DefaultProvider defaultProvider;
|
||||||
private final AnnotationResolver annotationResolver;
|
private final AnnotationResolver annotationResolver;
|
||||||
private final TypeResolver typeResolver;
|
|
||||||
private final QualifiedExpressionResolver qualifiedExpressionResolver;
|
|
||||||
private final FlexibleTypeCapabilitiesProvider flexibleTypeCapabilitiesProvider;
|
|
||||||
private final LazinessToken lazinessToken;
|
|
||||||
private final DynamicTypesSettings dynamicTypesSettings;
|
|
||||||
private final CallExpressionResolver callExpressionResolver;
|
private final CallExpressionResolver callExpressionResolver;
|
||||||
private final DescriptorResolver descriptorResolver;
|
private final DescriptorResolver descriptorResolver;
|
||||||
private final DelegatedPropertyResolver delegatedPropertyResolver;
|
private final DelegatedPropertyResolver delegatedPropertyResolver;
|
||||||
private final StatementFilter statementFilter;
|
private final StatementFilter statementFilter;
|
||||||
private final ControlStructureTypingUtils controlStructureTypingUtils;
|
private final ControlStructureTypingUtils controlStructureTypingUtils;
|
||||||
|
private final DynamicTypesSettings dynamicTypesSettings;
|
||||||
private final ExpressionTypingUtils expressionTypingUtils;
|
private final ExpressionTypingUtils expressionTypingUtils;
|
||||||
private final ForLoopConventionsChecker forLoopConventionsChecker;
|
private final ForLoopConventionsChecker forLoopConventionsChecker;
|
||||||
private final LocalClassifierAnalyzer localClassifierAnalyzer;
|
private final LocalClassifierAnalyzer localClassifierAnalyzer;
|
||||||
@@ -81,6 +78,9 @@ public class InjectorForMacros {
|
|||||||
private final CallCompleter callCompleter;
|
private final CallCompleter callCompleter;
|
||||||
private final CandidateResolver candidateResolver;
|
private final CandidateResolver candidateResolver;
|
||||||
private final TaskPrioritizer taskPrioritizer;
|
private final TaskPrioritizer taskPrioritizer;
|
||||||
|
private final QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||||
|
private final FlexibleTypeCapabilitiesProvider flexibleTypeCapabilitiesProvider;
|
||||||
|
private final LazinessToken lazinessToken;
|
||||||
|
|
||||||
public InjectorForMacros(
|
public InjectorForMacros(
|
||||||
@NotNull Project project,
|
@NotNull Project project,
|
||||||
@@ -93,15 +93,15 @@ public class InjectorForMacros {
|
|||||||
this.expressionTypingComponents = new ExpressionTypingComponents();
|
this.expressionTypingComponents = new ExpressionTypingComponents();
|
||||||
this.expressionTypingServices = new ExpressionTypingServices(getExpressionTypingComponents());
|
this.expressionTypingServices = new ExpressionTypingServices(getExpressionTypingComponents());
|
||||||
this.callResolver = new CallResolver();
|
this.callResolver = new CallResolver();
|
||||||
this.globalContext = org.jetbrains.kotlin.context.ContextPackage.GlobalContext();
|
|
||||||
this.storageManager = globalContext.getStorageManager();
|
|
||||||
this.defaultProvider = DefaultProvider.INSTANCE$;
|
|
||||||
this.annotationResolver = new AnnotationResolver();
|
this.annotationResolver = new AnnotationResolver();
|
||||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||||
this.flexibleTypeCapabilitiesProvider = new FlexibleTypeCapabilitiesProvider();
|
this.flexibleTypeCapabilitiesProvider = new FlexibleTypeCapabilitiesProvider();
|
||||||
|
this.globalContext = org.jetbrains.kotlin.context.ContextPackage.GlobalContext();
|
||||||
|
this.storageManager = globalContext.getStorageManager();
|
||||||
this.lazinessToken = new LazinessToken();
|
this.lazinessToken = new LazinessToken();
|
||||||
this.dynamicTypesSettings = new DynamicTypesSettings();
|
this.dynamicTypesSettings = new DynamicTypesSettings();
|
||||||
this.typeResolver = new TypeResolver(annotationResolver, qualifiedExpressionResolver, moduleDescriptor, flexibleTypeCapabilitiesProvider, storageManager, lazinessToken, dynamicTypesSettings);
|
this.typeResolver = new TypeResolver(annotationResolver, qualifiedExpressionResolver, moduleDescriptor, flexibleTypeCapabilitiesProvider, storageManager, lazinessToken, dynamicTypesSettings);
|
||||||
|
this.defaultProvider = DefaultProvider.INSTANCE$;
|
||||||
this.callExpressionResolver = new CallExpressionResolver();
|
this.callExpressionResolver = new CallExpressionResolver();
|
||||||
this.descriptorResolver = new DescriptorResolver();
|
this.descriptorResolver = new DescriptorResolver();
|
||||||
this.delegatedPropertyResolver = new DelegatedPropertyResolver();
|
this.delegatedPropertyResolver = new DelegatedPropertyResolver();
|
||||||
@@ -109,7 +109,7 @@ public class InjectorForMacros {
|
|||||||
this.controlStructureTypingUtils = new ControlStructureTypingUtils(getExpressionTypingServices());
|
this.controlStructureTypingUtils = new ControlStructureTypingUtils(getExpressionTypingServices());
|
||||||
this.expressionTypingUtils = new ExpressionTypingUtils(getExpressionTypingServices(), getCallResolver(), kotlinBuiltIns);
|
this.expressionTypingUtils = new ExpressionTypingUtils(getExpressionTypingServices(), getCallResolver(), kotlinBuiltIns);
|
||||||
this.forLoopConventionsChecker = new ForLoopConventionsChecker();
|
this.forLoopConventionsChecker = new ForLoopConventionsChecker();
|
||||||
this.localClassifierAnalyzer = new LocalClassifierAnalyzer(descriptorResolver, typeResolver, annotationResolver);
|
this.localClassifierAnalyzer = new LocalClassifierAnalyzer(descriptorResolver, getTypeResolver(), annotationResolver);
|
||||||
this.reflectionTypes = new ReflectionTypes(moduleDescriptor);
|
this.reflectionTypes = new ReflectionTypes(moduleDescriptor);
|
||||||
this.argumentTypeResolver = new ArgumentTypeResolver();
|
this.argumentTypeResolver = new ArgumentTypeResolver();
|
||||||
this.candidateResolver = new CandidateResolver();
|
this.candidateResolver = new CandidateResolver();
|
||||||
@@ -191,4 +191,8 @@ public class InjectorForMacros {
|
|||||||
return this.callResolver;
|
return this.callResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TypeResolver getTypeResolver() {
|
||||||
|
return this.typeResolver;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ private fun generatorForMacro() =
|
|||||||
publicField<ExpressionTypingServices>()
|
publicField<ExpressionTypingServices>()
|
||||||
publicField<ExpressionTypingComponents>()
|
publicField<ExpressionTypingComponents>()
|
||||||
publicField<CallResolver>()
|
publicField<CallResolver>()
|
||||||
|
publicField<TypeResolver>()
|
||||||
|
|
||||||
field<GlobalContext>(useAsContext = true,
|
field<GlobalContext>(useAsContext = true,
|
||||||
init = GivenExpression("org.jetbrains.kotlin.context.ContextPackage.GlobalContext()"))
|
init = GivenExpression("org.jetbrains.kotlin.context.ContextPackage.GlobalContext()"))
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
|
||||||
enum class Tail {
|
enum class Tail {
|
||||||
COMMA
|
COMMA
|
||||||
@@ -89,7 +90,12 @@ class PositionalArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?,
|
|||||||
= function.hashCode()
|
= function.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpectedInfos(val bindingContext: BindingContext, val resolutionFacade: ResolutionFacade) {
|
class ExpectedInfos(
|
||||||
|
val bindingContext: BindingContext,
|
||||||
|
val resolutionFacade: ResolutionFacade,
|
||||||
|
val moduleDescriptor: ModuleDescriptor,
|
||||||
|
val useHeuristicSignatures: Boolean
|
||||||
|
) {
|
||||||
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
return calculateForArgument(expressionWithType)
|
return calculateForArgument(expressionWithType)
|
||||||
?: calculateForFunctionLiteralArgument(expressionWithType)
|
?: calculateForFunctionLiteralArgument(expressionWithType)
|
||||||
@@ -207,7 +213,11 @@ class ExpectedInfos(val bindingContext: BindingContext, val resolutionFacade: Re
|
|||||||
|
|
||||||
val parameter = parameters[argumentIndex]
|
val parameter = parameters[argumentIndex]
|
||||||
val expectedName = if (descriptor.hasSynthesizedParameterNames()) null else parameter.getName().asString()
|
val expectedName = if (descriptor.hasSynthesizedParameterNames()) null else parameter.getName().asString()
|
||||||
expectedInfos.add(PositionalArgumentExpectedInfo(parameter.getType(), expectedName, tail, descriptor, argumentIndex))
|
val parameterType = if (useHeuristicSignatures)
|
||||||
|
HeuristicSignatures.correctedParameterType(descriptor, argumentIndex, moduleDescriptor, callElement.getProject()) ?: parameter.getType()
|
||||||
|
else
|
||||||
|
parameter.getType()
|
||||||
|
expectedInfos.add(PositionalArgumentExpectedInfo(parameterType, expectedName, tail, descriptor, argumentIndex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return expectedInfos
|
return expectedInfos
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import java.util.HashMap
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.types.SubstitutionUtils
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.di.InjectorForMacros
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import org.jetbrains.kotlin.resolve.JetModuleUtil
|
||||||
|
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
|
public object HeuristicSignatures {
|
||||||
|
private val signatures = HashMap<Pair<FqName, Name>, List<String>>()
|
||||||
|
|
||||||
|
;{
|
||||||
|
registerSignature("kotlin.Collection", "contains", "E")
|
||||||
|
registerSignature("kotlin.Collection", "containsAll", "kotlin.Collection<E>")
|
||||||
|
registerSignature("kotlin.MutableCollection", "remove", "E")
|
||||||
|
registerSignature("kotlin.MutableCollection", "removeAll", "kotlin.Collection<E>")
|
||||||
|
registerSignature("kotlin.MutableCollection", "retainAll", "kotlin.Collection<E>")
|
||||||
|
registerSignature("kotlin.List", "indexOf", "E")
|
||||||
|
registerSignature("kotlin.List", "lastIndexOf", "E")
|
||||||
|
registerSignature("kotlin.Map", "get", "K")
|
||||||
|
registerSignature("kotlin.Map", "containsKey", "K")
|
||||||
|
registerSignature("kotlin.Map", "containsValue", "V")
|
||||||
|
registerSignature("kotlin.MutableMap", "remove", "K")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerSignature(
|
||||||
|
classFqName: String,
|
||||||
|
name: String,
|
||||||
|
vararg parameterTypes: String) {
|
||||||
|
signatures[FqName(classFqName) to Name.identifier(name)] = parameterTypes.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun correctedParameterType(function: FunctionDescriptor, parameterIndex: Int, moduleDescriptor: ModuleDescriptor, project: Project): JetType? {
|
||||||
|
val ownerType = function.getDispatchReceiverParameter()?.getType() ?: return null
|
||||||
|
|
||||||
|
val superFunctions = function.getOverriddenDescriptors()
|
||||||
|
if (superFunctions.isNotEmpty()) {
|
||||||
|
for (superFunction in superFunctions) {
|
||||||
|
val correctedType = correctedParameterType(superFunction, parameterIndex, moduleDescriptor, project) ?: continue
|
||||||
|
val typeSubstitutor = SubstitutionUtils.buildDeepSubstitutor(ownerType)
|
||||||
|
return typeSubstitutor.safeSubstitute(correctedType, Variance.INVARIANT)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val ownerClass = ownerType.getConstructor().getDeclarationDescriptor() ?: return null
|
||||||
|
val classFqName = DescriptorUtils.getFqNameSafe(ownerClass)
|
||||||
|
val parameterTypes = signatures[classFqName to function.getName()] ?: return null
|
||||||
|
val typeStr = parameterTypes[parameterIndex]
|
||||||
|
val typeParameters = ownerClass.getTypeConstructor().getParameters()
|
||||||
|
|
||||||
|
val type = typeFromText(typeStr, typeParameters, moduleDescriptor, project)
|
||||||
|
|
||||||
|
// now substitute type parameters with actual arguments
|
||||||
|
val typeArgs = ownerType.getArguments()
|
||||||
|
val typeArgsMap = typeParameters.indices.map { typeParameters[it] to typeArgs[it] }.toMap()
|
||||||
|
val substitutor = TypeUtils.makeSubstitutorForTypeParametersMap(typeArgsMap)
|
||||||
|
return substitutor.substitute(type, Variance.INVARIANT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun typeFromText(text: String, typeParameters: Collection<TypeParameterDescriptor>, moduleDescriptor: ModuleDescriptor, project: Project): JetType {
|
||||||
|
val typeRef = JetPsiFactory(project).createType(text)
|
||||||
|
val injector = InjectorForMacros(project, moduleDescriptor)
|
||||||
|
val rootPackagesScope = JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor)
|
||||||
|
val typeParametersScope = TypeParametersScope(typeParameters)
|
||||||
|
val scope = ChainedScope(moduleDescriptor, "Root packages + type parameters", typeParametersScope, rootPackagesScope)
|
||||||
|
val type = injector.getTypeResolver().resolveType(scope, typeRef, BindingTraceContext(), false)
|
||||||
|
assert(!type.isError()) { "No type resolved from '$text'" }
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeParametersScope(params: Collection<TypeParameterDescriptor>) : JetScope by JetScope.Empty {
|
||||||
|
private val paramsByName = params.map { it.getName() to it }.toMap()
|
||||||
|
|
||||||
|
override fun getClassifier(name: Name) = paramsByName[name]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,8 +73,8 @@ fun insertLambdaTemplate(context: InsertionContext, placeholderRange: TextRange,
|
|||||||
|
|
||||||
fun buildLambdaPresentation(lambdaType: JetType): String {
|
fun buildLambdaPresentation(lambdaType: JetType): String {
|
||||||
val parameterTypes = functionParameterTypes(lambdaType)
|
val parameterTypes = functionParameterTypes(lambdaType)
|
||||||
val parametersPresentation = parameterTypes.map { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) }.makeString(", ")
|
val parametersPresentation = parameterTypes.map { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) }.joinToString(", ")
|
||||||
fun wrap(s: String) = if (parameterTypes.size != 1) "($s)" else s
|
fun wrap(s: String) = if (parameterTypes.size() != 1) "($s)" else s
|
||||||
return "{ ${wrap(parametersPresentation)} -> ... }"
|
return "{ ${wrap(parametersPresentation)} -> ... }"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,18 +86,18 @@ private fun needExplicitParameterTypes(context: InsertionContext, placeholderRan
|
|||||||
|
|
||||||
val resolutionFacade = file.getResolutionFacade()
|
val resolutionFacade = file.getResolutionFacade()
|
||||||
val bindingContext = resolutionFacade.analyze(expression, BodyResolveMode.PARTIAL)
|
val bindingContext = resolutionFacade.analyze(expression, BodyResolveMode.PARTIAL)
|
||||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade).calculate(expression) ?: return false
|
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, resolutionFacade.findModuleDescriptor(file), false).calculate(expression) ?: return false
|
||||||
val functionTypes = expectedInfos.map { it.type }.filter { KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(it) }.toSet()
|
val functionTypes = expectedInfos.map { it.type }.filter { KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(it) }.toSet()
|
||||||
if (functionTypes.size <= 1) return false
|
if (functionTypes.size() <= 1) return false
|
||||||
|
|
||||||
val lambdaParameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(lambdaType).size
|
val lambdaParameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(lambdaType).size()
|
||||||
return functionTypes.filter { KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(it).size == lambdaParameterCount }.size > 1
|
return functionTypes.filter { KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(it).size() == lambdaParameterCount }.size() > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildTemplate(lambdaType: JetType, explicitParameterTypes: Boolean, project: Project): Template {
|
private fun buildTemplate(lambdaType: JetType, explicitParameterTypes: Boolean, project: Project): Template {
|
||||||
val parameterTypes = functionParameterTypes(lambdaType)
|
val parameterTypes = functionParameterTypes(lambdaType)
|
||||||
|
|
||||||
val useParenthesis = explicitParameterTypes || parameterTypes.size != 1
|
val useParenthesis = explicitParameterTypes || parameterTypes.size() != 1
|
||||||
|
|
||||||
val manager = TemplateManager.getInstance(project)
|
val manager = TemplateManager.getInstance(project)
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ private fun buildTemplate(lambdaType: JetType, explicitParameterTypes: Boolean,
|
|||||||
template.addTextSegment("(")
|
template.addTextSegment("(")
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((i, parameterType) in parameterTypes.withIndices()) {
|
for ((i, parameterType) in parameterTypes.withIndex()) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
template.addTextSegment(", ")
|
template.addTextSegment(", ")
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ private class ParameterNameExpression(val nameSuggestions: Array<String>) : Expr
|
|||||||
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
|
override fun calculateQuickResult(context: ExpressionContext?): Result? = null
|
||||||
|
|
||||||
override fun calculateLookupItems(context: ExpressionContext?)
|
override fun calculateLookupItems(context: ExpressionContext?)
|
||||||
= Array<LookupElement>(nameSuggestions.size, { LookupElementBuilder.create(nameSuggestions[it]) })
|
= Array<LookupElement>(nameSuggestions.size(), { LookupElementBuilder.create(nameSuggestions[it]) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun functionParameterTypes(functionType: JetType): List<JetType>
|
fun functionParameterTypes(functionType: JetType): List<JetType>
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ class SmartCompletion(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExpectedInfos(bindingContext, resolutionFacade).calculate(expression)
|
return ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, true).calculate(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun implicitlyTypedDeclarationFromInitializer(expression: JetExpression): JetDeclaration? {
|
private fun implicitlyTypedDeclarationFromInitializer(expression: JetExpression): JetDeclaration? {
|
||||||
@@ -400,7 +400,7 @@ class SmartCompletion(
|
|||||||
|
|
||||||
val leftOperandType = bindingContext.get(BindingContext.EXPRESSION_TYPE, binaryExpression.getLeft()) ?: return null
|
val leftOperandType = bindingContext.get(BindingContext.EXPRESSION_TYPE, binaryExpression.getLeft()) ?: return null
|
||||||
val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType)
|
val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType)
|
||||||
val detector = TypesWithContainsDetector(scope, leftOperandType)
|
val detector = TypesWithContainsDetector(scope, leftOperandType, project, moduleDescriptor)
|
||||||
|
|
||||||
return buildResultByTypeFilter(expressionWithType, receiver, null) { detector.hasContains(it) }
|
return buildResultByTypeFilter(expressionWithType, receiver, null) { detector.hasContains(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,15 @@ import org.jetbrains.kotlin.idea.util.nullability
|
|||||||
import org.jetbrains.kotlin.idea.util.TypeNullability
|
import org.jetbrains.kotlin.idea.util.TypeNullability
|
||||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.idea.completion.HeuristicSignatures
|
||||||
|
|
||||||
//TODO: heuristics for collection's?
|
|
||||||
class TypesWithContainsDetector(
|
class TypesWithContainsDetector(
|
||||||
private val scope: JetScope,
|
private val scope: JetScope,
|
||||||
private val argumentType: JetType
|
private val argumentType: JetType,
|
||||||
|
private val project: Project,
|
||||||
|
private val moduleDescriptor: ModuleDescriptor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val cache = HashMap<FuzzyType, Boolean>()
|
private val cache = HashMap<FuzzyType, Boolean>()
|
||||||
@@ -54,7 +58,8 @@ class TypesWithContainsDetector(
|
|||||||
private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean {
|
private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean {
|
||||||
if (!TypeUtils.equalTypes(function.getReturnType(), booleanType)) return false
|
if (!TypeUtils.equalTypes(function.getReturnType(), booleanType)) return false
|
||||||
val parameter = function.getValueParameters().singleOrNull() ?: return false
|
val parameter = function.getValueParameters().singleOrNull() ?: return false
|
||||||
val parameterType = FuzzyType(parameter.getType(), function.getTypeParameters() + freeTypeParams)
|
val parameterType = HeuristicSignatures.correctedParameterType(function, 0, moduleDescriptor, project) ?: parameter.getType()
|
||||||
return parameterType.checkIsSuperTypeOf(argumentType) != null
|
val fuzzyParameterType = FuzzyType(parameterType, function.getTypeParameters() + freeTypeParams)
|
||||||
|
return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(list: List<String>, p1: Any, p2: String) {
|
||||||
|
list.contains(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
|
// EXIST: { itemText: "String", tailText: "() (kotlin)" }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(list: List<String>, p1: Collection<Any>, p2: List<String>) {
|
||||||
|
list.containsAll(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(list: Map<String, Int>, p1: Any, p2: String) {
|
||||||
|
list.containsKey(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(list: Map<String, Int>, p1: Any, p2: Int) {
|
||||||
|
list.containsValue(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(list: Map<String, Int>, p1: Any, p2: String) {
|
||||||
|
list.get(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
trait A
|
||||||
|
trait B : A
|
||||||
|
trait C
|
||||||
|
|
||||||
|
fun foo(a: A, cA: Collection<A>, cB: Collection<B>, cC: Collection<C>, cAny: Collection<Any>,
|
||||||
|
lA: List<A>, lb: List<B>, lC: List<C>, lAny: List<Any>,
|
||||||
|
aA: ArrayList<A>, aB: ArrayList<B>, aC: ArrayList<C>, aAny: ArrayList<Any>) {
|
||||||
|
if (a in <caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: cA
|
||||||
|
// ABSENT: cB
|
||||||
|
// ABSENT: cC
|
||||||
|
// EXIST: cAny
|
||||||
|
// EXIST: lA
|
||||||
|
// ABSENT: lB
|
||||||
|
// ABSENT: lC
|
||||||
|
// EXIST: lAny
|
||||||
|
// EXIST: aA
|
||||||
|
// ABSENT: aB
|
||||||
|
// ABSENT: aC
|
||||||
|
// EXIST: aAny
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(list: List<String>, p1: Any, p2: String) {
|
||||||
|
list.indexOf(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
|
// EXIST: { itemText: "String", tailText: "() (kotlin)" }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(list: List<String>, p1: Any, p2: String) {
|
||||||
|
list.lastIndexOf(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
|
// EXIST: { itemText: "String", tailText: "() (kotlin)" }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(list: MutableMap<String, Int>, p1: Any, p2: String) {
|
||||||
|
list.remove(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun foo(list: ArrayList<String>, p1: Any, p2: String) {
|
||||||
|
list.remove(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
|
// EXIST: { itemText: "String", tailText: "() (kotlin)" }
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun foo(list: ArrayList<String>, p1: ArrayList<Any>, p2: ArrayList<String>) {
|
||||||
|
list.removeAll(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun foo(list: ArrayList<String>, p1: ArrayList<Any>, p2: ArrayList<String>) {
|
||||||
|
list.retainAll(<caret>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: p1
|
||||||
|
// EXIST: p2
|
||||||
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
|
|||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@TestMetadata("idea/testData/completion/smart")
|
@TestMetadata("idea/testData/completion/smart")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@InnerTestClasses({JvmSmartCompletionTestGenerated.AfterAs.class, JvmSmartCompletionTestGenerated.AnonymousObject.class, JvmSmartCompletionTestGenerated.Constructor.class, JvmSmartCompletionTestGenerated.ForLoopRange.class, JvmSmartCompletionTestGenerated.FunctionLiterals.class, JvmSmartCompletionTestGenerated.FunctionReference.class, JvmSmartCompletionTestGenerated.Generics.class, JvmSmartCompletionTestGenerated.IfValue.class, JvmSmartCompletionTestGenerated.InElvisOperator.class, JvmSmartCompletionTestGenerated.InOperator.class, JvmSmartCompletionTestGenerated.Inheritors.class, JvmSmartCompletionTestGenerated.MultipleArgsItem.class, JvmSmartCompletionTestGenerated.SmartCasts.class, JvmSmartCompletionTestGenerated.This.class, JvmSmartCompletionTestGenerated.WhenEntry.class})
|
@InnerTestClasses({JvmSmartCompletionTestGenerated.AfterAs.class, JvmSmartCompletionTestGenerated.AnonymousObject.class, JvmSmartCompletionTestGenerated.Constructor.class, JvmSmartCompletionTestGenerated.ForLoopRange.class, JvmSmartCompletionTestGenerated.FunctionLiterals.class, JvmSmartCompletionTestGenerated.FunctionReference.class, JvmSmartCompletionTestGenerated.Generics.class, JvmSmartCompletionTestGenerated.HeuristicSignatures.class, JvmSmartCompletionTestGenerated.IfValue.class, JvmSmartCompletionTestGenerated.InElvisOperator.class, JvmSmartCompletionTestGenerated.InOperator.class, JvmSmartCompletionTestGenerated.Inheritors.class, JvmSmartCompletionTestGenerated.MultipleArgsItem.class, JvmSmartCompletionTestGenerated.SmartCasts.class, JvmSmartCompletionTestGenerated.This.class, JvmSmartCompletionTestGenerated.WhenEntry.class})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionTest {
|
public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionTest {
|
||||||
@TestMetadata("AfterExclSign.kt")
|
@TestMetadata("AfterExclSign.kt")
|
||||||
@@ -736,6 +736,87 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/completion/smart/heuristicSignatures")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class HeuristicSignatures extends AbstractJvmSmartCompletionTest {
|
||||||
|
public void testAllFilesPresentInHeuristicSignatures() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/completion/smart/heuristicSignatures"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Contains.kt")
|
||||||
|
public void testContains() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/Contains.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ContainsAll.kt")
|
||||||
|
public void testContainsAll() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/ContainsAll.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ContainsKey.kt")
|
||||||
|
public void testContainsKey() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/ContainsKey.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ContainsValue.kt")
|
||||||
|
public void testContainsValue() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/ContainsValue.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Get.kt")
|
||||||
|
public void testGet() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/Get.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InOperator.kt")
|
||||||
|
public void testInOperator() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/InOperator.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("IndexOf.kt")
|
||||||
|
public void testIndexOf() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/IndexOf.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("LastIndexOf.kt")
|
||||||
|
public void testLastIndexOf() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/LastIndexOf.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MapRemove.kt")
|
||||||
|
public void testMapRemove() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/MapRemove.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Remove.kt")
|
||||||
|
public void testRemove() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/Remove.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RemoveAll.kt")
|
||||||
|
public void testRemoveAll() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/RemoveAll.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RetainAll.kt")
|
||||||
|
public void testRetainAll() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/heuristicSignatures/RetainAll.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/completion/smart/ifValue")
|
@TestMetadata("idea/testData/completion/smart/ifValue")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user