KT-9950 IntelliJ IDEA does not suggest importing extension methods which have the same name as an instance method
#KT-9950 Fixed
This commit is contained in:
+12
-1
@@ -34,9 +34,20 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull DataFlowInfo dataFlowInfo,
|
||||
@NotNull KotlinType expectedType
|
||||
) {
|
||||
return newContext(trace, scope, dataFlowInfo, expectedType, ContextDependency.INDEPENDENT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ExpressionTypingContext newContext(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull DataFlowInfo dataFlowInfo,
|
||||
@NotNull KotlinType expectedType,
|
||||
@NotNull ContextDependency contextDependency
|
||||
) {
|
||||
return newContext(trace, scope, dataFlowInfo, expectedType,
|
||||
ContextDependency.INDEPENDENT, new ResolutionResultsCacheImpl(),
|
||||
contextDependency, new ResolutionResultsCacheImpl(),
|
||||
StatementFilter.NONE, false);
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -30,8 +30,6 @@ import org.jetbrains.kotlin.resolve.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||
@@ -93,7 +91,7 @@ public class ExpressionTypingServices {
|
||||
@NotNull BindingTrace trace,
|
||||
boolean isStatement
|
||||
) {
|
||||
return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, isStatement, expression);
|
||||
return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, isStatement, expression, ContextDependency.INDEPENDENT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -104,10 +102,11 @@ public class ExpressionTypingServices {
|
||||
@NotNull DataFlowInfo dataFlowInfo,
|
||||
@NotNull BindingTrace trace,
|
||||
boolean isStatement,
|
||||
@NotNull final KtExpression contextExpression
|
||||
@NotNull final KtExpression contextExpression,
|
||||
@NotNull ContextDependency contextDependency
|
||||
) {
|
||||
ExpressionTypingContext context = ExpressionTypingContext.newContext(
|
||||
trace, scope, dataFlowInfo, expectedType
|
||||
trace, scope, dataFlowInfo, expectedType, contextDependency
|
||||
);
|
||||
if (contextExpression != expression) {
|
||||
context = context.replaceExpressionContextProvider(new Function1<KtExpression, KtExpression>() {
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -36,11 +37,12 @@ import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
|
||||
trace: BindingTrace = BindingTraceContext(),
|
||||
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
|
||||
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
|
||||
isStatement: Boolean = false
|
||||
isStatement: Boolean = false,
|
||||
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
|
||||
): KotlinTypeInfo {
|
||||
PreliminaryDeclarationVisitor.createForExpression(this, trace)
|
||||
return contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
|
||||
.getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression)
|
||||
.getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression, contextDependency)
|
||||
}
|
||||
|
||||
@JvmOverloads fun KtExpression.analyzeInContext(
|
||||
@@ -49,9 +51,10 @@ import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
|
||||
trace: BindingTrace = BindingTraceContext(),
|
||||
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
|
||||
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
|
||||
isStatement: Boolean = false
|
||||
isStatement: Boolean = false,
|
||||
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
|
||||
): BindingContext {
|
||||
computeTypeInfoInContext(scope, contextExpression, trace, dataFlowInfo, expectedType, isStatement)
|
||||
computeTypeInfoInContext(scope, contextExpression, trace, dataFlowInfo, expectedType, isStatement, contextDependency)
|
||||
return trace.bindingContext
|
||||
}
|
||||
|
||||
|
||||
@@ -25,18 +25,23 @@ import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.packageDependencies.DependencyValidationManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiErrorElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
|
||||
import org.jetbrains.kotlin.idea.actions.createGroupedImportsAction
|
||||
import org.jetbrains.kotlin.idea.actions.createSingleImportAction
|
||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
|
||||
@@ -46,12 +51,25 @@ import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil.getConventionName
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil.isSelectorInQualified
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.CachedValueProperty
|
||||
@@ -123,22 +141,18 @@ internal abstract class ImportFixBase<T : KtExpression>(expression: T) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>):
|
||||
Collection<DeclarationDescriptor> {
|
||||
private fun computeSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection<DeclarationDescriptor> {
|
||||
val nameStr = name.asString()
|
||||
if (nameStr.isEmpty()) return emptyList()
|
||||
|
||||
val file = element.containingFile as KtFile
|
||||
val file = element.getContainingKtFile()
|
||||
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
if (!checkErrorStillPresent(bindingContext)) return emptyList()
|
||||
|
||||
val searchScope = getResolveScope(file)
|
||||
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
val diagnostics = bindingContext.diagnostics.forElement(element)
|
||||
|
||||
if (!diagnostics.any { it.factory in getSupportedErrors() }) return emptyList()
|
||||
|
||||
val resolutionFacade = element.getResolutionFacade()
|
||||
val resolutionFacade = file.getResolutionFacade()
|
||||
|
||||
fun isVisible(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (descriptor is DeclarationDescriptorWithVisibility) {
|
||||
@@ -166,6 +180,14 @@ internal abstract class ImportFixBase<T : KtExpression>(expression: T) :
|
||||
result
|
||||
}
|
||||
|
||||
private fun checkErrorStillPresent(bindingContext: BindingContext): Boolean {
|
||||
return elementsToCheckDiagnostics()
|
||||
.flatMap { bindingContext.diagnostics.forElement(it) }
|
||||
.any { diagnostic -> diagnostic.factory in getSupportedErrors() }
|
||||
}
|
||||
|
||||
protected open fun elementsToCheckDiagnostics(): Collection<PsiElement> = listOf(element)
|
||||
|
||||
abstract fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
@@ -196,7 +218,7 @@ internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T) :
|
||||
val expression = element
|
||||
|
||||
if (expression is KtSimpleNameExpression) {
|
||||
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
||||
if (!expression.isImportDirectiveExpression() && !isSelectorInQualified(expression)) {
|
||||
val filterByCallType = { descriptor: DeclarationDescriptor -> callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor) }
|
||||
|
||||
if (ProjectStructureUtil.isJsKotlinModule(expression.getContainingKtFile())) {
|
||||
@@ -221,31 +243,7 @@ internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T) :
|
||||
internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFixBase<KtSimpleNameExpression>(expression) {
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
||||
|
||||
override val importNames: Collection<Name> = run {
|
||||
if (element.getIdentifier() == null) {
|
||||
val conventionName = KtPsiUtil.getConventionName(element)
|
||||
if (conventionName != null) {
|
||||
if (element is KtOperationReferenceExpression) {
|
||||
val elementType = element.firstChild.node.elementType
|
||||
if (elementType in OperatorConventions.ASSIGNMENT_OPERATIONS) {
|
||||
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[elementType]
|
||||
val counterpartName = OperatorConventions.BINARY_OPERATION_NAMES[counterpart]
|
||||
if (counterpartName != null) {
|
||||
return@run listOf(conventionName, counterpartName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@run conventionName.singletonOrEmptyList()
|
||||
}
|
||||
}
|
||||
else if (Name.isValidIdentifier(element.getReferencedName())) {
|
||||
return@run Name.identifier(element.getReferencedName()).singletonOrEmptyList()
|
||||
}
|
||||
|
||||
emptyList<Name>()
|
||||
}
|
||||
|
||||
override val importNames = element.extractImportNames()
|
||||
|
||||
override fun getSupportedErrors() = ERRORS
|
||||
|
||||
@@ -259,6 +257,31 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtSimpleNameExpression.extractImportNames(): Collection<Name> {
|
||||
if (getIdentifier() == null) {
|
||||
val conventionName = getConventionName(this)
|
||||
if (conventionName != null) {
|
||||
if (this is KtOperationReferenceExpression) {
|
||||
val elementType = firstChild.node.elementType
|
||||
if (elementType in OperatorConventions.ASSIGNMENT_OPERATIONS) {
|
||||
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[elementType]
|
||||
val counterpartName = OperatorConventions.BINARY_OPERATION_NAMES[counterpart]
|
||||
if (counterpartName != null) {
|
||||
return listOf(conventionName, counterpartName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conventionName.singletonOrEmptyList()
|
||||
}
|
||||
}
|
||||
else if (Name.isValidIdentifier(getReferencedName())) {
|
||||
return Name.identifier(getReferencedName()).singletonOrEmptyList()
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
|
||||
internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase<KtExpression>(expression) {
|
||||
override val importNames = OperatorNameConventions.INVOKE.singletonList()
|
||||
@@ -275,8 +298,12 @@ internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase
|
||||
}
|
||||
}
|
||||
|
||||
internal open class ArrayAccessorImportFix(element: KtArrayAccessExpression, override val importNames: Collection<Name>, private val showHint: Boolean) :
|
||||
OrdinaryImportFixBase<KtArrayAccessExpression>(element) {
|
||||
internal open class ArrayAccessorImportFix(
|
||||
element: KtArrayAccessExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val showHint: Boolean
|
||||
) : OrdinaryImportFixBase<KtArrayAccessExpression>(element) {
|
||||
|
||||
override fun getCallTypeAndReceiver() =
|
||||
CallTypeAndReceiver.OPERATOR(element.arrayExpression!!)
|
||||
|
||||
@@ -310,8 +337,11 @@ internal open class ArrayAccessorImportFix(element: KtArrayAccessExpression, ove
|
||||
}
|
||||
|
||||
internal class DelegateAccessorsImportFix(
|
||||
element: KtExpression, override val importNames: Collection<Name>, private val solveSeveralProblems: Boolean) :
|
||||
OrdinaryImportFixBase<KtExpression>(element) {
|
||||
element: KtExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val solveSeveralProblems: Boolean
|
||||
) : OrdinaryImportFixBase<KtExpression>(element) {
|
||||
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.DELEGATE(element)
|
||||
|
||||
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||
@@ -351,8 +381,12 @@ internal class DelegateAccessorsImportFix(
|
||||
}
|
||||
}
|
||||
|
||||
internal class ComponentsImportFix(element: KtExpression, override val importNames: Collection<Name>, private val solveSeveralProblems: Boolean) :
|
||||
OrdinaryImportFixBase<KtExpression>(element) {
|
||||
internal class ComponentsImportFix(
|
||||
element: KtExpression,
|
||||
override val importNames: Collection<Name>,
|
||||
private val solveSeveralProblems: Boolean
|
||||
) : OrdinaryImportFixBase<KtExpression>(element) {
|
||||
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.OPERATOR(element)
|
||||
|
||||
override fun createAction(project: Project, editor: Editor): KotlinAddImportAction {
|
||||
@@ -397,15 +431,14 @@ internal class ImportMemberFix(expression: KtSimpleNameExpression) : ImportFixBa
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
val result = ArrayList<DeclarationDescriptor>()
|
||||
val expression = element
|
||||
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
||||
if (!element.isImportDirectiveExpression() && !isSelectorInQualified(element)) {
|
||||
val filterByCallType = { descriptor: DeclarationDescriptor -> callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor) }
|
||||
|
||||
indicesHelper.getKotlinCallablesByName(name)
|
||||
.filter { it.canBeReferencedViaImport() && !isTopLevelDeclaration(it) }
|
||||
.filterTo(result, filterByCallType)
|
||||
|
||||
if (!ProjectStructureUtil.isJsKotlinModule(expression.getContainingKtFile())) {
|
||||
if (!ProjectStructureUtil.isJsKotlinModule(element.getContainingKtFile())) {
|
||||
indicesHelper.getJvmCallablesByName(name)
|
||||
.filter { it.canBeReferencedViaImport() }
|
||||
.filterTo(result, filterByCallType)
|
||||
@@ -436,7 +469,90 @@ internal class ImportMemberFix(expression: KtSimpleNameExpression) : ImportFixBa
|
||||
|
||||
private val ERRORS: Collection<DiagnosticFactory<*>> by lazy { QuickFixes.getInstance().getDiagnostics(this) }
|
||||
}
|
||||
}
|
||||
|
||||
internal class ImportForMismatchingArgumentsFix(expression: KtSimpleNameExpression) : ImportFixBase<KtSimpleNameExpression>(expression) {
|
||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
||||
|
||||
override val importNames = element.extractImportNames()
|
||||
|
||||
override fun getSupportedErrors() = ERRORS
|
||||
|
||||
override fun elementsToCheckDiagnostics(): Collection<PsiElement> {
|
||||
val callExpression = element.parent as? KtCallExpression ?: return emptyList()
|
||||
return callExpression.valueArguments +
|
||||
callExpression.valueArguments.mapNotNull { it.getArgumentExpression() } +
|
||||
callExpression.valueArguments.mapNotNull { it.getArgumentName()?.referenceExpression } +
|
||||
callExpression.valueArgumentList.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
override fun fillCandidates(
|
||||
name: String,
|
||||
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||
bindingContext: BindingContext,
|
||||
indicesHelper: KotlinIndicesHelper
|
||||
): List<DeclarationDescriptor> {
|
||||
if (!Name.isValidIdentifier(name)) return emptyList()
|
||||
val identifier = Name.identifier(name)
|
||||
|
||||
val call = element.getParentCall(bindingContext) ?: return emptyList()
|
||||
val callElement = call.callElement as? KtExpression ?: return emptyList()
|
||||
if (callElement.anyDescendantOfType<PsiErrorElement>()) return emptyList() // incomplete call
|
||||
val elementToAnalyze = callElement.getQualifiedExpressionForSelectorOrThis()
|
||||
|
||||
val file = element.getContainingKtFile()
|
||||
val resolutionFacade = file.getResolutionFacade()
|
||||
val resolutionScope = elementToAnalyze.getResolutionScope(bindingContext, resolutionFacade)
|
||||
|
||||
fun filterFunction(descriptor: FunctionDescriptor): Boolean {
|
||||
if (!callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor)) return false
|
||||
|
||||
if (descriptor in resolutionScope.collectFunctions(identifier, NoLookupLocation.FROM_IDE)) return false // already imported
|
||||
|
||||
// check that this function matches all arguments
|
||||
val resolutionScopeWithAddedImport = resolutionScope.addImportingScope(ExplicitImportsScope(listOf(descriptor)))
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(elementToAnalyze)
|
||||
val newBindingContext = elementToAnalyze.analyzeInContext(
|
||||
resolutionScopeWithAddedImport,
|
||||
dataFlowInfo = dataFlowInfo,
|
||||
contextDependency = ContextDependency.DEPENDENT // to not check complete inference
|
||||
)
|
||||
return newBindingContext.diagnostics.none { it.severity == Severity.ERROR }
|
||||
}
|
||||
|
||||
val result = ArrayList<FunctionDescriptor>()
|
||||
|
||||
fun processDescriptor(descriptor: CallableDescriptor) {
|
||||
if (descriptor is FunctionDescriptor && filterFunction(descriptor)) {
|
||||
result.add(descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
indicesHelper
|
||||
.getCallableTopLevelExtensions(callTypeAndReceiver, element, bindingContext) { it == name }
|
||||
.forEach(::processDescriptor)
|
||||
|
||||
if (!isSelectorInQualified(element)) {
|
||||
indicesHelper
|
||||
.getTopLevelCallablesByName(name)
|
||||
.forEach(::processDescriptor)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): ImportForMismatchingArgumentsFix? {
|
||||
//TODO: not only KtCallExpression
|
||||
val callExpression = diagnostic.psiElement.getStrictParentOfType<KtCallExpression>() ?: return null
|
||||
val nameExpression = callExpression.calleeExpression as? KtNameReferenceExpression ?: return null
|
||||
return ImportForMismatchingArgumentsFix(nameExpression)
|
||||
}
|
||||
|
||||
override fun isApplicableForCodeFragment() = true
|
||||
|
||||
private val ERRORS: Collection<DiagnosticFactory<*>> by lazy { QuickFixes.getInstance().getDiagnostics(this) }
|
||||
}
|
||||
}
|
||||
|
||||
object ImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory() {
|
||||
|
||||
@@ -134,6 +134,12 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
UNRESOLVED_REFERENCE.registerFactory(ImportMemberFix)
|
||||
UNRESOLVED_REFERENCE.registerFactory(ImportFix)
|
||||
|
||||
TOO_MANY_ARGUMENTS.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
TYPE_MISMATCH.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
NAMED_PARAMETER_NOT_FOUND.registerFactory(ImportForMismatchingArgumentsFix)
|
||||
|
||||
UNRESOLVED_REFERENCE.registerFactory(AddTestLibQuickFix)
|
||||
|
||||
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(ImportFix)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "false"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
// ACTION: Add parameter to function 'foo'
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Create extension function 'X.foo'
|
||||
// ACTION: Create member function 'X.foo'
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
this.foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: String) {
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: The integer literal does not conform to the expected type String
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo(p: String) {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: Int) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: The integer literal does not conform to the expected type String
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo(p: String) {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: No value passed for parameter p
|
||||
// ERROR: Type mismatch: inferred type is Unit but String was expected
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo(p: Int) {
|
||||
}
|
||||
|
||||
fun f(): String {
|
||||
return foo(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun <T> X.foo(): T = TODO()
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: No value passed for parameter p
|
||||
// ERROR: Type mismatch: inferred type is Unit but String was expected
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo(p: Int) {
|
||||
}
|
||||
|
||||
fun f(): String {
|
||||
return foo(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
}
|
||||
|
||||
fun f(x: X) {
|
||||
x.foo(<caret>1)
|
||||
}
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: Int) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
}
|
||||
|
||||
fun f(x: X) {
|
||||
x.foo(<caret>1)
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: Int) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "false"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
// ACTION: Add parameter to function 'foo'
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Create extension function 'X.foo'
|
||||
// ACTION: Create member function 'X.foo'
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
}
|
||||
|
||||
fun f(x: X) {
|
||||
x.foo(<caret>1)
|
||||
}
|
||||
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun String.foo(p: Int) {
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
// ERROR: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: <br>public operator fun String?.plus(other: Any?): String defined in kotlin
|
||||
// ERROR: Unresolved reference: XXX
|
||||
// ERROR: Unresolved reference: xxx
|
||||
|
||||
package main
|
||||
|
||||
class X : XXX {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1) + xxx()
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: Int) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
// ERROR: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: <br>public operator fun String?.plus(other: Any?): String defined in kotlin
|
||||
// ERROR: Unresolved reference: XXX
|
||||
// ERROR: Unresolved reference: xxx
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X : XXX {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1) + xxx()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Type mismatch: inferred type is () -> Unit but Int was expected
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo(p: Int) {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo {<caret>}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(filter: (String) -> Boolean){}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Type mismatch: inferred type is () -> Unit but Int was expected
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo(p: Int) {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo {<caret>}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Cannot find a parameter with this name: p2
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f(p: Int) {
|
||||
foo(<caret>p2 = 0)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p1: Int = 1, p2: Int = 2, p3: Int = 3){}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Cannot find a parameter with this name: p2
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f(p: Int) {
|
||||
foo(<caret>p2 = 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "false"
|
||||
// ERROR: Type mismatch: inferred type is Int but String was expected
|
||||
// ACTION: Add 'toString()' call
|
||||
// ACTION: Change parameter 'p' type of function 'main.X.foo' to 'Int'
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Create function 'foo'
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo(p: String) {
|
||||
}
|
||||
|
||||
fun f(p: Int) {
|
||||
foo(<caret>p, )
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: Int) {
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f(p: Any) {
|
||||
if (p is String) {
|
||||
foo(<caret>p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: String) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f(p: Any) {
|
||||
if (p is String) {
|
||||
foo(<caret>p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
fun foo(p: Int) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "false"
|
||||
// ERROR: Too many arguments for public final fun foo(): Unit defined in main.X
|
||||
// ACTION: Add parameter to function 'foo'
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Create extension function 'X.foo'
|
||||
// ACTION: Create member function 'X.foo'
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo() {
|
||||
}
|
||||
|
||||
fun f() {
|
||||
this.foo(<caret>1)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
fun foo(p: Int) {
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// FILE: first.before.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Type mismatch: inferred type is Int but String was expected
|
||||
|
||||
package main
|
||||
|
||||
class X {
|
||||
fun foo(p: String) {
|
||||
}
|
||||
|
||||
fun f(p: Int) {
|
||||
foo(<caret>p)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
package other
|
||||
|
||||
import main.X
|
||||
|
||||
fun X.foo(p: Int) {
|
||||
}
|
||||
|
||||
// FILE: first.after.kt
|
||||
// "Import" "true"
|
||||
// ERROR: Type mismatch: inferred type is Int but String was expected
|
||||
|
||||
package main
|
||||
|
||||
import other.foo
|
||||
|
||||
class X {
|
||||
fun foo(p: String) {
|
||||
}
|
||||
|
||||
fun f(p: Int) {
|
||||
foo(<caret>p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,6 +580,99 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/withSmartCastQualifier.before.Main.kt");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/autoImports/mismatchingArgs")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class MismatchingArgs extends AbstractQuickFixMultiFileTest {
|
||||
public void testAllFilesPresentInMismatchingArgs() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/autoImports/mismatchingArgs"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("checkArgumentTypes.test")
|
||||
public void testCheckArgumentTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/checkArgumentTypes.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("constantExpectedTypeMismatch.test")
|
||||
public void testConstantExpectedTypeMismatch() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/constantExpectedTypeMismatch.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expectedTypeRequired.test")
|
||||
public void testExpectedTypeRequired() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/expectedTypeRequired.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionExplicitReceiver.test")
|
||||
public void testExtensionExplicitReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/extensionExplicitReceiver.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionImplicitReceiver.test")
|
||||
public void testExtensionImplicitReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/extensionImplicitReceiver.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionWrongReceiver.test")
|
||||
public void testExtensionWrongReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/extensionWrongReceiver.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ignoreErrorsOutsideCall.test")
|
||||
public void testIgnoreErrorsOutsideCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/ignoreErrorsOutsideCall.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaArgument.test")
|
||||
public void testLambdaArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/lambdaArgument.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("namedArgument.test")
|
||||
public void testNamedArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/namedArgument.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("notForIncompleteCall.test")
|
||||
public void testNotForIncompleteCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/notForIncompleteCall.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("smartCast.test")
|
||||
public void testSmartCast() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/smartCast.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFun.test")
|
||||
public void testTopLevelFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/topLevelFun.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFun_notWithReceiver.test")
|
||||
public void testTopLevelFun_notWithReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/topLevelFun_notWithReceiver.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatch.test")
|
||||
public void testTypeMismatch() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/mismatchingArgs/typeMismatch.test");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/changeSignature")
|
||||
|
||||
@@ -771,6 +771,7 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/unresolvedReferenceInCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/canBeParameter")
|
||||
|
||||
Reference in New Issue
Block a user