Converting to Kotlin (step 2)

This commit is contained in:
Valentin Kipyatkov
2016-03-28 19:06:38 +03:00
parent 9c18409966
commit eb918db3af
@@ -14,170 +14,134 @@
* 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.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.KotlinBundle;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.idea.util.ShortenReferences;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import java.util.*
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
class ChangeVariableTypeFix(element: KtVariableDeclaration, private val type: KotlinType) : KotlinQuickFixAction<KtVariableDeclaration>(element) {
public class ChangeVariableTypeFix extends KotlinQuickFixAction<KtVariableDeclaration> {
private final KotlinType type;
public ChangeVariableTypeFix(@NotNull KtVariableDeclaration element, @NotNull KotlinType type) {
super(element);
this.type = type;
override fun getText(): String {
var propertyName = element.fqName?.asString() ?: element.name
return KotlinBundle.message("change.element.type", propertyName, IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type))
}
@NotNull
@Override
public String getText() {
String propertyName = getElement().getName();
FqName fqName = getElement().getFqName();
if (fqName != null) propertyName = fqName.asString();
return KotlinBundle
.message("change.element.type", propertyName, IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type));
override fun getFamilyName(): String {
return KotlinBundle.message("change.type.family")
}
@NotNull
@Override
public String getFamilyName() {
return KotlinBundle.message("change.type.family");
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
return super.isAvailable(project, editor, file) && !ErrorUtils.containsErrorType(type)
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiFile file) {
return super.isAvailable(project, editor, file) && !ErrorUtils.containsErrorType(type);
}
@Throws(IncorrectOperationException::class)
public override operator fun invoke(project: Project, editor: Editor?, file: KtFile) {
val psiFactory = KtPsiFactory(file)
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull KtFile file) throws IncorrectOperationException {
KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(file);
val nameIdentifier = element.nameIdentifier ?: error("ChangeVariableTypeFix applied to variable without name")
PsiElement nameIdentifier = getElement().getNameIdentifier();
assert nameIdentifier != null : "ChangeVariableTypeFix applied to variable without name";
val replacingTypeReference = psiFactory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type))
val toShorten = ArrayList<KtTypeReference>()
toShorten.add(element.setTypeReference(replacingTypeReference)!!)
KtTypeReference replacingTypeReference = psiFactory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type));
List<KtTypeReference> toShorten = new ArrayList<KtTypeReference>();
toShorten.add(getElement().setTypeReference(replacingTypeReference));
if (getElement() instanceof KtProperty) {
KtPropertyAccessor getter = ((KtProperty) getElement()).getGetter();
KtTypeReference getterReturnTypeRef = getter == null ? null : getter.getReturnTypeReference();
if (element is KtProperty) {
val getter = element.getter
val getterReturnTypeRef = getter?.returnTypeReference
if (getterReturnTypeRef != null) {
toShorten.add((KtTypeReference) getterReturnTypeRef.replace(replacingTypeReference));
toShorten.add(getterReturnTypeRef.replace(replacingTypeReference) as KtTypeReference)
}
KtPropertyAccessor setter = ((KtProperty) getElement()).getSetter();
KtParameter setterParameter = setter == null ? null : setter.getParameter();
KtTypeReference setterParameterTypeRef = setterParameter == null ? null : setterParameter.getTypeReference();
val setter = element.setter
val setterParameter = setter?.parameter
val setterParameterTypeRef = setterParameter?.typeReference
if (setterParameterTypeRef != null) {
toShorten.add((KtTypeReference) setterParameterTypeRef.replace(replacingTypeReference));
toShorten.add(setterParameterTypeRef.replace(replacingTypeReference) as KtTypeReference)
}
}
ShortenReferences.DEFAULT.process(toShorten);
ShortenReferences.DEFAULT.process(toShorten)
}
@NotNull
public static KotlinSingleIntentionActionFactory createFactoryForComponentFunctionReturnTypeMismatch() {
return new KotlinSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
KtDestructuringDeclarationEntry
entry = ChangeFunctionReturnTypeFix.getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic);
BindingContext context = ResolutionUtils.analyze(entry);
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
if (resolvedCall == null) return null;
KtFunction componentFunction = (KtFunction) DescriptorToSourceUtils
.descriptorToDeclaration(resolvedCall.getCandidateDescriptor());
if (componentFunction == null) return null;
KotlinType expectedType = resolvedCall.getCandidateDescriptor().getReturnType();
return expectedType == null ? null : new ChangeVariableTypeFix(entry, expectedType);
}
};
}
companion object {
@NotNull
public static KotlinIntentionActionsFactory createFactoryForPropertyOrReturnTypeMismatchOnOverride() {
return new KotlinIntentionActionsFactory() {
@NotNull
@Override
protected List<IntentionAction> doCreateActions(@NotNull Diagnostic diagnostic) {
List<IntentionAction> actions = new LinkedList<IntentionAction>();
if (diagnostic.getPsiElement() instanceof KtProperty) {
KtProperty property = (KtProperty) diagnostic.getPsiElement();
DeclarationDescriptor descriptor = ResolutionUtils.resolveToDescriptor(property);
if (!(descriptor instanceof PropertyDescriptor)) return actions;
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
KotlinType
lowerBoundOfOverriddenPropertiesTypes = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(propertyDescriptor);
KotlinType propertyType = propertyDescriptor.getReturnType();
assert propertyType != null : "Property type cannot be null if it mismatch something";
List<PropertyDescriptor> overriddenMismatchingProperties = new LinkedList<PropertyDescriptor>();
boolean canChangeOverriddenPropertyType = true;
for (PropertyDescriptor overriddenProperty: propertyDescriptor.getOverriddenDescriptors()) {
KotlinType overriddenPropertyType = overriddenProperty.getReturnType();
if (overriddenPropertyType != null) {
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(propertyType, overriddenPropertyType)) {
overriddenMismatchingProperties.add(overriddenProperty);
}
else if (overriddenProperty.isVar() && !KotlinTypeChecker.DEFAULT.equalTypes(overriddenPropertyType, propertyType)) {
canChangeOverriddenPropertyType = false;
}
if (overriddenProperty.isVar() && lowerBoundOfOverriddenPropertiesTypes != null &&
!KotlinTypeChecker.DEFAULT.equalTypes(lowerBoundOfOverriddenPropertiesTypes, overriddenPropertyType)) {
lowerBoundOfOverriddenPropertiesTypes = null;
}
}
}
if (lowerBoundOfOverriddenPropertiesTypes != null) {
actions.add(new ChangeVariableTypeFix(property, lowerBoundOfOverriddenPropertiesTypes));
}
if (overriddenMismatchingProperties.size() == 1 && canChangeOverriddenPropertyType) {
PsiElement overriddenProperty = DescriptorToSourceUtils
.descriptorToDeclaration(overriddenMismatchingProperties.get(0));
if (overriddenProperty instanceof KtProperty) {
actions.add(new ChangeVariableTypeFix((KtProperty) overriddenProperty, propertyType));
}
}
fun createFactoryForComponentFunctionReturnTypeMismatch(): KotlinSingleIntentionActionFactory {
return object : KotlinSingleIntentionActionFactory() {
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val entry = ChangeFunctionReturnTypeFix.getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic)
val context = entry.analyze()
val resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) ?: return null
val componentFunction = DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as KtFunction? ?: return null
val expectedType = resolvedCall.candidateDescriptor.returnType
return if (expectedType == null) null else ChangeVariableTypeFix(entry, expectedType)
}
return actions;
}
};
}
fun createFactoryForPropertyOrReturnTypeMismatchOnOverride(): KotlinIntentionActionsFactory {
return object : KotlinIntentionActionsFactory() {
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val actions = LinkedList<IntentionAction>()
if (diagnostic.psiElement is KtProperty) {
val property = diagnostic.psiElement as KtProperty
val descriptor = property.resolveToDescriptor()
if (descriptor !is PropertyDescriptor) return actions
var lowerBoundOfOverriddenPropertiesTypes = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(descriptor)
val propertyType = descriptor.returnType ?: error("Property type cannot be null if it mismatch something")
val overriddenMismatchingProperties = LinkedList<PropertyDescriptor>()
var canChangeOverriddenPropertyType = true
for (overriddenProperty in descriptor.overriddenDescriptors) {
val overriddenPropertyType = overriddenProperty.returnType
if (overriddenPropertyType != null) {
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(propertyType!!, overriddenPropertyType)) {
overriddenMismatchingProperties.add(overriddenProperty)
}
else if (overriddenProperty.isVar && !KotlinTypeChecker.DEFAULT.equalTypes(overriddenPropertyType, propertyType)) {
canChangeOverriddenPropertyType = false
}
if (overriddenProperty.isVar && lowerBoundOfOverriddenPropertiesTypes != null &&
!KotlinTypeChecker.DEFAULT.equalTypes(lowerBoundOfOverriddenPropertiesTypes, overriddenPropertyType)) {
lowerBoundOfOverriddenPropertiesTypes = null
}
}
}
if (lowerBoundOfOverriddenPropertiesTypes != null) {
actions.add(ChangeVariableTypeFix(property, lowerBoundOfOverriddenPropertiesTypes))
}
if (overriddenMismatchingProperties.size == 1 && canChangeOverriddenPropertyType) {
val overriddenProperty = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingProperties[0])
if (overriddenProperty is KtProperty) {
actions.add(ChangeVariableTypeFix(overriddenProperty, propertyType!!))
}
}
}
return actions
}
}
}
}
}