blob: 052d27ab66c06e147df98ba1cc985fd8e6c16ac1 [file] [log] [blame]
/*
* Copyright 2000-2011 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 com.intellij.refactoring.typeMigration.rules;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
/**
* @author anna
* Date: 08-Aug-2008
*/
public class RootTypeConversionRule extends TypeConversionRule {
public TypeConversionDescriptorBase findConversion(final PsiType from,
final PsiType to,
final PsiMember member,
final PsiExpression context,
final TypeMigrationLabeler labeler) {
if (to instanceof PsiClassType && from instanceof PsiClassType) {
final PsiClass targetClass = ((PsiClassType)to).resolve();
if (targetClass != null && member instanceof PsiMethod && member.isPhysical()) {
PsiMethod method = (PsiMethod)member;
PsiMethod replacer = targetClass.findMethodBySignature(method, true);
if (replacer == null) {
for (PsiMethod superMethod : method.findDeepestSuperMethods()) {
replacer = targetClass.findMethodBySignature(superMethod, true);
if (replacer != null) {
method = superMethod;
break;
}
}
}
if (replacer != null && TypeConversionUtil.areTypesConvertible(method.getReturnType(), replacer.getReturnType())) {
final PsiElement parent = context.getParent();
if (context instanceof PsiReferenceExpression && parent instanceof PsiMethodCallExpression) {
final JavaResolveResult resolveResult = ((PsiReferenceExpression)context).advancedResolve(false);
final PsiSubstitutor aSubst;
final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)parent).getMethodExpression();
final PsiExpression qualifier = methodExpression.getQualifierExpression();
final PsiClass substitutionClass = method.getContainingClass();
if (qualifier != null) {
final PsiType evaluatedQualifierType = labeler.getTypeEvaluator().evaluateType(qualifier);
if (evaluatedQualifierType instanceof PsiClassType) {
aSubst = ((PsiClassType)evaluatedQualifierType).resolveGenerics().getSubstitutor();
}
else {
aSubst = PsiSubstitutor.EMPTY;
}
}
else {
aSubst = TypeConversionUtil.getClassSubstitutor(member.getContainingClass(), substitutionClass, PsiSubstitutor.EMPTY);
}
final PsiParameter[] originalParams = ((PsiMethod)member).getParameterList().getParameters();
final PsiParameter[] migrationParams = replacer.getParameterList().getParameters();
final PsiExpression[] actualParams = ((PsiMethodCallExpression)parent).getArgumentList().getExpressions();
assert originalParams.length == migrationParams.length;
final PsiSubstitutor methodTypeParamsSubstitutor =
labeler.getTypeEvaluator().createMethodSubstitution(originalParams, actualParams, method, context, aSubst != null ? aSubst : PsiSubstitutor.EMPTY, true);
for (int i = 0; i < originalParams.length; i++) {
final PsiType originalType = resolveResult.getSubstitutor().substitute(originalParams[i].getType());
PsiType type = migrationParams[i].getType();
if (InheritanceUtil.isInheritorOrSelf(targetClass, substitutionClass, true)) {
final PsiSubstitutor superClassSubstitutor =
TypeConversionUtil.getClassSubstitutor(substitutionClass, targetClass, PsiSubstitutor.EMPTY);
assert (superClassSubstitutor != null);
type = superClassSubstitutor.substitute(type);
}
final PsiType migrationType = methodTypeParamsSubstitutor.substitute(type);
if (!originalType.equals(migrationType) && !TypeConversionUtil.areTypesAssignmentCompatible(migrationType, actualParams[i])) {
labeler.migrateExpressionType(actualParams[i], migrationType, context, false, true);
}
}
}
return new TypeConversionDescriptorBase();
}
}
}
return null;
}
}