Converting to Kotlin (step 2)
This commit is contained in:
+78
-100
@@ -14,147 +14,125 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix;
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
import com.intellij.codeInsight.intention.IntentionAction;
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.util.IncorrectOperationException;
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.idea.project.platform
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle;
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
|
||||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.idea.util.ShortenReferences;
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import java.util.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
|
||||||
import org.jetbrains.kotlin.types.TypeProjection;
|
|
||||||
import org.jetbrains.kotlin.types.TypeUtils;
|
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
class ChangeFunctionLiteralReturnTypeFix(functionLiteralExpression: KtLambdaExpression, private val type: KotlinType) : KotlinQuickFixAction<KtLambdaExpression>(functionLiteralExpression) {
|
||||||
import java.util.List;
|
private val functionLiteralReturnTypeRef: KtTypeReference?
|
||||||
|
private var appropriateQuickFix: IntentionAction? = null
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.idea.project.PlatformKt.getPlatform;
|
init {
|
||||||
|
functionLiteralReturnTypeRef = functionLiteralExpression.functionLiteral.typeReference
|
||||||
|
|
||||||
public class ChangeFunctionLiteralReturnTypeFix extends KotlinQuickFixAction<KtLambdaExpression> {
|
doInit(functionLiteralExpression)
|
||||||
private final KotlinType type;
|
}
|
||||||
private final KtTypeReference functionLiteralReturnTypeRef;
|
|
||||||
private IntentionAction appropriateQuickFix = null;
|
|
||||||
|
|
||||||
public ChangeFunctionLiteralReturnTypeFix(@NotNull KtLambdaExpression functionLiteralExpression, @NotNull KotlinType type) {
|
private fun doInit(functionLiteralExpression: KtLambdaExpression) {
|
||||||
super(functionLiteralExpression);
|
val analysisResult = functionLiteralExpression.getContainingKtFile().analyzeFullyAndGetResult()
|
||||||
this.type = type;
|
val context = analysisResult.bindingContext
|
||||||
functionLiteralReturnTypeRef = functionLiteralExpression.getFunctionLiteral().getTypeReference();
|
val functionLiteralType = context.getType(functionLiteralExpression) ?: error("Type of function literal not available in binding context")
|
||||||
|
|
||||||
AnalysisResult analysisResult = ResolutionUtils.analyzeFullyAndGetResult(functionLiteralExpression.getContainingKtFile());
|
val builtIns = analysisResult.moduleDescriptor.builtIns
|
||||||
BindingContext context = analysisResult.getBindingContext();
|
val functionClass = builtIns.getFunction(functionLiteralType.arguments.size - 1)
|
||||||
KotlinType functionLiteralType = context.getType(functionLiteralExpression);
|
val functionClassTypeParameters = LinkedList<KotlinType>()
|
||||||
assert functionLiteralType != null : "Type of function literal not available in binding context";
|
for (typeProjection in functionLiteralType.arguments) {
|
||||||
|
functionClassTypeParameters.add(typeProjection.type)
|
||||||
KotlinBuiltIns builtIns = analysisResult.getModuleDescriptor().getBuiltIns();
|
|
||||||
ClassDescriptor functionClass = builtIns.getFunction(functionLiteralType.getArguments().size() - 1);
|
|
||||||
List<KotlinType> functionClassTypeParameters = new LinkedList<KotlinType>();
|
|
||||||
for (TypeProjection typeProjection: functionLiteralType.getArguments()) {
|
|
||||||
functionClassTypeParameters.add(typeProjection.getType());
|
|
||||||
}
|
}
|
||||||
// Replacing return type:
|
// Replacing return type:
|
||||||
functionClassTypeParameters.remove(functionClassTypeParameters.size() - 1);
|
functionClassTypeParameters.removeAt(functionClassTypeParameters.size - 1)
|
||||||
functionClassTypeParameters.add(type);
|
functionClassTypeParameters.add(type)
|
||||||
KotlinType eventualFunctionLiteralType = TypeUtils.substituteParameters(functionClass, functionClassTypeParameters);
|
val eventualFunctionLiteralType = TypeUtils.substituteParameters(functionClass, functionClassTypeParameters)
|
||||||
|
|
||||||
KtProperty correspondingProperty = PsiTreeUtil.getParentOfType(functionLiteralExpression, KtProperty.class);
|
val correspondingProperty = PsiTreeUtil.getParentOfType(functionLiteralExpression, KtProperty::class.java)
|
||||||
if (correspondingProperty != null && QuickFixUtil.canEvaluateTo(correspondingProperty.getInitializer(), functionLiteralExpression)) {
|
if (correspondingProperty != null && QuickFixUtil.canEvaluateTo(correspondingProperty.initializer!!, functionLiteralExpression)) {
|
||||||
KtTypeReference correspondingPropertyTypeRef = correspondingProperty.getTypeReference();
|
val correspondingPropertyTypeRef = correspondingProperty.typeReference
|
||||||
KotlinType propertyType = context.get(BindingContext.TYPE, correspondingPropertyTypeRef);
|
val propertyType = context.get(BindingContext.TYPE, correspondingPropertyTypeRef)
|
||||||
if (propertyType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, propertyType)) {
|
if (propertyType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, propertyType)) {
|
||||||
appropriateQuickFix = new ChangeVariableTypeFix(correspondingProperty, eventualFunctionLiteralType);
|
appropriateQuickFix = ChangeVariableTypeFix(correspondingProperty, eventualFunctionLiteralType)
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt.getParentResolvedCall(
|
val resolvedCall = functionLiteralExpression.getParentResolvedCall(context, true)
|
||||||
functionLiteralExpression, context, true);
|
|
||||||
if (resolvedCall != null) {
|
if (resolvedCall != null) {
|
||||||
ValueArgument valueArgument = CallUtilKt.getValueArgumentForExpression(resolvedCall.getCall(), functionLiteralExpression);
|
val valueArgument = resolvedCall.call.getValueArgumentForExpression(functionLiteralExpression)
|
||||||
KtParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument);
|
val correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument)
|
||||||
if (correspondingParameter != null) {
|
if (correspondingParameter != null) {
|
||||||
KtTypeReference correspondingParameterTypeRef = correspondingParameter.getTypeReference();
|
val correspondingParameterTypeRef = correspondingParameter.typeReference
|
||||||
KotlinType parameterType = context.get(BindingContext.TYPE, correspondingParameterTypeRef);
|
val parameterType = context.get(BindingContext.TYPE, correspondingParameterTypeRef)
|
||||||
if (parameterType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parameterType)) {
|
if (parameterType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parameterType)) {
|
||||||
appropriateQuickFix = new ChangeParameterTypeFix(correspondingParameter, eventualFunctionLiteralType);
|
appropriateQuickFix = ChangeParameterTypeFix(correspondingParameter, eventualFunctionLiteralType)
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KtFunction parentFunction = PsiTreeUtil.getParentOfType(functionLiteralExpression, KtFunction.class, true);
|
val parentFunction = PsiTreeUtil.getParentOfType(functionLiteralExpression, KtFunction::class.java, true)
|
||||||
if (parentFunction != null && QuickFixUtil.canFunctionOrGetterReturnExpression(parentFunction, functionLiteralExpression)) {
|
if (parentFunction != null && QuickFixUtil.canFunctionOrGetterReturnExpression(parentFunction, functionLiteralExpression)) {
|
||||||
KtTypeReference parentFunctionReturnTypeRef = parentFunction.getTypeReference();
|
val parentFunctionReturnTypeRef = parentFunction.typeReference
|
||||||
KotlinType parentFunctionReturnType = context.get(BindingContext.TYPE, parentFunctionReturnTypeRef);
|
val parentFunctionReturnType = context.get(BindingContext.TYPE, parentFunctionReturnTypeRef)
|
||||||
if (parentFunctionReturnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parentFunctionReturnType)) {
|
if (parentFunctionReturnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parentFunctionReturnType)) {
|
||||||
appropriateQuickFix = new ChangeFunctionReturnTypeFix(parentFunction, eventualFunctionLiteralType);
|
appropriateQuickFix = ChangeFunctionReturnTypeFix(parentFunction, eventualFunctionLiteralType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getText(): String {
|
||||||
@Override
|
|
||||||
public String getText() {
|
|
||||||
if (appropriateQuickFix != null) {
|
if (appropriateQuickFix != null) {
|
||||||
return appropriateQuickFix.getText();
|
return appropriateQuickFix!!.text
|
||||||
}
|
}
|
||||||
return String.format("Change lambda expression return type to '%s'",
|
return String.format("Change lambda expression return type to '%s'",
|
||||||
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type));
|
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type))
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getFamilyName(): String {
|
||||||
@Override
|
return KotlinBundle.message("change.type.family")
|
||||||
public String getFamilyName() {
|
|
||||||
return KotlinBundle.message("change.type.family");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiFile file) {
|
return super.isAvailable(project, editor, file) && (functionLiteralReturnTypeRef != null || appropriateQuickFix != null && appropriateQuickFix!!.isAvailable(project, editor!!, file))
|
||||||
return super.isAvailable(project, editor, file) &&
|
|
||||||
(functionLiteralReturnTypeRef != null || (appropriateQuickFix != null && appropriateQuickFix.isAvailable(project, editor, file)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
public void invoke(@NotNull Project project, Editor editor, @NotNull KtFile file) throws IncorrectOperationException {
|
|
||||||
if (functionLiteralReturnTypeRef != null) {
|
if (functionLiteralReturnTypeRef != null) {
|
||||||
KtTypeReference newTypeRef = KtPsiFactoryKt.KtPsiFactory(file).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type));
|
var newTypeRef = KtPsiFactory(file).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type))
|
||||||
newTypeRef = (KtTypeReference) functionLiteralReturnTypeRef.replace(newTypeRef);
|
newTypeRef = functionLiteralReturnTypeRef.replace(newTypeRef) as KtTypeReference
|
||||||
ShortenReferences.DEFAULT.process(newTypeRef);
|
ShortenReferences.DEFAULT.process(newTypeRef)
|
||||||
}
|
}
|
||||||
if (appropriateQuickFix != null && appropriateQuickFix.isAvailable(project, editor, file)) {
|
if (appropriateQuickFix != null && appropriateQuickFix!!.isAvailable(project, editor!!, file)) {
|
||||||
appropriateQuickFix.invoke(project, editor, file);
|
appropriateQuickFix!!.invoke(project, editor, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
companion object {
|
||||||
public static KotlinSingleIntentionActionFactory createFactoryForExpectedOrAssignmentTypeMismatch() {
|
fun createFactoryForExpectedOrAssignmentTypeMismatch(): KotlinSingleIntentionActionFactory {
|
||||||
return new KotlinSingleIntentionActionFactory() {
|
return object : KotlinSingleIntentionActionFactory() {
|
||||||
@Nullable
|
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
@Override
|
val functionLiteralExpression = QuickFixUtil.getParentElementOfType(diagnostic, KtLambdaExpression::class.java) ?: return null
|
||||||
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
|
return ChangeFunctionLiteralReturnTypeFix(functionLiteralExpression, functionLiteralExpression.platform.builtIns.getUnitType())
|
||||||
KtLambdaExpression
|
}
|
||||||
functionLiteralExpression = QuickFixUtil.getParentElementOfType(diagnostic, KtLambdaExpression.class);
|
|
||||||
if (functionLiteralExpression == null) return null;
|
|
||||||
return new ChangeFunctionLiteralReturnTypeFix(functionLiteralExpression, getPlatform(functionLiteralExpression).getBuiltIns().getUnitType());
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user