Create From Usage: Do not keep semantic information in quickfix instances directly as it leads to memory leaks
This commit is contained in:
@@ -288,3 +288,5 @@ public fun PsiElement.getTextWithLocation(): String = "'${this.getText()}' at ${
|
||||
|
||||
public fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element)
|
||||
|
||||
public fun <E: PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> =
|
||||
SmartPointerManager.getInstance(getProject()).createSmartPsiElementPointer(this)
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
public object NullQuickFix : IntentionAction {
|
||||
override fun getText() = ""
|
||||
|
||||
override fun getFamilyName() = ""
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) = false
|
||||
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun invoke(NotNull project: Project, editor: Editor?, file: PsiFile?) {
|
||||
throw UnsupportedOperationException("invoke() shouldn't be called")
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClas
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromReferenceExpressionActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateLocalVariableActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory
|
||||
import org.jetbrains.kotlin.lexer.JetTokens.*
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
@@ -250,11 +250,11 @@ public class QuickFixRegistrar : QuickFixContributor {
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(CreateBinaryOperationActionFactory)
|
||||
TOO_MANY_ARGUMENTS.registerFactory(CreateBinaryOperationActionFactory)
|
||||
|
||||
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(CreateCallableFromCallActionFactory)
|
||||
UNRESOLVED_REFERENCE.registerFactory(CreateCallableFromCallActionFactory)
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(CreateCallableFromCallActionFactory)
|
||||
TOO_MANY_ARGUMENTS.registerFactory(CreateCallableFromCallActionFactory)
|
||||
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateCallableFromCallActionFactory)
|
||||
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
UNRESOLVED_REFERENCE.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
TOO_MANY_ARGUMENTS.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(CreateConstructorFromDelegationCallActionFactory)
|
||||
TOO_MANY_ARGUMENTS.registerFactory(CreateConstructorFromDelegationCallActionFactory)
|
||||
@@ -269,9 +269,9 @@ public class QuickFixRegistrar : QuickFixContributor {
|
||||
UNRESOLVED_REFERENCE.registerFactory(CreateLocalVariableActionFactory)
|
||||
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateLocalVariableActionFactory)
|
||||
|
||||
UNRESOLVED_REFERENCE.registerFactory(CreateParameterActionFactory)
|
||||
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(CreateParameterActionFactory)
|
||||
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateParameterActionFactory)
|
||||
UNRESOLVED_REFERENCE.registerFactory(CreateParameterByRefActionFactory)
|
||||
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(CreateParameterByRefActionFactory)
|
||||
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(CreateParameterByRefActionFactory)
|
||||
|
||||
NAMED_PARAMETER_NOT_FOUND.registerFactory(CreateParameterByNamedArgumentActionFactory)
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
public class QuickFixWithDelegateFactory(
|
||||
private val delegateFactory: () -> IntentionAction
|
||||
) : IntentionAction {
|
||||
private val familyName: String
|
||||
private val text: String
|
||||
private val startInWriteAction: Boolean
|
||||
|
||||
init {
|
||||
val delegate = delegateFactory()
|
||||
familyName = delegate.familyName
|
||||
text = delegate.text
|
||||
startInWriteAction = delegate.startInWriteAction()
|
||||
}
|
||||
|
||||
override fun getFamilyName() = familyName
|
||||
|
||||
override fun getText() = text
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) =
|
||||
delegateFactory().isAvailable(project, editor, file)
|
||||
|
||||
override fun startInWriteAction() = startInWriteAction
|
||||
|
||||
override fun invoke(NotNull project: Project, editor: Editor?, file: PsiFile?) {
|
||||
delegateFactory().invoke(project, editor, file)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
|
||||
public abstract class CreateFromUsageFactory<E : JetElement, D> : JetIntentionActionsFactory() {
|
||||
protected abstract fun getElementOfInterest(diagnostic: Diagnostic): E?
|
||||
|
||||
protected open fun createQuickFix(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
diagnostic: Diagnostic,
|
||||
quickFixDataFactory: (SmartPsiElementPointer<E>) -> D
|
||||
): QuickFixWithDelegateFactory? = null
|
||||
|
||||
protected open fun createQuickFixes(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
diagnostic: Diagnostic,
|
||||
quickFixDataFactory: (SmartPsiElementPointer<E>) -> D
|
||||
): List<QuickFixWithDelegateFactory> = createQuickFix(originalElementPointer, diagnostic, quickFixDataFactory).singletonOrEmptyList()
|
||||
|
||||
protected abstract fun createQuickFixData(element: E, diagnostic: Diagnostic): D
|
||||
|
||||
override final fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val diagnosticMessage = DefaultErrorMessages.render(diagnostic)
|
||||
val diagnosticElementPointer = diagnostic.psiElement.createSmartPointer()
|
||||
val originalElement = getElementOfInterest(diagnostic) ?: return null
|
||||
val originalElementPointer = originalElement.createSmartPointer()
|
||||
|
||||
val file = originalElement.containingFile
|
||||
val project = file.project
|
||||
|
||||
// Cache data so that it can be shared between quick fixes bound to the same element & diagnostic
|
||||
// Cache null values
|
||||
var cachedData: Ref<D>? = null
|
||||
val actions: List<QuickFixWithDelegateFactory>
|
||||
try {
|
||||
actions = createQuickFixes(originalElementPointer, diagnostic) factory@ {
|
||||
val element = it.element ?: return@factory null
|
||||
val diagnosticElement = diagnosticElementPointer.element ?: return@factory null
|
||||
if (!diagnosticElement.isValid || !element.isValid) return@factory null
|
||||
|
||||
val currentDiagnostic =
|
||||
element.analyze(BodyResolveMode.PARTIAL)
|
||||
.diagnostics
|
||||
.forElement(diagnosticElement)
|
||||
.firstOrNull { DefaultErrorMessages.render(it) == diagnosticMessage } ?: return@factory null
|
||||
if (cachedData == null) {
|
||||
cachedData = Ref(createQuickFixData(element, currentDiagnostic))
|
||||
}
|
||||
cachedData!!.get()
|
||||
}.filter { it.isAvailable(project, null, file) }
|
||||
}
|
||||
finally {
|
||||
cachedData = null // Do not keep cache after all actions are initialized
|
||||
}
|
||||
|
||||
return actions
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -16,10 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
|
||||
public abstract class CreateFromUsageFixBase(element: PsiElement) : JetIntentionAction<PsiElement>(element) {
|
||||
public abstract class CreateFromUsageFixBase<T: JetElement>(element: T) : JetIntentionAction<T>(element) {
|
||||
override fun getFamilyName(): String = JetBundle.message("create.from.usage.family")
|
||||
}
|
||||
|
||||
+10
@@ -234,6 +234,16 @@ fun JetCallElement.getTypeInfoForTypeArguments(): List<TypeInfo> {
|
||||
return getTypeArguments().map { it.getTypeReference()?.let { TypeInfo(it, Variance.INVARIANT) } }.filterNotNull()
|
||||
}
|
||||
|
||||
fun JetCallExpression.getParameterInfos(): List<ParameterInfo> {
|
||||
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
|
||||
return valueArguments.map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
it.getArgumentName()?.getReferenceExpression()?.getReferencedName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypePredicate.getRepresentativeTypes(): Set<JetType> {
|
||||
return when (this) {
|
||||
is SingleType -> Collections.singleton(targetType)
|
||||
|
||||
+23
-23
@@ -16,44 +16,44 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetBinaryExpression
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.lexer.JetToken
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.lexer.JetToken
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.JetBinaryExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.Collections
|
||||
|
||||
public object CreateBinaryOperationActionFactory: JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val callExpr = diagnostic.getPsiElement().getParent() as? JetBinaryExpression ?: return null
|
||||
val token = callExpr.getOperationToken() as JetToken
|
||||
public object CreateBinaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetBinaryExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetBinaryExpression? {
|
||||
return diagnostic.psiElement.parent as? JetBinaryExpression
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetBinaryExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val token = element.operationToken as JetToken
|
||||
val operationName = when (token) {
|
||||
JetTokens.IDENTIFIER -> callExpr.getOperationReference().getReferencedName()
|
||||
else -> OperatorConventions.getNameForOperationSymbol(token)?.asString()
|
||||
} ?: return null
|
||||
JetTokens.IDENTIFIER -> element.operationReference.getReferencedName()
|
||||
else -> OperatorConventions.getNameForOperationSymbol(token)?.asString()
|
||||
} ?: return null
|
||||
val inOperation = token in OperatorConventions.IN_OPERATIONS
|
||||
val comparisonOperation = token in OperatorConventions.COMPARISON_OPERATIONS
|
||||
|
||||
val leftExpr = callExpr.getLeft() ?: return null
|
||||
val rightExpr = callExpr.getRight() ?: return null
|
||||
val leftExpr = element.left ?: return null
|
||||
val rightExpr = element.right ?: return null
|
||||
|
||||
val receiverExpr = if (inOperation) rightExpr else leftExpr
|
||||
val argumentExpr = if (inOperation) leftExpr else rightExpr
|
||||
|
||||
val builtIns = KotlinBuiltIns.getInstance()
|
||||
|
||||
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
|
||||
val returnType = when {
|
||||
inOperation -> TypeInfo.ByType(builtIns.getBooleanType(), Variance.INVARIANT).noSubstitutions()
|
||||
comparisonOperation -> TypeInfo.ByType(builtIns.getIntType(), Variance.INVARIANT).noSubstitutions()
|
||||
else -> TypeInfo(callExpr, Variance.OUT_VARIANCE)
|
||||
inOperation -> TypeInfo.ByType(builtIns.booleanType, Variance.INVARIANT).noSubstitutions()
|
||||
comparisonOperation -> TypeInfo.ByType(builtIns.intType, Variance.INVARIANT).noSubstitutions()
|
||||
else -> TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
}
|
||||
val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_VARIANCE)))
|
||||
return CreateCallableFromUsageFixes(callExpr, FunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters))
|
||||
return FunctionInfo(operationName, receiverType, returnType, Collections.emptyList(), parameters)
|
||||
}
|
||||
}
|
||||
|
||||
+128
-87
@@ -16,124 +16,91 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.getExtractionContainers
|
||||
import org.jetbrains.kotlin.idea.refactoring.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
object CreateCallableFromCallActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val diagElement = diagnostic.getPsiElement()
|
||||
sealed class CreateCallableFromCallActionFactory<E : JetExpression>(
|
||||
extensionsEnabled: Boolean = true
|
||||
) : CreateCallableMemberFromUsageFactory<E>(extensionsEnabled) {
|
||||
protected abstract fun doCreateCallableInfo(
|
||||
expression: E,
|
||||
context: BindingContext,
|
||||
name: String,
|
||||
receiverType: TypeInfo,
|
||||
possibleContainers: List<JetElement>
|
||||
): CallableInfo?
|
||||
|
||||
protected fun getExpressionOfInterest(diagnostic: Diagnostic): JetExpression? {
|
||||
val diagElement = diagnostic.psiElement
|
||||
if (PsiTreeUtil.getParentOfType(
|
||||
diagElement,
|
||||
javaClass<JetTypeReference>(), javaClass<JetAnnotationEntry>(), javaClass<JetImportDirective>()
|
||||
) != null) return null
|
||||
|
||||
val callExpr = when (diagnostic.getFactory()) {
|
||||
in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS, Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND -> {
|
||||
val parent = diagElement.getParent()
|
||||
if (parent is JetCallExpression && parent.getCalleeExpression() == diagElement) parent else diagElement
|
||||
}
|
||||
return when (diagnostic.factory) {
|
||||
in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS, Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND -> {
|
||||
val parent = diagElement.parent
|
||||
if (parent is JetCallExpression && parent.calleeExpression == diagElement) parent else diagElement
|
||||
}
|
||||
|
||||
Errors.NO_VALUE_FOR_PARAMETER,
|
||||
Errors.TOO_MANY_ARGUMENTS -> diagElement.getNonStrictParentOfType<JetCallExpression>()
|
||||
Errors.NO_VALUE_FOR_PARAMETER,
|
||||
Errors.TOO_MANY_ARGUMENTS -> diagElement.getNonStrictParentOfType<JetCallExpression>()
|
||||
|
||||
else -> throw AssertionError("Unexpected diagnostic: ${diagnostic.getFactory()}")
|
||||
} as? JetExpression ?: return null
|
||||
else -> throw AssertionError("Unexpected diagnostic: ${diagnostic.factory}")
|
||||
} as? JetExpression
|
||||
}
|
||||
|
||||
val project = callExpr.getProject()
|
||||
override fun createCallableInfo(element: E, diagnostic: Diagnostic): CallableInfo? {
|
||||
val project = element.project
|
||||
|
||||
val calleeExpr = when (callExpr) {
|
||||
is JetCallExpression -> callExpr.getCalleeExpression()
|
||||
is JetSimpleNameExpression -> callExpr
|
||||
val calleeExpr = when (element) {
|
||||
is JetCallExpression -> element.calleeExpression
|
||||
is JetSimpleNameExpression -> element
|
||||
else -> null
|
||||
} as? JetSimpleNameExpression ?: return null
|
||||
|
||||
if (calleeExpr.getReferencedNameElementType() != JetTokens.IDENTIFIER) return null
|
||||
|
||||
val callParent = callExpr.getParent()
|
||||
val fullCallExpr =
|
||||
if (callParent is JetQualifiedExpression && callParent.getSelectorExpression() == callExpr) callParent else callExpr
|
||||
|
||||
val context = calleeExpr.analyze()
|
||||
val receiver = callExpr.getCall(context)?.getExplicitReceiver() ?: ReceiverValue.NO_RECEIVER
|
||||
val receiver = element.getCall(context)?.explicitReceiver ?: ReceiverValue.NO_RECEIVER
|
||||
val receiverType = getReceiverTypeInfo(context, project, receiver) ?: return null
|
||||
|
||||
val possibleContainers =
|
||||
if (receiverType is TypeInfo.Empty) {
|
||||
val containers = with(fullCallExpr.getExtractionContainers()) {
|
||||
if (callExpr is JetCallExpression) this else filter { it is JetClassBody || it is JetFile }
|
||||
val containers = with(element.getQualifiedExpressionForSelectorOrThis().getExtractionContainers()) {
|
||||
if (element is JetCallExpression) this else filter { it is JetClassBody || it is JetFile }
|
||||
}
|
||||
if (containers.isNotEmpty()) containers else return null
|
||||
}
|
||||
else Collections.emptyList()
|
||||
|
||||
val name = calleeExpr.getReferencedName()
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
|
||||
val callableInfos = ArrayList<CallableInfo>(2)
|
||||
when (callExpr) {
|
||||
is JetCallExpression -> {
|
||||
val parameters = callExpr.getValueArguments().map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
it.getArgumentName()?.getReferenceExpression()?.getReferencedName()
|
||||
)
|
||||
}
|
||||
val typeParameters = callExpr.getTypeInfoForTypeArguments()
|
||||
val returnType = TypeInfo(fullCallExpr, Variance.OUT_VARIANCE)
|
||||
callableInfos.add(FunctionInfo(name, receiverType, returnType, possibleContainers, parameters, typeParameters))
|
||||
|
||||
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, fullCallExpr] ?: anyType
|
||||
val constructorDescriptor = callExpr.getResolvedCall(context)?.getResultingDescriptor() as? ConstructorDescriptor
|
||||
val classDescriptor = constructorDescriptor?.getContainingDeclaration() as? ClassDescriptor
|
||||
val klass = classDescriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
||||
if ((klass is JetClass || klass is PsiClass) && klass.canRefactor()
|
||||
&& typeParameters.isEmpty()
|
||||
&& classDescriptor!!.getDefaultType().isSubtypeOf(expectedType)) {
|
||||
callableInfos.add(SecondaryConstructorInfo(parameters, klass))
|
||||
}
|
||||
}
|
||||
|
||||
is JetSimpleNameExpression -> {
|
||||
val varExpected = fullCallExpr.getAssignmentByLHS() != null
|
||||
val returnType = TypeInfo(
|
||||
fullCallExpr.getExpressionForTypeGuess(),
|
||||
if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE
|
||||
)
|
||||
callableInfos.add(PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers))
|
||||
}
|
||||
}
|
||||
|
||||
return callableInfos.flatMap{ CreateCallableFromUsageFixes(callExpr, it) }
|
||||
return doCreateCallableInfo(element, context, calleeExpr.getReferencedName(), receiverType, possibleContainers)
|
||||
}
|
||||
|
||||
private fun getReceiverTypeInfo(context: BindingContext, project: Project, receiver: ReceiverValue): TypeInfo? {
|
||||
@@ -146,9 +113,83 @@ object CreateCallableFromCallActionFactory : JetIntentionActionsFactory() {
|
||||
val classifier = receiver.classifier as? JavaClassDescriptor ?: return null
|
||||
val javaClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classifier) as? PsiClass
|
||||
if (javaClass == null || !javaClass.canRefactor()) return null
|
||||
TypeInfo.StaticContextRequired(TypeInfo(classifier.getDefaultType(), Variance.IN_VARIANCE))
|
||||
TypeInfo.StaticContextRequired(TypeInfo(classifier.defaultType, Variance.IN_VARIANCE))
|
||||
}
|
||||
else -> TypeInfo(receiver.getType(), Variance.IN_VARIANCE)
|
||||
else -> TypeInfo(receiver.type, Variance.IN_VARIANCE)
|
||||
}
|
||||
}
|
||||
|
||||
object Property: CreateCallableFromCallActionFactory<JetSimpleNameExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetSimpleNameExpression? {
|
||||
return getExpressionOfInterest(diagnostic) as? JetSimpleNameExpression
|
||||
}
|
||||
|
||||
override fun doCreateCallableInfo(
|
||||
expression: JetSimpleNameExpression,
|
||||
context: BindingContext,
|
||||
name: String,
|
||||
receiverType: TypeInfo,
|
||||
possibleContainers: List<JetElement>
|
||||
): CallableInfo? {
|
||||
val fullCallExpr = expression.getQualifiedExpressionForSelectorOrThis()
|
||||
val varExpected = fullCallExpr.getAssignmentByLHS() != null
|
||||
val returnType = TypeInfo(
|
||||
fullCallExpr.getExpressionForTypeGuess(),
|
||||
if (varExpected) Variance.INVARIANT else Variance.OUT_VARIANCE
|
||||
)
|
||||
return PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers)
|
||||
}
|
||||
}
|
||||
|
||||
object Function: CreateCallableFromCallActionFactory<JetCallExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
|
||||
return getExpressionOfInterest(diagnostic) as? JetCallExpression
|
||||
}
|
||||
|
||||
override fun doCreateCallableInfo(
|
||||
expression: JetCallExpression,
|
||||
context: BindingContext,
|
||||
name: String,
|
||||
receiverType: TypeInfo,
|
||||
possibleContainers: List<JetElement>
|
||||
): CallableInfo? {
|
||||
val parameters = expression.getParameterInfos()
|
||||
val typeParameters = expression.getTypeInfoForTypeArguments()
|
||||
val returnType = TypeInfo(expression.getQualifiedExpressionForSelectorOrThis(), Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(name, receiverType, returnType, possibleContainers, parameters, typeParameters)
|
||||
}
|
||||
}
|
||||
|
||||
object Constructor: CreateCallableFromCallActionFactory<JetCallExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
|
||||
return getExpressionOfInterest(diagnostic) as? JetCallExpression
|
||||
}
|
||||
|
||||
override fun doCreateCallableInfo(
|
||||
expression: JetCallExpression,
|
||||
context: BindingContext,
|
||||
name: String,
|
||||
receiverType: TypeInfo,
|
||||
possibleContainers: List<JetElement>
|
||||
): CallableInfo? {
|
||||
if (expression.typeArguments.isNotEmpty()) return null
|
||||
|
||||
val constructorDescriptor = expression.getResolvedCall(context)?.resultingDescriptor as? ConstructorDescriptor
|
||||
val classDescriptor = constructorDescriptor?.containingDeclaration as? ClassDescriptor
|
||||
val klass = classDescriptor?.source?.getPsi()
|
||||
if ((klass !is JetClass && klass !is PsiClass) || !klass.canRefactor()) return null
|
||||
|
||||
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, expression.getQualifiedExpressionForSelectorOrThis()]
|
||||
?: KotlinBuiltIns.getInstance().nullableAnyType
|
||||
if (!classDescriptor!!.defaultType.isSubtypeOf(expectedType)) return null
|
||||
|
||||
val parameters = expression.getParameterInfos()
|
||||
|
||||
return SecondaryConstructorInfo(parameters, klass)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val INSTANCES = arrayOf(Function, Constructor, Property)
|
||||
}
|
||||
}
|
||||
|
||||
+27
-42
@@ -21,35 +21,37 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.chooseContainerElementIfNecessary
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.JetClassBody
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import java.util.Collections
|
||||
import java.util.HashSet
|
||||
|
||||
public class CreateCallableFromUsageFix(originalElement: JetElement, callableInfos: List<CallableInfo>)
|
||||
: CreateCallableFromUsageFixBase(originalElement, callableInfos, false) {
|
||||
constructor(originalExpression: JetElement, callableInfo: CallableInfo) : this(originalExpression, Collections.singletonList(callableInfo))
|
||||
}
|
||||
public class CreateCallableFromUsageFix<E : JetElement>(
|
||||
originalExpression: E,
|
||||
callableInfos: List<CallableInfo>
|
||||
) : CreateCallableFromUsageFixBase<E>(originalExpression, callableInfos, false)
|
||||
|
||||
public class CreateExtensionCallableFromUsageFix(originalElement: JetElement, callableInfos: List<CallableInfo>)
|
||||
: CreateCallableFromUsageFixBase(originalElement, callableInfos, true), LowPriorityAction {
|
||||
constructor(originalExpression: JetElement, callableInfo: CallableInfo) : this(originalExpression, Collections.singletonList(callableInfo))
|
||||
}
|
||||
public class CreateExtensionCallableFromUsageFix<E : JetElement>(
|
||||
originalExpression: E,
|
||||
callableInfos: List<CallableInfo>
|
||||
) : CreateCallableFromUsageFixBase<E>(originalExpression, callableInfos, true), LowPriorityAction
|
||||
|
||||
public abstract class CreateCallableFromUsageFixBase(
|
||||
originalElement: JetElement,
|
||||
public abstract class CreateCallableFromUsageFixBase<E : JetElement>(
|
||||
originalExpression: E,
|
||||
val callableInfos: List<CallableInfo>,
|
||||
val isExtension: Boolean
|
||||
) : CreateFromUsageFixBase(originalElement) {
|
||||
|
||||
) : CreateFromUsageFixBase<E>(originalExpression) {
|
||||
init {
|
||||
assert (callableInfos.isNotEmpty()) { "No CallableInfos: ${originalElement.getElementTextWithContext()}" }
|
||||
assert (callableInfos.isNotEmpty()) { "No CallableInfos: ${originalExpression.getElementTextWithContext()}" }
|
||||
if (callableInfos.size() > 1) {
|
||||
val receiverSet = callableInfos.mapTo(HashSet<TypeInfo>()) { it.receiverTypeInfo }
|
||||
if (receiverSet.size() > 1) throw AssertionError("All functions must have common receiver: $receiverSet")
|
||||
@@ -60,7 +62,7 @@ public abstract class CreateCallableFromUsageFixBase(
|
||||
}
|
||||
|
||||
private fun getDeclarationIfApplicable(project: Project, candidate: TypeCandidate): PsiElement? {
|
||||
val descriptor = candidate.theType.getConstructor().getDeclarationDescriptor() ?: return null
|
||||
val descriptor = candidate.theType.constructor.declarationDescriptor ?: return null
|
||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
|
||||
if (declaration !is JetClassOrObject && declaration !is PsiClass) return null
|
||||
return if (isExtension || declaration.canRefactor()) declaration else null
|
||||
@@ -92,23 +94,23 @@ public abstract class CreateCallableFromUsageFixBase(
|
||||
}.toString()
|
||||
}
|
||||
|
||||
fun isAvailable(): Boolean {
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
if (!super.isAvailable(project, editor, file)) return false
|
||||
if (file !is JetFile) return false
|
||||
|
||||
val receiverInfo = callableInfos.first().receiverTypeInfo
|
||||
|
||||
if (receiverInfo is TypeInfo.Empty) return !isExtension
|
||||
// TODO: Remove after companion object extensions are supported
|
||||
if (isExtension && receiverInfo.staticContextRequired) return false
|
||||
|
||||
val file = element.getContainingFile() as JetFile
|
||||
val project = file.getProject()
|
||||
val callableBuilder =
|
||||
CallableBuilderConfiguration(callableInfos, element as JetExpression, file, null, isExtension).createBuilder()
|
||||
val callableBuilder = CallableBuilderConfiguration(callableInfos, element, file, null, isExtension).createBuilder()
|
||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfos.first().receiverTypeInfo)
|
||||
val propertyInfo = callableInfos.firstOrNull { it is PropertyInfo } as PropertyInfo?
|
||||
val isFunction = callableInfos.any { it.kind == CallableKind.FUNCTION }
|
||||
return receiverTypeCandidates.any {
|
||||
val declaration = getDeclarationIfApplicable(project, it)
|
||||
val insertToJavaInterface = declaration is PsiClass && declaration.isInterface()
|
||||
val insertToJavaInterface = declaration is PsiClass && declaration.isInterface
|
||||
when {
|
||||
propertyInfo != null && insertToJavaInterface && (!receiverInfo.staticContextRequired || propertyInfo.writable) ->
|
||||
false
|
||||
@@ -128,7 +130,7 @@ public abstract class CreateCallableFromUsageFixBase(
|
||||
|
||||
fun runBuilder(placement: CallablePlacement) {
|
||||
callableBuilder.placement = placement
|
||||
project.executeCommand(getText()) { callableBuilder.build() }
|
||||
project.executeCommand(text) { callableBuilder.build() }
|
||||
}
|
||||
|
||||
if (callableInfo is SecondaryConstructorInfo) {
|
||||
@@ -149,30 +151,13 @@ public abstract class CreateCallableFromUsageFixBase(
|
||||
}
|
||||
else {
|
||||
assert(callableInfo.receiverTypeInfo is TypeInfo.Empty) {
|
||||
"No receiver type candidates: ${element.getText()} in ${file.getText()}"
|
||||
"No receiver type candidates: ${element.text} in ${file.text}"
|
||||
}
|
||||
|
||||
chooseContainerElementIfNecessary(callableInfo.possibleContainers, editor, popupTitle, true, { it }) {
|
||||
val container = if (it is JetClassBody) it.getParent() as JetClassOrObject else it
|
||||
val container = if (it is JetClassBody) it.parent as JetClassOrObject else it
|
||||
runBuilder(CallablePlacement.NoReceiver(container))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun CreateCallableFromUsageFixes(
|
||||
originalExpression: JetExpression,
|
||||
callableInfos: List<CallableInfo>
|
||||
) : List<CreateCallableFromUsageFixBase> {
|
||||
return listOf(
|
||||
CreateCallableFromUsageFix(originalExpression, callableInfos),
|
||||
CreateExtensionCallableFromUsageFix(originalExpression, callableInfos)
|
||||
).filter { it.isAvailable() }
|
||||
}
|
||||
|
||||
public fun CreateCallableFromUsageFixes(
|
||||
originalExpression: JetExpression,
|
||||
callableInfo: CallableInfo
|
||||
) : List<CreateCallableFromUsageFixBase> {
|
||||
return CreateCallableFromUsageFixes(originalExpression, Collections.singletonList(callableInfo))
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.quickfix.NullQuickFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||
|
||||
public abstract class CreateCallableMemberFromUsageFactory<E : JetElement>(
|
||||
val extensionsSupported: Boolean = true
|
||||
) : CreateFromUsageFactory<E, List<CallableInfo>>() {
|
||||
private fun newCallableQuickFix(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
quickFixDataFactory: (SmartPsiElementPointer<E>) -> List<CallableInfo>,
|
||||
quickFixFactory: (E, List<CallableInfo>) -> CreateCallableFromUsageFixBase<E>
|
||||
): QuickFixWithDelegateFactory {
|
||||
return QuickFixWithDelegateFactory {
|
||||
val data = quickFixDataFactory(originalElementPointer).orEmpty()
|
||||
val originalElement = originalElementPointer.element
|
||||
if (data.isNotEmpty() && originalElement != null) quickFixFactory(originalElement, data) else NullQuickFix
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun createCallableInfo(element: E, diagnostic: Diagnostic): CallableInfo? = null
|
||||
|
||||
override fun createQuickFixData(element: E, diagnostic: Diagnostic): List<CallableInfo>
|
||||
= createCallableInfo(element, diagnostic).singletonOrEmptyList()
|
||||
|
||||
override fun createQuickFixes(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
diagnostic: Diagnostic,
|
||||
quickFixDataFactory: (SmartPsiElementPointer<E>) -> List<CallableInfo>
|
||||
): List<QuickFixWithDelegateFactory> {
|
||||
val memberFix = newCallableQuickFix(originalElementPointer, quickFixDataFactory) { element, data ->
|
||||
CreateCallableFromUsageFix(element, data)
|
||||
}
|
||||
if (!extensionsSupported) return listOf(memberFix)
|
||||
|
||||
val extensionFix = newCallableQuickFix(originalElementPointer, quickFixDataFactory) { element, data ->
|
||||
CreateExtensionCallableFromUsageFix(element, data)
|
||||
}
|
||||
return listOf(memberFix, extensionFix)
|
||||
}
|
||||
}
|
||||
+19
-20
@@ -17,39 +17,38 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.psi.JetMultiDeclaration
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetForExpression
|
||||
import org.jetbrains.kotlin.psi.JetMultiDeclaration
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
|
||||
object CreateComponentFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
object CreateComponentFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetMultiDeclaration>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetMultiDeclaration? {
|
||||
QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetMultiDeclaration>())?.let { return it }
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())?.multiParameter
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetMultiDeclaration, diagnostic: Diagnostic): CallableInfo? {
|
||||
val diagnosticWithParameters = Errors.COMPONENT_FUNCTION_MISSING.cast(diagnostic)
|
||||
val name = diagnosticWithParameters.getA()
|
||||
|
||||
val name = diagnosticWithParameters.a
|
||||
if (!isComponentLike(name)) return null
|
||||
|
||||
val componentNumber = getComponentIndex(name) - 1
|
||||
|
||||
var multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetMultiDeclaration>())
|
||||
val ownerType = if (multiDeclaration == null) {
|
||||
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())!!
|
||||
multiDeclaration = forExpr.getMultiParameter()!!
|
||||
TypeInfo(diagnosticWithParameters.getB(), Variance.IN_VARIANCE)
|
||||
}
|
||||
else {
|
||||
val rhs = multiDeclaration.getInitializer() ?: return null
|
||||
TypeInfo(rhs, Variance.IN_VARIANCE)
|
||||
}
|
||||
val entries = multiDeclaration.getEntries()
|
||||
val ownerType = element.initializer?.let { TypeInfo(it, Variance.IN_VARIANCE) }
|
||||
?: TypeInfo(diagnosticWithParameters.b, Variance.IN_VARIANCE)
|
||||
val entries = element.entries
|
||||
|
||||
val entry = entries[componentNumber]
|
||||
val returnType = TypeInfo(entry, Variance.OUT_VARIANCE)
|
||||
|
||||
return CreateCallableFromUsageFixes(multiDeclaration, FunctionInfo(name.getIdentifier(), ownerType, returnType))
|
||||
return FunctionInfo(name.identifier, ownerType, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
+17
-15
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
@@ -24,45 +23,48 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.SecondaryConstructorInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
object CreateConstructorFromDelegationCallActionFactory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val delegationCall = diagnostic.getPsiElement().getStrictParentOfType<JetConstructorDelegationCall>() ?: return null
|
||||
val calleeExpression = delegationCall.getCalleeExpression() ?: return null
|
||||
val currentClass = delegationCall.getStrictParentOfType<JetClass>() ?: return null
|
||||
object CreateConstructorFromDelegationCallActionFactory : CreateCallableMemberFromUsageFactory<JetConstructorDelegationCall>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetConstructorDelegationCall? {
|
||||
return diagnostic.psiElement.getStrictParentOfType<JetConstructorDelegationCall>()
|
||||
}
|
||||
|
||||
val project = currentClass.getProject()
|
||||
override fun createCallableInfo(element: JetConstructorDelegationCall, diagnostic: Diagnostic): CallableInfo? {
|
||||
val calleeExpression = element.calleeExpression ?: return null
|
||||
val currentClass = element.getStrictParentOfType<JetClass>() ?: return null
|
||||
|
||||
val project = currentClass.project
|
||||
|
||||
val classDescriptor = currentClass.resolveToDescriptor() as? ClassDescriptor ?: return null
|
||||
|
||||
val targetClass = if (calleeExpression.isThis()) {
|
||||
val targetClass = if (calleeExpression.isThis) {
|
||||
currentClass
|
||||
}
|
||||
else {
|
||||
val superClassDescriptor = DescriptorUtils.getSuperclassDescriptors(classDescriptor)
|
||||
.singleOrNull { it.getKind() == ClassKind.CLASS } ?: return null
|
||||
val superClassDescriptor =
|
||||
DescriptorUtils.getSuperclassDescriptors(classDescriptor).singleOrNull { it.kind == ClassKind.CLASS } ?: return null
|
||||
DescriptorToSourceUtilsIde.getAnyDeclaration(project, superClassDescriptor) ?: return null
|
||||
}
|
||||
if (!(targetClass.canRefactor() && (targetClass is JetClass || targetClass is PsiClass))) return null
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
val parameters = delegationCall.getValueArguments().map {
|
||||
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
|
||||
val parameters = element.valueArguments.map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
it.getArgumentName()?.asName?.asString()
|
||||
)
|
||||
}
|
||||
|
||||
return CreateCallableFromUsageFix(delegationCall, SecondaryConstructorInfo(parameters, targetClass))
|
||||
return SecondaryConstructorInfo(parameters, targetClass)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-16
@@ -16,49 +16,48 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.SecondaryConstructorInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
|
||||
import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
object CreateConstructorFromDelegatorToSuperCallActionFactory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val delegationCall = diagnostic.getPsiElement().getStrictParentOfType<JetDelegatorToSuperCall>() ?: return null
|
||||
val typeReference = delegationCall.getCalleeExpression().getTypeReference() ?: return null
|
||||
object CreateConstructorFromDelegatorToSuperCallActionFactory : CreateCallableMemberFromUsageFactory<JetDelegatorToSuperCall>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetDelegatorToSuperCall? {
|
||||
return diagnostic.psiElement.getStrictParentOfType<JetDelegatorToSuperCall>()
|
||||
}
|
||||
|
||||
val project = delegationCall.getProject()
|
||||
override fun createCallableInfo(element: JetDelegatorToSuperCall, diagnostic: Diagnostic): CallableInfo? {
|
||||
val typeReference = element.calleeExpression.typeReference ?: return null
|
||||
|
||||
val project = element.project
|
||||
|
||||
val superType = typeReference.analyze()[BindingContext.TYPE, typeReference] ?: return null
|
||||
val superClassDescriptor = superType.getConstructor().getDeclarationDescriptor() as? ClassDescriptor ?: return null
|
||||
if (superClassDescriptor.getKind() != ClassKind.CLASS) return null
|
||||
val superClassDescriptor = superType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
if (superClassDescriptor.kind != ClassKind.CLASS) return null
|
||||
val targetClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, superClassDescriptor) ?: return null
|
||||
if (!(targetClass.canRefactor() && (targetClass is JetClass || targetClass is PsiClass))) return null
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
val parameters = delegationCall.getValueArguments().map {
|
||||
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
|
||||
val parameters = element.valueArguments.map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
it.getArgumentName()?.asName?.asString()
|
||||
)
|
||||
}
|
||||
|
||||
return CreateCallableFromUsageFix(delegationCall, SecondaryConstructorInfo(parameters, targetClass))
|
||||
return SecondaryConstructorInfo(parameters, targetClass)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-14
@@ -17,25 +17,26 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetArrayAccessExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
|
||||
object CreateGetFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>()) ?: return null
|
||||
val arrayExpr = accessExpr.getArrayExpression() ?: return null
|
||||
object CreateGetFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetArrayAccessExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetArrayAccessExpression? {
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>())
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetArrayAccessExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val arrayExpr = element.arrayExpression ?: return null
|
||||
|
||||
val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE)
|
||||
|
||||
val parameters = accessExpr.getIndexExpressions().map {
|
||||
ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE))
|
||||
}
|
||||
|
||||
val returnType = TypeInfo(accessExpr, Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(accessExpr, FunctionInfo("get", arrayType, returnType, Collections.emptyList(), parameters))
|
||||
val parameters = element.indexExpressions.map { ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE)) }
|
||||
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo("get", arrayType, returnType, Collections.emptyList(), parameters)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -16,24 +16,27 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetForExpression
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
object CreateHasNextFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val diagnosticWithParameters = DiagnosticFactory.cast(diagnostic, Errors.HAS_NEXT_MISSING, Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE)
|
||||
val ownerType = TypeInfo(diagnosticWithParameters.getA(), Variance.IN_VARIANCE)
|
||||
object CreateHasNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())
|
||||
}
|
||||
|
||||
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
|
||||
val returnType = TypeInfo(KotlinBuiltIns.getInstance().getBooleanType(), Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(forExpr, FunctionInfo("hasNext", ownerType, returnType))
|
||||
override fun createCallableInfo(element: JetForExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val diagnosticWithParameters =
|
||||
DiagnosticFactory.cast(diagnostic, Errors.HAS_NEXT_MISSING, Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE)
|
||||
val ownerType = TypeInfo(diagnosticWithParameters.a, Variance.IN_VARIANCE)
|
||||
val returnType = TypeInfo(KotlinBuiltIns.getInstance().booleanType, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo("hasNext", ownerType, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-14
@@ -16,11 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
@@ -28,27 +27,26 @@ import org.jetbrains.kotlin.psi.JetCallExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
object CreateInvokeFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val callExpr = diagnostic.getPsiElement().getParent() as? JetCallExpression ?: return null
|
||||
object CreateInvokeFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetCallExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
|
||||
return diagnostic.psiElement.parent as? JetCallExpression
|
||||
}
|
||||
|
||||
val expectedType = Errors.FUNCTION_EXPECTED.cast(diagnostic).getB()
|
||||
if (expectedType.isError()) return null
|
||||
override fun createCallableInfo(element: JetCallExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val expectedType = Errors.FUNCTION_EXPECTED.cast(diagnostic).b
|
||||
if (expectedType.isError) return null
|
||||
|
||||
val receiverType = TypeInfo(expectedType, Variance.IN_VARIANCE)
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
val parameters = callExpr.getValueArguments().map {
|
||||
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
|
||||
val parameters = element.valueArguments.map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
it.getArgumentName()?.getReferenceExpression()?.getReferencedName()
|
||||
)
|
||||
}
|
||||
|
||||
val returnType = TypeInfo(callExpr, Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(
|
||||
callExpr,
|
||||
FunctionInfo(OperatorConventions.INVOKE.asString(), receiverType, returnType, emptyList(), parameters)
|
||||
)
|
||||
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(OperatorConventions.INVOKE.asString(), receiverType, returnType, emptyList(), parameters)
|
||||
}
|
||||
}
|
||||
|
||||
+28
-21
@@ -16,30 +16,33 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.psi.JetForExpression
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetForExpression
|
||||
import org.jetbrains.kotlin.types.JetTypeImpl
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.Collections
|
||||
|
||||
object CreateIteratorFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val file = diagnostic.getPsiFile() as? JetFile ?: return null
|
||||
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
|
||||
val iterableExpr = forExpr.getLoopRange() ?: return null
|
||||
val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression
|
||||
object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetForExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val file = diagnostic.psiFile as? JetFile ?: return null
|
||||
val iterableExpr = element.loopRange ?: return null
|
||||
val variableExpr: JetExpression = ((element.loopParameter ?: element.multiParameter) ?: return null) as JetExpression
|
||||
val iterableType = TypeInfo(iterableExpr, Variance.IN_VARIANCE)
|
||||
val returnJetType = KotlinBuiltIns.getInstance().getIterator().getDefaultType()
|
||||
val returnJetType = KotlinBuiltIns.getInstance().iterator.defaultType
|
||||
|
||||
val analysisResult = file.analyzeFullyAndGetResult()
|
||||
val returnJetTypeParameterTypes = variableExpr.guessTypes(analysisResult.bindingContext, analysisResult.moduleDescriptor)
|
||||
@@ -47,8 +50,12 @@ object CreateIteratorFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
|
||||
val returnJetTypeParameterType = TypeProjectionImpl(returnJetTypeParameterTypes[0])
|
||||
val returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType)
|
||||
val newReturnJetType = JetTypeImpl(returnJetType.getAnnotations(), returnJetType.getConstructor(), returnJetType.isMarkedNullable(), returnJetTypeArguments, returnJetType.getMemberScope())
|
||||
val newReturnJetType = JetTypeImpl(returnJetType.annotations,
|
||||
returnJetType.constructor,
|
||||
returnJetType.isMarkedNullable,
|
||||
returnJetTypeArguments,
|
||||
returnJetType.memberScope)
|
||||
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(forExpr, FunctionInfo("iterator", iterableType, returnType))
|
||||
return FunctionInfo("iterator", iterableType, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -17,24 +17,27 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetForExpression
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
object CreateNextFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
object CreateNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetForExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetForExpression? {
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>())
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetForExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val diagnosticWithParameters = DiagnosticFactory.cast(diagnostic, Errors.NEXT_MISSING, Errors.NEXT_NONE_APPLICABLE)
|
||||
val ownerType = TypeInfo(diagnosticWithParameters.getA(), Variance.IN_VARIANCE)
|
||||
val ownerType = TypeInfo(diagnosticWithParameters.a, Variance.IN_VARIANCE)
|
||||
|
||||
val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetForExpression>()) ?: return null
|
||||
val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression
|
||||
val returnType = TypeInfo(variableExpr, Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(forExpr, FunctionInfo("next", ownerType, returnType))
|
||||
val variableExpr = element.loopParameter ?: element.multiParameter ?: return null
|
||||
val returnType = TypeInfo(variableExpr as JetExpression, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo("next", ownerType, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
+30
-29
@@ -16,48 +16,49 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
object CreatePropertyDelegateAccessorsActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val expression = diagnostic.getPsiElement() as? JetExpression ?: return null
|
||||
val context = expression.analyze()
|
||||
object CreatePropertyDelegateAccessorsActionFactory : CreateCallableMemberFromUsageFactory<JetExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetExpression? {
|
||||
return diagnostic.psiElement as? JetExpression
|
||||
}
|
||||
|
||||
override fun createQuickFixData(element: JetExpression, diagnostic: Diagnostic): List<CallableInfo> {
|
||||
val context = element.analyze()
|
||||
|
||||
fun isApplicableForAccessor(accessor: PropertyAccessorDescriptor?): Boolean =
|
||||
accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null
|
||||
|
||||
val builtIns = KotlinBuiltIns.getInstance()
|
||||
|
||||
val property = expression.getNonStrictParentOfType<JetProperty>() ?: return null
|
||||
val property = element.getNonStrictParentOfType<JetProperty>() ?: return emptyList()
|
||||
val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? PropertyDescriptor
|
||||
?: return null
|
||||
?: return emptyList()
|
||||
|
||||
val propertyReceiver = propertyDescriptor.getExtensionReceiverParameter() ?: propertyDescriptor.getDispatchReceiverParameter()
|
||||
val propertyType = propertyDescriptor.getType()
|
||||
val propertyReceiver = propertyDescriptor.extensionReceiverParameter ?: propertyDescriptor.dispatchReceiverParameter
|
||||
val propertyType = propertyDescriptor.type
|
||||
|
||||
val accessorReceiverType = TypeInfo(expression, Variance.IN_VARIANCE)
|
||||
val thisRefParam = ParameterInfo(TypeInfo(propertyReceiver?.getType() ?: builtIns.getNullableNothingType(), Variance.IN_VARIANCE))
|
||||
val metadataParam = ParameterInfo(TypeInfo(builtIns.getPropertyMetadata().getDefaultType(), Variance.IN_VARIANCE))
|
||||
val accessorReceiverType = TypeInfo(element, Variance.IN_VARIANCE)
|
||||
val thisRefParam = ParameterInfo(TypeInfo(propertyReceiver?.type ?: builtIns.nullableNothingType, Variance.IN_VARIANCE))
|
||||
val metadataParam = ParameterInfo(TypeInfo(builtIns.propertyMetadata.defaultType, Variance.IN_VARIANCE))
|
||||
|
||||
val callableInfos = SmartList<CallableInfo>()
|
||||
|
||||
if (isApplicableForAccessor(propertyDescriptor.getGetter())) {
|
||||
if (isApplicableForAccessor(propertyDescriptor.getter)) {
|
||||
val getterInfo = FunctionInfo(
|
||||
name = "get",
|
||||
receiverTypeInfo = accessorReceiverType,
|
||||
@@ -67,17 +68,17 @@ object CreatePropertyDelegateAccessorsActionFactory : JetIntentionActionsFactory
|
||||
callableInfos.add(getterInfo)
|
||||
}
|
||||
|
||||
if (propertyDescriptor.isVar() && isApplicableForAccessor(propertyDescriptor.getSetter())) {
|
||||
if (propertyDescriptor.isVar && isApplicableForAccessor(propertyDescriptor.setter)) {
|
||||
val newValueParam = ParameterInfo(TypeInfo(propertyType, Variance.IN_VARIANCE))
|
||||
val setterInfo = FunctionInfo(
|
||||
name = "set",
|
||||
receiverTypeInfo = accessorReceiverType,
|
||||
returnTypeInfo = TypeInfo(builtIns.getUnitType(), Variance.OUT_VARIANCE),
|
||||
returnTypeInfo = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE),
|
||||
parameterInfos = listOf(thisRefParam, metadataParam, newValueParam)
|
||||
)
|
||||
callableInfos.add(setterInfo)
|
||||
}
|
||||
|
||||
return CreateCallableFromUsageFixes(expression, callableInfos)
|
||||
return callableInfos
|
||||
}
|
||||
}
|
||||
|
||||
+27
-24
@@ -16,53 +16,56 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.psi.JetArrayAccessExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.psi.JetBinaryExpression
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetArrayAccessExpression
|
||||
import org.jetbrains.kotlin.psi.JetBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.JetOperationExpression
|
||||
import org.jetbrains.kotlin.psi.JetUnaryExpression
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
object CreateSetFunctionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>()) ?: return null
|
||||
val arrayExpr = accessExpr.getArrayExpression() ?: return null
|
||||
object CreateSetFunctionActionFactory : CreateCallableMemberFromUsageFactory<JetArrayAccessExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetArrayAccessExpression? {
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetArrayAccessExpression>())
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetArrayAccessExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val arrayExpr = element.arrayExpression ?: return null
|
||||
val arrayType = TypeInfo(arrayExpr, Variance.IN_VARIANCE)
|
||||
|
||||
val builtIns = KotlinBuiltIns.getInstance()
|
||||
|
||||
val parameters = accessExpr.getIndexExpressions().mapTo(ArrayList<ParameterInfo>()) {
|
||||
val parameters = element.indexExpressions.mapTo(ArrayList<ParameterInfo>()) {
|
||||
ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE))
|
||||
}
|
||||
|
||||
val assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetOperationExpression>()) ?: return null
|
||||
val valType = when (assignmentExpr) {
|
||||
is JetBinaryExpression -> {
|
||||
TypeInfo(assignmentExpr.getRight() ?: return null, Variance.IN_VARIANCE)
|
||||
TypeInfo(assignmentExpr.right ?: return null, Variance.IN_VARIANCE)
|
||||
}
|
||||
is JetUnaryExpression -> {
|
||||
if (assignmentExpr.getOperationToken() !in OperatorConventions.INCREMENT_OPERATIONS) return null
|
||||
if (assignmentExpr.operationToken !in OperatorConventions.INCREMENT_OPERATIONS) return null
|
||||
|
||||
val context = assignmentExpr.analyze()
|
||||
val rhsType = assignmentExpr.getResolvedCall(context)?.getResultingDescriptor()?.getReturnType()
|
||||
TypeInfo(if (rhsType == null || ErrorUtils.containsErrorType(rhsType)) builtIns.getAnyType() else rhsType, Variance.IN_VARIANCE)
|
||||
val rhsType = assignmentExpr.getResolvedCall(context)?.resultingDescriptor?.returnType
|
||||
TypeInfo(if (rhsType == null || ErrorUtils.containsErrorType(rhsType)) builtIns.anyType else rhsType, Variance.IN_VARIANCE)
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
parameters.add(ParameterInfo(valType, "value"))
|
||||
|
||||
val returnType = TypeInfo(builtIns.getUnitType(), Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(accessExpr, FunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters))
|
||||
val returnType = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo("set", arrayType, returnType, Collections.emptyList(), parameters)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -17,25 +17,28 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.JetToken
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.psi.JetUnaryExpression
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
public object CreateUnaryOperationActionFactory: JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val callExpr = diagnostic.getPsiElement().getParent() as? JetUnaryExpression ?: return null
|
||||
val token = callExpr.getOperationToken() as JetToken
|
||||
public object CreateUnaryOperationActionFactory: CreateCallableMemberFromUsageFactory<JetUnaryExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetUnaryExpression? {
|
||||
return diagnostic.psiElement.parent as? JetUnaryExpression
|
||||
}
|
||||
|
||||
override fun createCallableInfo(element: JetUnaryExpression, diagnostic: Diagnostic): CallableInfo? {
|
||||
val token = element.operationToken as JetToken
|
||||
val operationName = OperatorConventions.getNameForOperationSymbol(token) ?: return null
|
||||
val incDec = token in OperatorConventions.INCREMENT_OPERATIONS
|
||||
|
||||
val receiverExpr = callExpr.getBaseExpression() ?: return null
|
||||
val receiverExpr = element.baseExpression ?: return null
|
||||
|
||||
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
|
||||
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(callExpr, Variance.OUT_VARIANCE)
|
||||
return CreateCallableFromUsageFixes(callExpr, FunctionInfo(operationName.asString(), receiverType, returnType))
|
||||
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(operationName.asString(), receiverType, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
+31
-31
@@ -16,28 +16,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
|
||||
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.JetUserType
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall
|
||||
import org.jetbrains.kotlin.psi.JetCallElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.psi.JetConstructorCalleeExpression
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
|
||||
public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val diagElement = diagnostic.getPsiElement()
|
||||
public object CreateClassFromCallWithConstructorCalleeActionFactory : CreateClassFromUsageFactory<JetCallElement>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallElement? {
|
||||
val diagElement = diagnostic.psiElement
|
||||
|
||||
val callElement = PsiTreeUtil.getParentOfType(
|
||||
diagElement,
|
||||
@@ -45,26 +39,34 @@ public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleI
|
||||
javaClass<JetDelegatorToSuperCall>()
|
||||
) as? JetCallElement ?: return null
|
||||
|
||||
val isAnnotation = callElement is JetAnnotationEntry
|
||||
|
||||
val callee = callElement.getCalleeExpression() as? JetConstructorCalleeExpression ?: return null
|
||||
val calleeRef = callee.getConstructorReferenceExpression() ?: return null
|
||||
val callee = callElement.calleeExpression as? JetConstructorCalleeExpression ?: return null
|
||||
val calleeRef = callee.constructorReferenceExpression ?: return null
|
||||
|
||||
if (!calleeRef.isAncestor(diagElement)) return null
|
||||
return callElement
|
||||
}
|
||||
|
||||
val file = callElement.getContainingFile() as? JetFile ?: return null
|
||||
val typeRef = callee.getTypeReference() ?: return null
|
||||
val userType = typeRef.getTypeElement() as? JetUserType ?: return null
|
||||
override fun getPossibleClassKinds(element: JetCallElement, diagnostic: Diagnostic): List<ClassKind> {
|
||||
return (if (element is JetAnnotationEntry) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS).singletonList()
|
||||
}
|
||||
|
||||
override fun createQuickFixData(element: JetCallElement, diagnostic: Diagnostic): ClassInfo? {
|
||||
val isAnnotation = element is JetAnnotationEntry
|
||||
val callee = element.calleeExpression as? JetConstructorCalleeExpression ?: return null
|
||||
val calleeRef = callee.constructorReferenceExpression ?: return null
|
||||
val file = element.containingFile as? JetFile ?: return null
|
||||
val typeRef = callee.typeReference ?: return null
|
||||
val userType = typeRef.typeElement as? JetUserType ?: return null
|
||||
|
||||
val context = userType.analyze()
|
||||
|
||||
val qualifier = userType.getQualifier()?.getReferenceExpression()
|
||||
val qualifier = userType.qualifier?.referenceExpression
|
||||
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||
|
||||
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
val valueArguments = callElement.getValueArguments()
|
||||
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
|
||||
val valueArguments = element.valueArguments
|
||||
val defaultParamName = if (valueArguments.size() == 1) "value" else null
|
||||
val parameterInfos = valueArguments.map {
|
||||
ParameterInfo(
|
||||
@@ -75,13 +77,12 @@ public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleI
|
||||
|
||||
val typeArgumentInfos = when {
|
||||
isAnnotation -> Collections.emptyList<TypeInfo>()
|
||||
else -> callElement.getTypeArguments()
|
||||
.map { it.getTypeReference()?.let { TypeInfo(it, Variance.INVARIANT) } }
|
||||
else -> element.typeArguments
|
||||
.map { it.typeReference?.let { TypeInfo(it, Variance.INVARIANT) } }
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
val classInfo = ClassInfo(
|
||||
kind = if (isAnnotation) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS,
|
||||
return ClassInfo(
|
||||
name = calleeRef.getReferencedName(),
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = TypeInfo.Empty,
|
||||
@@ -89,6 +90,5 @@ public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleI
|
||||
open = !isAnnotation,
|
||||
typeArguments = typeArgumentInfos
|
||||
)
|
||||
return CreateClassFromUsageFix(callElement, classInfo)
|
||||
}
|
||||
}
|
||||
|
||||
+43
-25
@@ -16,43 +16,63 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeInfoForTypeArguments
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.JetTypeReference
|
||||
import org.jetbrains.kotlin.psi.JetCallExpression
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.JetQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetAnnotationEntry
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
|
||||
public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val diagElement = diagnostic.getPsiElement()
|
||||
public object CreateClassFromConstructorCallActionFactory: CreateClassFromUsageFactory<JetCallExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetCallExpression? {
|
||||
val diagElement = diagnostic.psiElement
|
||||
if (diagElement.getNonStrictParentOfType<JetTypeReference>() != null) return null
|
||||
|
||||
val callExpr = diagElement.parent as? JetCallExpression ?: return null
|
||||
return if (callExpr.calleeExpression == diagElement) callExpr else null
|
||||
}
|
||||
|
||||
override fun getPossibleClassKinds(element: JetCallExpression, diagnostic: Diagnostic): List<ClassKind> {
|
||||
val inAnnotationEntry = diagnostic.psiElement.getNonStrictParentOfType<JetAnnotationEntry>() != null
|
||||
|
||||
val (context, moduleDescriptor) = element.analyzeFullyAndGetResult()
|
||||
val file = element.containingFile as? JetFile ?: return emptyList()
|
||||
val call = element.getCall(context) ?: return emptyList()
|
||||
val targetParent = getTargetParentByCall(call, file) ?: return emptyList()
|
||||
|
||||
val classKind = if (inAnnotationEntry) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS
|
||||
val fullCallExpr = element.getQualifiedExpressionForSelectorOrThis()
|
||||
if (!fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent).second(classKind)) return emptyList()
|
||||
|
||||
return classKind.singletonList()
|
||||
}
|
||||
|
||||
override fun createQuickFixData(element: JetCallExpression, diagnostic: Diagnostic): ClassInfo? {
|
||||
val diagElement = diagnostic.psiElement
|
||||
if (diagElement.getNonStrictParentOfType<JetTypeReference>() != null) return null
|
||||
|
||||
val inAnnotationEntry = diagElement.getNonStrictParentOfType<JetAnnotationEntry>() != null
|
||||
|
||||
val callExpr = diagElement.getParent() as? JetCallExpression ?: return null
|
||||
if (callExpr.getCalleeExpression() != diagElement) return null
|
||||
val callExpr = diagElement.parent as? JetCallExpression ?: return null
|
||||
if (callExpr.calleeExpression != diagElement) return null
|
||||
|
||||
val calleeExpr = callExpr.getCalleeExpression() as? JetSimpleNameExpression ?: return null
|
||||
val calleeExpr = callExpr.calleeExpression as? JetSimpleNameExpression ?: return null
|
||||
|
||||
val name = calleeExpr.getReferencedName()
|
||||
if (!inAnnotationEntry && !name.checkClassName()) return null
|
||||
|
||||
val callParent = callExpr.getParent()
|
||||
val callParent = callExpr.parent
|
||||
val fullCallExpr =
|
||||
if (callParent is JetQualifiedExpression && callParent.getSelectorExpression() == callExpr) callParent else callExpr
|
||||
if (callParent is JetQualifiedExpression && callParent.selectorExpression == callExpr) callParent else callExpr
|
||||
|
||||
val file = fullCallExpr.getContainingFile() as? JetFile ?: return null
|
||||
val file = fullCallExpr.containingFile as? JetFile ?: return null
|
||||
|
||||
val (context, moduleDescriptor) = callExpr.analyzeFullyAndGetResult()
|
||||
|
||||
@@ -60,9 +80,9 @@ public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionAct
|
||||
val targetParent = getTargetParentByCall(call, file) ?: return null
|
||||
val inner = isInnerClassExpected(call)
|
||||
|
||||
val valueArguments = callExpr.getValueArguments()
|
||||
val valueArguments = callExpr.valueArguments
|
||||
val defaultParamName = if (inAnnotationEntry && valueArguments.size() == 1) "value" else null
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
val anyType = KotlinBuiltIns.getInstance().nullableAnyType
|
||||
val parameterInfos = valueArguments.map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
@@ -77,8 +97,7 @@ public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionAct
|
||||
|
||||
val typeArgumentInfos = if (inAnnotationEntry) Collections.emptyList() else callExpr.getTypeInfoForTypeArguments()
|
||||
|
||||
val classInfo = ClassInfo(
|
||||
kind = classKind,
|
||||
return ClassInfo(
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = expectedTypeInfo,
|
||||
@@ -86,6 +105,5 @@ public object CreateClassFromConstructorCallActionFactory: JetSingleIntentionAct
|
||||
typeArguments = typeArgumentInfos,
|
||||
parameterInfos = parameterInfos
|
||||
)
|
||||
return CreateClassFromUsageFix(callExpr, classInfo)
|
||||
}
|
||||
}
|
||||
|
||||
+86
-68
@@ -16,74 +16,74 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.JetTypeReference
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.JetCallExpression
|
||||
import org.jetbrains.kotlin.psi.JetImportDirective
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetReferenceExpression
|
||||
import java.util.Arrays
|
||||
import org.jetbrains.kotlin.psi.JetDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isDotReceiver
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isDotReceiver
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import java.util.Arrays
|
||||
import java.util.Collections
|
||||
|
||||
public object CreateClassFromReferenceExpressionActionFactory : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
public object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFactory<JetSimpleNameExpression>(true) {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetSimpleNameExpression? {
|
||||
val refExpr = diagnostic.psiElement as? JetSimpleNameExpression ?: return null
|
||||
if (refExpr.getNonStrictParentOfType<JetTypeReference>() != null) return null
|
||||
return refExpr
|
||||
}
|
||||
|
||||
private fun getFullCallExpression(element: JetSimpleNameExpression): JetExpression? {
|
||||
return element.parent?.let {
|
||||
when {
|
||||
it is JetCallExpression && it.calleeExpression == element -> return null
|
||||
it is JetQualifiedExpression && it.selectorExpression == element -> it
|
||||
else -> element
|
||||
}
|
||||
} as? JetExpression
|
||||
}
|
||||
|
||||
private fun isQualifierExpected(element: JetSimpleNameExpression) = element.isDotReceiver() || ((element.parent as? JetDotQualifiedExpression)?.isDotReceiver() ?: false)
|
||||
|
||||
private fun isInsideOfImport(element: JetSimpleNameExpression) = element.getNonStrictParentOfType<JetImportDirective>() != null
|
||||
|
||||
override fun getPossibleClassKinds(element: JetSimpleNameExpression, diagnostic: Diagnostic): List<ClassKind> {
|
||||
fun isEnum(element: PsiElement): Boolean {
|
||||
return when (element) {
|
||||
is JetClass -> element.isEnum()
|
||||
is PsiClass -> element.isEnum()
|
||||
is PsiClass -> element.isEnum
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
val refExpr = diagnostic.getPsiElement() as? JetSimpleNameExpression ?: return Collections.emptyList()
|
||||
if (refExpr.getNonStrictParentOfType<JetTypeReference>() != null) return Collections.emptyList()
|
||||
val file = element.containingFile as? JetFile ?: return Collections.emptyList()
|
||||
|
||||
val file = refExpr.getContainingFile() as? JetFile ?: return Collections.emptyList()
|
||||
val name = element.getReferencedName()
|
||||
|
||||
val name = refExpr.getReferencedName()
|
||||
val (context, moduleDescriptor) = element.analyzeFullyAndGetResult()
|
||||
|
||||
val (context, moduleDescriptor) = refExpr.analyzeFullyAndGetResult()
|
||||
val fullCallExpr = getFullCallExpression(element) ?: return Collections.emptyList()
|
||||
|
||||
val fullCallExpr = refExpr.getParent()?.let {
|
||||
when {
|
||||
it is JetCallExpression && it.getCalleeExpression() == refExpr -> return Collections.emptyList()
|
||||
it is JetQualifiedExpression && it.getSelectorExpression() == refExpr -> it
|
||||
else -> refExpr
|
||||
}
|
||||
} as? JetExpression ?: return Collections.emptyList()
|
||||
|
||||
val inImport = refExpr.getNonStrictParentOfType<JetImportDirective>() != null
|
||||
val qualifierExpected = refExpr.isDotReceiver() || ((refExpr.getParent() as? JetDotQualifiedExpression)?.isDotReceiver() ?: false)
|
||||
|
||||
if (inImport || qualifierExpected) {
|
||||
val receiverSelector = (fullCallExpr as? JetQualifiedExpression)?.getReceiverExpression()?.getQualifiedElementSelector() as? JetReferenceExpression
|
||||
val inImport = element.getNonStrictParentOfType<JetImportDirective>() != null
|
||||
if (inImport || isQualifierExpected(element)) {
|
||||
val receiverSelector = (fullCallExpr as? JetQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? JetReferenceExpression
|
||||
val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||
|
||||
val targetParent =
|
||||
getTargetParentByQualifier(refExpr.getContainingJetFile(), receiverSelector != null, qualifierDescriptor)
|
||||
getTargetParentByQualifier(element.getContainingJetFile(), receiverSelector != null, qualifierDescriptor)
|
||||
?: return Collections.emptyList()
|
||||
|
||||
val createPackageAction = refExpr.getCreatePackageFixIfApplicable(targetParent)
|
||||
if (createPackageAction != null) return Collections.singletonList(createPackageAction)
|
||||
element.getCreatePackageFixIfApplicable(targetParent)?.let { return emptyList() }
|
||||
|
||||
return (if (name.checkClassName()) ClassKind.values() else arrayOf())
|
||||
if (!name.checkClassName()) return emptyList()
|
||||
|
||||
return ClassKind
|
||||
.values()
|
||||
.filter {
|
||||
when (it) {
|
||||
ClassKind.ANNOTATION_CLASS -> inImport
|
||||
@@ -91,24 +91,15 @@ public object CreateClassFromReferenceExpressionActionFactory : JetIntentionActi
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
.map {
|
||||
val classInfo = ClassInfo(
|
||||
kind = it,
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = TypeInfo.Empty
|
||||
)
|
||||
CreateClassFromUsageFix(refExpr, classInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if (fullCallExpr.getAssignmentByLHS() != null) return Collections.emptyList()
|
||||
|
||||
val call = refExpr.getCall(context) ?: return Collections.emptyList()
|
||||
val call = element.getCall(context) ?: return Collections.emptyList()
|
||||
val targetParent = getTargetParentByCall(call, file) ?: return Collections.emptyList()
|
||||
if (isInnerClassExpected(call)) return Collections.emptyList()
|
||||
|
||||
val (expectedTypeInfo, filter) = fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent)
|
||||
val filter = fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent).second
|
||||
|
||||
return Arrays.asList(ClassKind.OBJECT, ClassKind.ENUM_ENTRY)
|
||||
.filter {
|
||||
@@ -118,14 +109,41 @@ public object CreateClassFromReferenceExpressionActionFactory : JetIntentionActi
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
.map {
|
||||
val classInfo = ClassInfo(
|
||||
kind = it,
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = expectedTypeInfo
|
||||
)
|
||||
CreateClassFromUsageFix(refExpr, classInfo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createQuickFixData(element: JetSimpleNameExpression, diagnostic: Diagnostic): ClassInfo? {
|
||||
val file = element.containingFile as? JetFile ?: return null
|
||||
|
||||
val name = element.getReferencedName()
|
||||
|
||||
val (context, moduleDescriptor) = element.analyzeFullyAndGetResult()
|
||||
|
||||
val fullCallExpr = getFullCallExpression(element) ?: return null
|
||||
|
||||
if (isInsideOfImport(element) || isQualifierExpected(element)) {
|
||||
val receiverSelector = (fullCallExpr as? JetQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? JetReferenceExpression
|
||||
val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||
|
||||
val targetParent =
|
||||
getTargetParentByQualifier(element.getContainingJetFile(), receiverSelector != null, qualifierDescriptor)
|
||||
?: return null
|
||||
|
||||
return ClassInfo(
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = TypeInfo.Empty
|
||||
)
|
||||
}
|
||||
|
||||
val call = element.getCall(context) ?: return null
|
||||
val targetParent = getTargetParentByCall(call, file) ?: return null
|
||||
|
||||
val expectedTypeInfo = fullCallExpr.getInheritableTypeInfo(context, moduleDescriptor, targetParent).first
|
||||
|
||||
return ClassInfo(
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = expectedTypeInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+41
-47
@@ -16,49 +16,36 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
|
||||
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.psi.JetUserType
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.psi.JetDelegatorToSuperClass
|
||||
import org.jetbrains.kotlin.psi.JetConstructorCalleeExpression
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.psi.JetConstructorCalleeExpression
|
||||
import org.jetbrains.kotlin.psi.JetDelegatorToSuperClass
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetUserType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.Collections
|
||||
|
||||
public object CreateClassFromTypeReferenceActionFactory: JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val userType = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetUserType>()) ?: return Collections.emptyList()
|
||||
val typeArguments = userType.getTypeArgumentsAsTypes()
|
||||
public object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<JetUserType>(true) {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetUserType? {
|
||||
return QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetUserType>())
|
||||
}
|
||||
|
||||
val refExpr = userType.getReferenceExpression() ?: return Collections.emptyList()
|
||||
val name = refExpr.getReferencedName()
|
||||
|
||||
val typeRefParent = userType.getParent()?.getParent()
|
||||
override fun getPossibleClassKinds(element: JetUserType, diagnostic: Diagnostic): List<ClassKind> {
|
||||
val typeRefParent = element.parent?.parent
|
||||
if (typeRefParent is JetConstructorCalleeExpression) return Collections.emptyList()
|
||||
|
||||
val traitExpected = typeRefParent is JetDelegatorToSuperClass
|
||||
|
||||
val context = userType.analyze()
|
||||
val isQualifier = (element.parent as? JetUserType)?.let { it.qualifier == element } ?: false
|
||||
|
||||
val file = userType.getContainingFile() as? JetFile ?: return Collections.emptyList()
|
||||
|
||||
val isQualifier = (userType.getParent() as? JetUserType)?.let { it.getQualifier() == userType } ?: false
|
||||
val qualifier = userType.getQualifier()?.getReferenceExpression()
|
||||
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||
|
||||
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return Collections.emptyList()
|
||||
|
||||
val possibleKinds = when {
|
||||
return when {
|
||||
traitExpected -> Collections.singletonList(ClassKind.TRAIT)
|
||||
else -> ClassKind.values().filter {
|
||||
val noTypeArguments = typeArguments.isEmpty()
|
||||
val noTypeArguments = element.typeArgumentsAsTypes.isEmpty()
|
||||
when (it) {
|
||||
ClassKind.OBJECT -> noTypeArguments && isQualifier
|
||||
ClassKind.ANNOTATION_CLASS -> noTypeArguments && !isQualifier
|
||||
@@ -68,22 +55,29 @@ public object CreateClassFromTypeReferenceActionFactory: JetIntentionActionsFact
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getAnyType()
|
||||
override fun createQuickFixData(element: JetUserType, diagnostic: Diagnostic): ClassInfo? {
|
||||
val name = element.referenceExpression?.getReferencedName() ?: return null
|
||||
if (element.parent?.parent is JetConstructorCalleeExpression) return null
|
||||
|
||||
val createPackageAction = refExpr.getCreatePackageFixIfApplicable(targetParent)
|
||||
val createClassActions = possibleKinds.map {
|
||||
val classInfo = ClassInfo(
|
||||
kind = it,
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = TypeInfo.Empty,
|
||||
typeArguments = typeArguments.map {
|
||||
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
|
||||
}
|
||||
)
|
||||
CreateClassFromUsageFix(userType, classInfo)
|
||||
}
|
||||
return createPackageAction.singletonOrEmptyList() + createClassActions
|
||||
val file = element.containingFile as? JetFile ?: return null
|
||||
|
||||
val context = element.analyze()
|
||||
val qualifier = element.qualifier?.referenceExpression
|
||||
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||
|
||||
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().anyType
|
||||
|
||||
return ClassInfo(
|
||||
name = name,
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = TypeInfo.Empty,
|
||||
typeArguments = element.typeArgumentsAsTypes.map {
|
||||
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage.createClass
|
||||
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.quickfix.NullQuickFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFactory
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetUserType
|
||||
|
||||
abstract class CreateClassFromUsageFactory<E : JetElement>(
|
||||
val createPackageIsAvailable: Boolean = false
|
||||
) : CreateFromUsageFactory<E, ClassInfo?>() {
|
||||
protected abstract fun getPossibleClassKinds(element: E, diagnostic: Diagnostic): List<ClassKind>
|
||||
|
||||
override fun createQuickFixes(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
diagnostic: Diagnostic,
|
||||
quickFixDataFactory: (SmartPsiElementPointer<E>) -> ClassInfo?
|
||||
): List<QuickFixWithDelegateFactory> {
|
||||
val originalElement = originalElementPointer.element ?: return emptyList()
|
||||
|
||||
val classFixes = getPossibleClassKinds(originalElement, diagnostic).map { classKind ->
|
||||
QuickFixWithDelegateFactory {
|
||||
val currentElement = originalElementPointer.element
|
||||
val data = quickFixDataFactory(originalElementPointer)
|
||||
if (currentElement != null && data != null) {
|
||||
CreateClassFromUsageFix(originalElement, data.copy(kind = classKind))
|
||||
} else NullQuickFix
|
||||
}
|
||||
}
|
||||
|
||||
if (!createPackageIsAvailable) return classFixes
|
||||
val refExpr = (originalElement as? JetUserType)?.referenceExpression ?: return classFixes
|
||||
val packageFix = QuickFixWithDelegateFactory {
|
||||
quickFixDataFactory(originalElementPointer)?.let {
|
||||
refExpr.getCreatePackageFixIfApplicable(it.targetParent)
|
||||
} ?: NullQuickFix
|
||||
}
|
||||
|
||||
return classFixes + packageFix
|
||||
}
|
||||
}
|
||||
+18
-21
@@ -25,17 +25,13 @@ import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiPackage
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.getOrCreateKotlinFile
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.ENUM_ENTRY
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.OBJECT
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.PLAIN_CLASS
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.TRAIT
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.*
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
@@ -48,11 +44,12 @@ enum class ClassKind(val keyword: String, val description: String) {
|
||||
ENUM_ENTRY("", "enum constant"),
|
||||
ANNOTATION_CLASS("annotation class", "annotation"),
|
||||
TRAIT("interface", "interface"),
|
||||
OBJECT("object", "object")
|
||||
OBJECT("object", "object"),
|
||||
DEFAULT("", "") // Used as a placeholder and must be replaced with one of the kinds above
|
||||
}
|
||||
|
||||
public class ClassInfo(
|
||||
val kind: ClassKind,
|
||||
public data class ClassInfo(
|
||||
val kind: ClassKind = ClassKind.DEFAULT,
|
||||
val name: String,
|
||||
val targetParent: PsiElement,
|
||||
val expectedTypeInfo: TypeInfo,
|
||||
@@ -62,19 +59,19 @@ public class ClassInfo(
|
||||
val parameterInfos: List<ParameterInfo> = Collections.emptyList()
|
||||
)
|
||||
|
||||
public class CreateClassFromUsageFix(
|
||||
element: JetElement,
|
||||
public class CreateClassFromUsageFix<E : JetElement>(
|
||||
element: E,
|
||||
val classInfo: ClassInfo
|
||||
): CreateFromUsageFixBase(element) {
|
||||
|
||||
): CreateFromUsageFixBase<E>(element) {
|
||||
override fun getText() = "Create ${classInfo.kind.description} '${classInfo.name}'"
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
if (!super.isAvailable(project, editor, file)) return false
|
||||
with(classInfo) {
|
||||
if (kind == DEFAULT) return false
|
||||
if (targetParent is PsiClass) {
|
||||
if (kind == OBJECT || kind == ENUM_ENTRY) return false
|
||||
if (targetParent.isInterface() && inner) return false
|
||||
if (targetParent.isInterface && inner) return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -82,27 +79,27 @@ public class CreateClassFromUsageFix(
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
fun createFileByPackage(psiPackage: PsiPackage): JetFile? {
|
||||
val directories = psiPackage.getDirectories().filter { it.canRefactor() }
|
||||
assert (directories.isNotEmpty()) { "Package '${psiPackage.getQualifiedName()}' must be refactorable" }
|
||||
val directories = psiPackage.directories.filter { it.canRefactor() }
|
||||
assert (directories.isNotEmpty()) { "Package '${psiPackage.qualifiedName}' must be refactorable" }
|
||||
|
||||
val currentModule = ModuleUtilCore.findModuleForPsiElement(file)
|
||||
val preferredDirectory =
|
||||
directories.firstOrNull { ModuleUtilCore.findModuleForPsiElement(it) == currentModule }
|
||||
?: directories.firstOrNull()
|
||||
|
||||
val targetDirectory = if (directories.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
val targetDirectory = if (directories.size() > 1 && !ApplicationManager.getApplication().isUnitTestMode) {
|
||||
DirectoryChooserUtil.chooseDirectory(directories.toTypedArray(), preferredDirectory, project, HashMap())
|
||||
}
|
||||
else {
|
||||
preferredDirectory
|
||||
} ?: return null
|
||||
|
||||
val fileName = "${classInfo.name}.${JetFileType.INSTANCE.getDefaultExtension()}"
|
||||
val fileName = "${classInfo.name}.${JetFileType.INSTANCE.defaultExtension}"
|
||||
val targetFile = getOrCreateKotlinFile(fileName, targetDirectory)
|
||||
if (targetFile == null) {
|
||||
val filePath = "${targetDirectory.getVirtualFile().getPath()}/$fileName"
|
||||
val filePath = "${targetDirectory.virtualFile.path}/$fileName"
|
||||
CodeInsightUtils.showErrorHint(
|
||||
targetDirectory.getProject(),
|
||||
targetDirectory.project,
|
||||
editor!!,
|
||||
"File $filePath already exists but does not correspond to Kotlin file",
|
||||
"Create file",
|
||||
@@ -117,7 +114,7 @@ public class CreateClassFromUsageFix(
|
||||
when (targetParent) {
|
||||
is JetElement, is PsiClass -> targetParent
|
||||
is PsiPackage -> createFileByPackage(targetParent)
|
||||
else -> throw AssertionError("Unexpected element: " + targetParent.getText())
|
||||
else -> throw AssertionError("Unexpected element: " + targetParent.text)
|
||||
} ?: return
|
||||
|
||||
val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo)
|
||||
@@ -125,7 +122,7 @@ public class CreateClassFromUsageFix(
|
||||
Collections.singletonList(constructorInfo), element as JetElement, file, editor, false, kind == PLAIN_CLASS || kind == TRAIT
|
||||
).createBuilder()
|
||||
builder.placement = CallablePlacement.NoReceiver(targetParent)
|
||||
project.executeCommand(getText()) { builder.build() }
|
||||
project.executeCommand(text) { builder.build() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -17,14 +17,13 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.intentions.ConvertToBlockBodyIntention
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
@@ -47,7 +46,7 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
|
||||
.filter { it is JetBlockExpression || it is JetDeclarationWithBody }
|
||||
.firstOrNull() as? JetElement ?: return null
|
||||
|
||||
return object: CreateFromUsageFixBase(refExpr) {
|
||||
return object: CreateFromUsageFixBase<JetSimpleNameExpression>(refExpr) {
|
||||
override fun getText(): String = JetBundle.message("create.local.variable.from.usage", propertyName)
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
@@ -57,12 +56,12 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
|
||||
|
||||
val actualContainer = when (container) {
|
||||
is JetBlockExpression -> container
|
||||
else -> ConvertToBlockBodyIntention.convert(container as JetDeclarationWithBody).getBodyExpression()!!
|
||||
else -> ConvertToBlockBodyIntention.convert(container as JetDeclarationWithBody).bodyExpression!!
|
||||
} as JetBlockExpression
|
||||
|
||||
if (actualContainer != container) {
|
||||
val bodyExpression = actualContainer.getStatements().first()
|
||||
originalElement = (bodyExpression as? JetReturnExpression)?.getReturnedExpression() ?: bodyExpression
|
||||
val bodyExpression = actualContainer.statements.first()!!
|
||||
originalElement = (bodyExpression as? JetReturnExpression)?.returnedExpression ?: bodyExpression
|
||||
}
|
||||
|
||||
val typeInfo = TypeInfo(
|
||||
@@ -73,7 +72,7 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
|
||||
|
||||
with (CallableBuilderConfiguration(propertyInfo.singletonOrEmptyList(), originalElement, file, editor).createBuilder()) {
|
||||
placement = CallablePlacement.NoReceiver(actualContainer)
|
||||
project.executeCommand(getText()) { build() }
|
||||
project.executeCommand(text) { build() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage.createVariable
|
||||
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.JetPropertyAccessor
|
||||
import org.jetbrains.kotlin.psi.JetFunction
|
||||
import org.jetbrains.kotlin.psi.JetClassInitializer
|
||||
import org.jetbrains.kotlin.psi.JetClassBody
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeParameters
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import java.util.LinkedHashSet
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
|
||||
import org.jetbrains.kotlin.psi.JetEnumEntry
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.psi.JetDelegationSpecifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
|
||||
object CreateParameterActionFactory: JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val result = (diagnostic.getPsiFile() as? JetFile)?.analyzeFullyAndGetResult() ?: return null
|
||||
val context = result.bindingContext
|
||||
|
||||
val refExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetSimpleNameExpression>()) ?: return null
|
||||
if (refExpr.getQualifiedElement() != refExpr) return null
|
||||
|
||||
val varExpected = refExpr.getAssignmentByLHS() != null
|
||||
|
||||
val paramType = refExpr.getExpressionForTypeGuess().guessTypes(context, result.moduleDescriptor).let {
|
||||
when (it.size()) {
|
||||
0 -> KotlinBuiltIns.getInstance().getAnyType()
|
||||
1 -> it.first()
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
var valOrVar: JetValVar = JetValVar.None
|
||||
|
||||
fun chooseContainingClass(it: PsiElement): JetClass? {
|
||||
valOrVar = if (varExpected) JetValVar.Var else JetValVar.Val
|
||||
return it.parents.firstIsInstanceOrNull<JetClassOrObject>() as? JetClass
|
||||
}
|
||||
|
||||
// todo: skip lambdas for now because Change Signature doesn't apply to them yet
|
||||
val container = refExpr.parents
|
||||
.filter {
|
||||
it is JetNamedFunction || it is JetPropertyAccessor || it is JetClassBody || it is JetClassInitializer ||
|
||||
it is JetDelegationSpecifier
|
||||
}
|
||||
.firstOrNull()
|
||||
?.let {
|
||||
when {
|
||||
it is JetNamedFunction && varExpected,
|
||||
it is JetPropertyAccessor -> chooseContainingClass(it)
|
||||
it is JetClassInitializer -> it.getParent()?.getParent() as? JetClass
|
||||
it is JetDelegationSpecifier -> {
|
||||
val klass = it.getStrictParentOfType<JetClass>()
|
||||
if (klass != null && !klass.isInterface() && klass !is JetEnumEntry) klass else null
|
||||
}
|
||||
it is JetClassBody -> {
|
||||
val klass = it.getParent() as? JetClass
|
||||
when {
|
||||
klass is JetEnumEntry -> chooseContainingClass(klass)
|
||||
klass != null && klass.isInterface() -> null
|
||||
else -> klass
|
||||
}
|
||||
}
|
||||
else -> it
|
||||
}
|
||||
} ?: return null
|
||||
|
||||
val functionDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, container]?.let {
|
||||
if (it is ClassDescriptor) it.getUnsubstitutedPrimaryConstructor() else it
|
||||
} as? FunctionDescriptor ?: return null
|
||||
|
||||
if (paramType.hasTypeParametersToAdd(functionDescriptor, context)) return null
|
||||
|
||||
return CreateParameterFromUsageFix(
|
||||
functionDescriptor,
|
||||
context,
|
||||
JetParameterInfo(callableDescriptor = functionDescriptor,
|
||||
name = refExpr.getReferencedName(),
|
||||
type = paramType,
|
||||
valOrVar = valOrVar),
|
||||
refExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun JetType.hasTypeParametersToAdd(functionDescriptor: FunctionDescriptor, context: BindingContext): Boolean {
|
||||
val typeParametersToAdd = LinkedHashSet(getTypeParameters())
|
||||
typeParametersToAdd.removeAll(functionDescriptor.getTypeParameters())
|
||||
if (typeParametersToAdd.isEmpty()) return false
|
||||
|
||||
val scope = when(functionDescriptor) {
|
||||
is ConstructorDescriptor -> {
|
||||
val classDescriptor = functionDescriptor.getContainingDeclaration() as? ClassDescriptorWithResolutionScopes
|
||||
classDescriptor?.getScopeForClassHeaderResolution()
|
||||
}
|
||||
|
||||
is FunctionDescriptor -> {
|
||||
val function = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) as? JetFunction
|
||||
function?.let { context[BindingContext.RESOLUTION_SCOPE, it.getBodyExpression()] }
|
||||
}
|
||||
|
||||
else -> null
|
||||
} ?: return true
|
||||
|
||||
return typeParametersToAdd.any { scope.getClassifier(it.getName()) != it }
|
||||
}
|
||||
+24
-25
@@ -16,40 +16,38 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable
|
||||
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
|
||||
import org.jetbrains.kotlin.psi.JetValueArgument
|
||||
import org.jetbrains.kotlin.psi.JetCallElement
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.psi.JetFunction
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
|
||||
public object CreateParameterByNamedArgumentActionFactory: JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val result = (diagnostic.getPsiFile() as? JetFile)?.analyzeFullyAndGetResult() ?: return null
|
||||
public object CreateParameterByNamedArgumentActionFactory: CreateParameterFromUsageFactory<JetValueArgument>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetValueArgument? {
|
||||
val argument = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetValueArgument>()) ?: return null
|
||||
return if (argument.isNamed()) argument else null
|
||||
}
|
||||
|
||||
override fun createQuickFixData(element: JetValueArgument, diagnostic: Diagnostic): CreateParameterData<JetValueArgument>? {
|
||||
val result = (diagnostic.psiFile as? JetFile)?.analyzeFullyAndGetResult() ?: return null
|
||||
val context = result.bindingContext
|
||||
|
||||
val argument = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetValueArgument>()) ?: return null
|
||||
val name = argument.getArgumentName()?.getText() ?: return null
|
||||
val argumentExpression = argument.getArgumentExpression()
|
||||
val name = element.getArgumentName()?.text ?: return null
|
||||
val argumentExpression = element.getArgumentExpression()
|
||||
|
||||
val callElement = argument.getStrictParentOfType<JetCallElement>() ?: return null
|
||||
val functionDescriptor = callElement.getResolvedCall(context)?.getResultingDescriptor() as? FunctionDescriptor ?: return null
|
||||
val callable = DescriptorToSourceUtilsIde.getAnyDeclaration(callElement.getProject(), functionDescriptor) ?: return null
|
||||
val callElement = element.getStrictParentOfType<JetCallElement>() ?: return null
|
||||
val functionDescriptor = callElement.getResolvedCall(context)?.resultingDescriptor as? FunctionDescriptor ?: return null
|
||||
val callable = DescriptorToSourceUtilsIde.getAnyDeclaration(callElement.project, functionDescriptor) ?: return null
|
||||
if (!((callable is JetFunction || callable is JetClass) && callable.canRefactor())) return null
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getAnyType()
|
||||
val anyType = KotlinBuiltIns.getInstance().anyType
|
||||
val paramType = argumentExpression?.guessTypes(context, result.moduleDescriptor)?.let {
|
||||
when (it.size()) {
|
||||
0 -> anyType
|
||||
@@ -65,6 +63,7 @@ public object CreateParameterByNamedArgumentActionFactory: JetSingleIntentionAct
|
||||
type = paramType,
|
||||
defaultValueForCall = argumentExpression
|
||||
)
|
||||
return CreateParameterFromUsageFix(functionDescriptor, context, parameterInfo, argument)
|
||||
|
||||
return CreateParameterData(context, parameterInfo, element)
|
||||
}
|
||||
}
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage.createVariable
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getTypeParameters
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetValVar
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.util.LinkedHashSet
|
||||
|
||||
object CreateParameterByRefActionFactory : CreateParameterFromUsageFactory<JetSimpleNameExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): JetSimpleNameExpression? {
|
||||
val refExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetSimpleNameExpression>()) ?: return null
|
||||
if (refExpr.getQualifiedElement() != refExpr) return null
|
||||
return refExpr
|
||||
}
|
||||
|
||||
override fun createQuickFixData(
|
||||
element: JetSimpleNameExpression,
|
||||
diagnostic: Diagnostic
|
||||
): CreateParameterData<JetSimpleNameExpression>? {
|
||||
val result = (diagnostic.psiFile as? JetFile)?.analyzeFullyAndGetResult() ?: return null
|
||||
val context = result.bindingContext
|
||||
|
||||
val varExpected = element.getAssignmentByLHS() != null
|
||||
|
||||
val paramType = element.getExpressionForTypeGuess().guessTypes(context, result.moduleDescriptor).let {
|
||||
when (it.size()) {
|
||||
0 -> KotlinBuiltIns.getInstance().anyType
|
||||
1 -> it.first()
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
var valOrVar: JetValVar = JetValVar.None
|
||||
|
||||
fun chooseContainingClass(it: PsiElement): JetClass? {
|
||||
valOrVar = if (varExpected) JetValVar.Var else JetValVar.Val
|
||||
return it.parents.firstIsInstanceOrNull<JetClassOrObject>() as? JetClass
|
||||
}
|
||||
|
||||
// todo: skip lambdas for now because Change Signature doesn't apply to them yet
|
||||
val container = element.parents
|
||||
.filter {
|
||||
it is JetNamedFunction || it is JetPropertyAccessor || it is JetClassBody || it is JetClassInitializer ||
|
||||
it is JetDelegationSpecifier
|
||||
}
|
||||
.firstOrNull()
|
||||
?.let {
|
||||
when {
|
||||
it is JetNamedFunction && varExpected,
|
||||
it is JetPropertyAccessor -> chooseContainingClass(it)
|
||||
it is JetClassInitializer -> it.parent?.parent as? JetClass
|
||||
it is JetDelegationSpecifier -> {
|
||||
val klass = it.getStrictParentOfType<JetClass>()
|
||||
if (klass != null && !klass.isInterface() && klass !is JetEnumEntry) klass else null
|
||||
}
|
||||
it is JetClassBody -> {
|
||||
val klass = it.parent as? JetClass
|
||||
when {
|
||||
klass is JetEnumEntry -> chooseContainingClass(klass)
|
||||
klass != null && klass.isInterface() -> null
|
||||
else -> klass
|
||||
}
|
||||
}
|
||||
else -> it
|
||||
}
|
||||
} ?: return null
|
||||
|
||||
val functionDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, container]?.let {
|
||||
if (it is ClassDescriptor) it.unsubstitutedPrimaryConstructor else it
|
||||
} as? FunctionDescriptor ?: return null
|
||||
|
||||
if (paramType.hasTypeParametersToAdd(functionDescriptor, context)) return null
|
||||
|
||||
return CreateParameterData(
|
||||
context,
|
||||
JetParameterInfo(callableDescriptor = functionDescriptor,
|
||||
name = element.getReferencedName(),
|
||||
type = paramType,
|
||||
valOrVar = valOrVar),
|
||||
element
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun JetType.hasTypeParametersToAdd(functionDescriptor: FunctionDescriptor, context: BindingContext): Boolean {
|
||||
val typeParametersToAdd = LinkedHashSet(getTypeParameters())
|
||||
typeParametersToAdd.removeAll(functionDescriptor.typeParameters)
|
||||
if (typeParametersToAdd.isEmpty()) return false
|
||||
|
||||
val scope =
|
||||
when (functionDescriptor) {
|
||||
is ConstructorDescriptor -> {
|
||||
(functionDescriptor.containingDeclaration as? ClassDescriptorWithResolutionScopes)?.scopeForClassHeaderResolution
|
||||
}
|
||||
|
||||
is FunctionDescriptor -> {
|
||||
val function = functionDescriptor.source.getPsi() as? JetFunction
|
||||
function?.let { context[BindingContext.RESOLUTION_SCOPE, it.bodyExpression] }
|
||||
}
|
||||
|
||||
else -> null
|
||||
} ?: return true
|
||||
|
||||
return typeParametersToAdd.any { scope.getClassifier(it.name) != it }
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage.createVariable
|
||||
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.quickfix.NullQuickFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFactory
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetParameterInfo
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
data class CreateParameterData<E : JetElement>(
|
||||
val context: BindingContext,
|
||||
val parameterInfo: JetParameterInfo,
|
||||
val originalExpression: E
|
||||
)
|
||||
|
||||
abstract class CreateParameterFromUsageFactory<E : JetElement>: CreateFromUsageFactory<E, CreateParameterData<E>?>() {
|
||||
override fun createQuickFix(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
diagnostic: Diagnostic,
|
||||
quickFixDataFactory: (SmartPsiElementPointer<E>) -> CreateParameterData<E>?
|
||||
): QuickFixWithDelegateFactory? {
|
||||
return QuickFixWithDelegateFactory {
|
||||
quickFixDataFactory(originalElementPointer)?.let { data ->
|
||||
CreateParameterFromUsageFix(data.parameterInfo.callableDescriptor as FunctionDescriptor,
|
||||
data.context,
|
||||
data.parameterInfo,
|
||||
data.originalExpression)
|
||||
} ?: NullQuickFix
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -27,14 +27,14 @@ import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
public class CreateParameterFromUsageFix(
|
||||
public class CreateParameterFromUsageFix<E : JetElement>(
|
||||
val functionDescriptor: FunctionDescriptor,
|
||||
val bindingContext: BindingContext,
|
||||
val parameterInfo: JetParameterInfo,
|
||||
val defaultValueContext: JetElement
|
||||
) : CreateFromUsageFixBase(defaultValueContext) {
|
||||
val defaultValueContext: E
|
||||
) : CreateFromUsageFixBase<E>(defaultValueContext) {
|
||||
override fun getText(): String {
|
||||
return JetBundle.message("create.parameter.from.usage", parameterInfo.getName())
|
||||
return JetBundle.message("create.parameter.from.usage", parameterInfo.name)
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
@@ -46,6 +46,6 @@ public class CreateParameterFromUsageFix(
|
||||
override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean = false
|
||||
}
|
||||
|
||||
runChangeSignature(project, functionDescriptor, config, bindingContext, defaultValueContext, getText())
|
||||
runChangeSignature(project, functionDescriptor, config, bindingContext, defaultValueContext, text)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user