diff --git a/openapi/src/com/intellij/psi/GenericsUtil.java b/openapi/src/com/intellij/psi/GenericsUtil.java index befe6e9d6b69..0776a7e1164c 100644 --- a/openapi/src/com/intellij/psi/GenericsUtil.java +++ b/openapi/src/com/intellij/psi/GenericsUtil.java @@ -172,32 +172,4 @@ public class GenericsUtil { return type.getInternalCanonicalText().equals(type.getCanonicalText()); } - public static PsiClass[] getGreatestLowerClasses(final PsiClass aClass, final PsiClass bClass) { - if (InheritanceUtil.isInheritorOrSelf(aClass, bClass, true)) { - return new PsiClass[]{aClass}; - } - - if (InheritanceUtil.isInheritorOrSelf(bClass, aClass, true)) { - return new PsiClass[]{bClass}; - } - - final Set descendants = new LinkedHashSet(); - - new Object() { - public void getGreatestLowerClasses(final PsiClass aClass, final PsiClass bClass, final Set descendants) { - if (aClass.isInheritor(bClass, true)) { - descendants.add(bClass); - } - else { - final PsiSearchHelper helper = aClass.getManager().getSearchHelper(); - final PsiClass[] bSubs = helper.findInheritors(bClass, helper.getUseScope(bClass), true); - for (int i = 0; i < bSubs.length; i++) { - getLeastUpperClassesInner(bSubs[i], aClass, descendants); - } - } - } - }.getGreatestLowerClasses(aClass, bClass, descendants); - - return descendants.toArray(new PsiClass[descendants.size()]); - } } diff --git a/source/com/intellij/refactoring/typeCook/deductive/builder/System.java b/source/com/intellij/refactoring/typeCook/deductive/builder/System.java index 9903b62d068f..d547636f69f0 100644 --- a/source/com/intellij/refactoring/typeCook/deductive/builder/System.java +++ b/source/com/intellij/refactoring/typeCook/deductive/builder/System.java @@ -78,6 +78,10 @@ public class System { final PsiElement element = i.next(); final PsiType type = myTypes.get(element); + if (type == null){ + continue; + } + if (element instanceof PsiParameter) { final PsiParameter parm = (PsiParameter)element; final PsiMethod method = (PsiMethod)parm.getDeclarationScope(); @@ -429,7 +433,11 @@ public class System { for (final Iterator e = myElements.iterator(); e.hasNext();) { final PsiElement element = e.next(); - data[i++] = binding.substitute(myTypes.get(element)).getCanonicalText() + "\\n" + elementString(element); + final PsiType t = myTypes.get(element); + if (t != null) + data[i++] = binding.substitute(t).getCanonicalText() + "\\n" + elementString(element); + else + data[i++] = "\\n" + elementString(element); } Arrays.sort(data, diff --git a/source/com/intellij/refactoring/typeCook/deductive/builder/SystemBuilder.java b/source/com/intellij/refactoring/typeCook/deductive/builder/SystemBuilder.java index 42a88f8ed00c..6f91200e3896 100644 --- a/source/com/intellij/refactoring/typeCook/deductive/builder/SystemBuilder.java +++ b/source/com/intellij/refactoring/typeCook/deductive/builder/SystemBuilder.java @@ -33,6 +33,7 @@ public class SystemBuilder { private PsiManager myManager; private HashMap myMethodCache; private HashMap myParameters; + private HashMap myMethods; private HashMap mySuper; private HashMap myTypes; private HashSet myVisitedConstructions; @@ -46,6 +47,7 @@ public class SystemBuilder { mySettings = settings; myMethodCache = new HashMap(); myParameters = new HashMap(); + myMethods = new HashMap(); mySuper = new HashMap(); myTypes = new HashMap(); myVisitedConstructions = new HashSet(); @@ -95,16 +97,25 @@ public class SystemBuilder { keyMethod = superMethod; + myMethods.put(method, keyMethod); + if (parameter != null) { keyParameter = (PsiParameter)e; - myParameters.put(parameter, keyParameter); } } else { Boolean good = myMethodCache.get(method); - if (good != null) { - return good.booleanValue(); + if (good != null && good.booleanValue()) { + if (myMethods.get(method) == null) { + myMethods.put(method, method); + } + + if (parameter != null && myParameters.get(parameter) == null) { + myParameters.put(parameter, parameter); + } + + return true; } keyMethod = method; @@ -112,29 +123,35 @@ public class SystemBuilder { } final PsiMethod[] overriders = helper.findOverridingMethods(keyMethod, keyMethod.getUseScope(), true); - PsiMethod prev = keyMethod; for (int i = 0; i < overriders.length; i++) { - PsiMethod overrider = overriders[i]; - - if (prev != null) { - mySuper.put(overrider, prev); - prev = overrider; - } - - PsiElement e = - parameter == null ? (PsiElement)overrider : overrider.getParameterList().getParameters()[index]; + final PsiMethod overrider = overriders[i]; + final PsiElement e = parameter == null ? (PsiElement)overrider : overrider.getParameterList().getParameters()[index]; if (!victims.contains(e)) { myMethodCache.put(keyMethod, new Boolean(false)); return false; } + } + + for (int i = 0; i < overriders.length; i++) { + final PsiMethod overrider = overriders[i]; + final PsiElement e = parameter == null ? (PsiElement)overrider : overrider.getParameterList().getParameters()[index]; + + mySuper.put(overrider, keyMethod); + myMethods.put(overrider, keyMethod); if (parameter != null) { - myParameters.put(parameter, keyParameter); + myParameters.put((PsiParameter)e, keyParameter); } } + myMethods.put(method, keyMethod); + + if (parameter != null) { + myParameters.put(parameter, keyParameter); + } + myMethodCache.put(keyMethod, new Boolean(true)); return true; @@ -279,100 +296,106 @@ public class SystemBuilder { } else { final PsiType theType = - new Object() { - PsiType introduceAdditionalTypeVariables(final PsiType type, - final PsiSubstitutor qualifier, - final PsiSubstitutor supertype) { - final PsiClassType.ClassResolveResult result = Util.resolveType(type); - final PsiClass aClass = result.getElement(); + new Object() { + PsiType introduceAdditionalTypeVariables(final PsiType type, + final PsiSubstitutor qualifier, + final PsiSubstitutor supertype) { + final PsiClassType.ClassResolveResult result = Util.resolveType(type); + final PsiClass aClass = result.getElement(); - if (aClass != null) { - if (aClass instanceof PsiTypeParameter) { - final PsiTypeParameter tp = ((PsiTypeParameter)aClass); + if (aClass != null) { + if (aClass instanceof PsiTypeParameter) { + final PsiTypeParameter tp = ((PsiTypeParameter)aClass); + final PsiClassType[] extypes = tp.getExtendsListTypes(); - PsiType pv = mapping.get(tp); + PsiType pv = mapping.get(tp); - if (pv == null) { - pv = myTypeVariableFactory.create(); - mapping.put(tp, pv); - } - - return pv; + if (pv == null) { + pv = myTypeVariableFactory.create(); + mapping.put(tp, pv); } - final Map substitutionMap = result.getSubstitutor().getSubstitutionMap(); - - PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; - - for (Iterator t = substitutionMap.keySet().iterator(); t.hasNext();) { - final PsiTypeParameter p = t.next(); - final PsiType pType = substitutionMap.get(p); - - if (pType instanceof PsiWildcardType) { - final PsiWildcardType wildcard = ((PsiWildcardType)pType); - final PsiType theBound = wildcard.getBound(); - - if (theBound != null) { - final PsiType bound = Util.substituteType(Util.substituteType(theBound, supertype), qualifier); - - if (Util.bindsTypeVariables(bound)) { - final PsiType var = myTypeVariableFactory.create(); - - if (wildcard.isExtends()) { - system.addSubtypeConstraint(bound, var); - } - else { - system.addSubtypeConstraint(var, bound); - } - - theSubst = theSubst.put(p, var); - } - else if (Util.bindsTypeParameters(bound, typeParameters)) { - final PsiType var = myTypeVariableFactory.create(); - PsiSubstitutor subst = PsiSubstitutor.EMPTY; - - for (int i = 0; i < aTypeParms.length; i++) { - final PsiTypeParameter aTypeParm = aTypeParms[i]; - - PsiType parmVar = mapping.get(aTypeParm); - - if (parmVar == null) { - parmVar = myTypeVariableFactory.create(); - mapping.put(aTypeParm, parmVar); - } - - subst = subst.put(aTypeParm, parmVar); - } - - final PsiType bnd = Util.substituteType(bound, subst); - - if (wildcard.isExtends()) { - system.addSubtypeConstraint(bnd, var); - } - else { - system.addSubtypeConstraint(var, bnd); - } - - theSubst = theSubst.put(p, var); - } - else { - theSubst = theSubst.put(p, pType); - } - } - } - else { - theSubst = theSubst.put(p, introduceAdditionalTypeVariables(pType, qualifier, supertype)); - } + for (int j = 0; j < extypes.length; j++) { + final PsiType extype = Util.substituteType(extypes[j], qualifier); + system.addSubtypeConstraint(pv, extype); } - return aClass.getManager().getElementFactory().createType(aClass, theSubst); + return pv; } - return type; + final Map substitutionMap = result.getSubstitutor().getSubstitutionMap(); + + PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; + + for (Iterator t = substitutionMap.keySet().iterator(); t.hasNext();) { + final PsiTypeParameter p = t.next(); + final PsiType pType = substitutionMap.get(p); + + if (pType instanceof PsiWildcardType) { + final PsiWildcardType wildcard = ((PsiWildcardType)pType); + final PsiType theBound = wildcard.getBound(); + + if (theBound != null) { + final PsiType bound = Util.substituteType(Util.substituteType(theBound, supertype), qualifier); + + if (Util.bindsTypeVariables(bound)) { + final PsiType var = myTypeVariableFactory.create(); + + if (wildcard.isExtends()) { + system.addSubtypeConstraint(bound, var); + } + else { + system.addSubtypeConstraint(var, bound); + } + + theSubst = theSubst.put(p, var); + } + else if (Util.bindsTypeParameters(bound, typeParameters)) { + final PsiType var = myTypeVariableFactory.create(); + PsiSubstitutor subst = PsiSubstitutor.EMPTY; + + for (int i = 0; i < aTypeParms.length; i++) { + final PsiTypeParameter aTypeParm = aTypeParms[i]; + + PsiType parmVar = mapping.get(aTypeParm); + + if (parmVar == null) { + parmVar = myTypeVariableFactory.create(); + mapping.put(aTypeParm, parmVar); + } + + subst = subst.put(aTypeParm, parmVar); + } + + final PsiType bnd = Util.substituteType(bound, subst); + + if (wildcard.isExtends()) { + system.addSubtypeConstraint(bnd, var); + } + else { + system.addSubtypeConstraint(var, bnd); + } + + theSubst = theSubst.put(p, var); + } + else { + theSubst = theSubst.put(p, pType); + } + } + } + else { + theSubst = theSubst.put(p, introduceAdditionalTypeVariables(pType, qualifier, supertype)); + } + } + + return aClass.getManager().getElementFactory().createType(aClass, theSubst); } - }.introduceAdditionalTypeVariables( - Util.substituteType(Util.substituteType(parmType, supertypeSubstitutor), qualifierSubstitutor), qualifierSubstitutor, - supertypeSubstitutor); + + return type; + } + }.introduceAdditionalTypeVariables( + Util.substituteType(Util.substituteType(parmType, supertypeSubstitutor), qualifierSubstitutor), qualifierSubstitutor, + supertypeSubstitutor); system.addSubtypeConstraint(argumenType, theType); } @@ -575,6 +598,24 @@ public class SystemBuilder { } return; } + else if (element instanceof PsiMethod) { + final PsiType reType = getType(element); + + element.accept(new PsiRecursiveElementVisitor() { + public void visitReturnStatement(final PsiReturnStatement statement) { + super.visitReturnStatement(statement); + + final PsiExpression retExpr = statement.getReturnValue(); + + if (retExpr != null) { + system.addSubtypeConstraint(e.valuateType(retExpr), reType); + } + } + } + ); + + return; + } final PsiStatement root = (PsiStatement)PsiTreeUtil.getParentOfType(element, PsiStatement.class); @@ -583,63 +624,65 @@ public class SystemBuilder { if (!myVisitedConstructions.contains(anchor)) { root.accept(new PsiRecursiveElementVisitor() { - public void visitAssignmentExpression(final PsiAssignmentExpression expression) { - super.visitAssignmentExpression(expression); + public void visitAssignmentExpression(final PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); - system.addSubtypeConstraint(e.valuateType(expression.getRExpression()), e.valuateType(expression.getLExpression())); - } + system.addSubtypeConstraint(e.valuateType(expression.getRExpression()), e.valuateType(expression.getLExpression())); + } - public void visitConditionalExpression(final PsiConditionalExpression expression) { - super.visitConditionalExpression(expression); + public void visitConditionalExpression(final PsiConditionalExpression expression) { + super.visitConditionalExpression(expression); - system.addSubtypeConstraint(e.valuateType(expression.getThenExpression()), e.valuateType(expression.getElseExpression())); - system.addSubtypeConstraint(e.valuateType(expression.getElseExpression()), e.valuateType(expression.getThenExpression())); - } + system.addSubtypeConstraint(e.valuateType(expression.getThenExpression()), + e.valuateType(expression.getElseExpression())); + system.addSubtypeConstraint(e.valuateType(expression.getElseExpression()), + e.valuateType(expression.getThenExpression())); + } - public void visitMethodCallExpression(final PsiMethodCallExpression expression) { - super.visitMethodCallExpression(expression); - e.valuateType(expression); - } + public void visitMethodCallExpression(final PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + e.valuateType(expression); + } - public void visitReturnStatement(final PsiReturnStatement statement) { - super.visitReturnStatement(statement); + public void visitReturnStatement(final PsiReturnStatement statement) { + super.visitReturnStatement(statement); - final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class); + final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class); - if (method != null) { - system.addSubtypeConstraint(e.valuateType(statement.getReturnValue()), getType(method)); - } - } + if (method != null) { + system.addSubtypeConstraint(e.valuateType(statement.getReturnValue()), getType(method)); + } + } - public void visitTypeCastExpression(final PsiTypeCastExpression expression) { - super.visitTypeCastExpression(expression); + public void visitTypeCastExpression(final PsiTypeCastExpression expression) { + super.visitTypeCastExpression(expression); - system.addSubtypeConstraint(e.valuateType(expression.getOperand()), e.valuateType(expression)); - } + system.addSubtypeConstraint(e.valuateType(expression.getOperand()), e.valuateType(expression)); + } - public void visitNewExpression(final PsiNewExpression expression) { - super.visitNewExpression(expression); + public void visitNewExpression(final PsiNewExpression expression) { + super.visitNewExpression(expression); - final PsiArrayInitializerExpression init = expression.getArrayInitializer(); + final PsiArrayInitializerExpression init = expression.getArrayInitializer(); - if (init != null) { - final PsiExpression[] inits = init.getInitializers(); - final PsiType type = getType(expression); + if (init != null) { + final PsiExpression[] inits = init.getInitializers(); + final PsiType type = getType(expression); - for (int i = 0; i < inits.length; i++) { - system.addSubtypeConstraint(e.valuateType(inits[i]).createArrayType(), type); - } - } - } + for (int i = 0; i < inits.length; i++) { + system.addSubtypeConstraint(e.valuateType(inits[i]).createArrayType(), type); + } + } + } - public void visitReferenceExpression(final PsiReferenceExpression expression) { - final PsiExpression qualifierExpression = expression.getQualifierExpression(); + public void visitReferenceExpression(final PsiReferenceExpression expression) { + final PsiExpression qualifierExpression = expression.getQualifierExpression(); - if (qualifierExpression != null) { - qualifierExpression.accept(this); - } - } - }); + if (qualifierExpression != null) { + qualifierExpression.accept(this); + } + } + }); myVisitedConstructions.add(anchor); } @@ -673,47 +716,47 @@ public class SystemBuilder { if (definedType instanceof PsiTypeVariable) { for (int j = 0; j < extendsList.length; j++) { final PsiType extendsType = - new Object() { - PsiType replaceWildCards(final PsiType type) { - if (type instanceof PsiWildcardType) { - final PsiWildcardType wildcard = ((PsiWildcardType)type); - final PsiType var = myTypeVariableFactory.create(); - final PsiType bound = wildcard.getBound(); + new Object() { + PsiType replaceWildCards(final PsiType type) { + if (type instanceof PsiWildcardType) { + final PsiWildcardType wildcard = ((PsiWildcardType)type); + final PsiType var = myTypeVariableFactory.create(); + final PsiType bound = wildcard.getBound(); - if (bound != null) { - if (wildcard.isExtends()) { - system.addSubtypeConstraint(Util.substituteType(replaceWildCards(bound), definedSubst), var); - } - else { - system.addSubtypeConstraint(var, Util.substituteType(replaceWildCards(bound), definedSubst)); - } + if (bound != null) { + if (wildcard.isExtends()) { + system.addSubtypeConstraint(Util.banalize(Util.substituteType(replaceWildCards(bound), definedSubst)), var); } - - return var; - } - else if (type instanceof PsiClassType) { - final PsiClassType.ClassResolveResult result = Util.resolveType(type); - final PsiClass aClass = result.getElement(); - final PsiSubstitutor aSubst = result.getSubstitutor(); - - if (aClass != null) { - PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; - - for (Iterator i = aSubst.getSubstitutionMap().keySet().iterator(); i.hasNext();) { - final PsiTypeParameter p = i.next(); - - theSubst = theSubst.put(p, replaceWildCards(aSubst.substitute(p))); - } - - return aClass.getManager().getElementFactory().createType(aClass, theSubst); + else { + system.addSubtypeConstraint(var, Util.banalize(Util.substituteType(replaceWildCards(bound), definedSubst))); } } - return type; + return var; } - }.replaceWildCards(extendsList[j]); + else if (type instanceof PsiClassType) { + final PsiClassType.ClassResolveResult result = Util.resolveType(type); + final PsiClass aClass = result.getElement(); + final PsiSubstitutor aSubst = result.getSubstitutor(); - system.addSubtypeConstraint(Util.substituteType(extendsType, definedSubst), definedType); + if (aClass != null) { + PsiSubstitutor theSubst = PsiSubstitutor.EMPTY; + + for (Iterator i = aSubst.getSubstitutionMap().keySet().iterator(); i.hasNext();) { + final PsiTypeParameter p = i.next(); + + theSubst = theSubst.put(p, replaceWildCards(aSubst.substitute(p))); + } + + return aClass.getManager().getElementFactory().createType(aClass, theSubst); + } + } + + return type; + } + }.replaceWildCards(extendsList[j]); + + system.addSubtypeConstraint(definedType, Util.banalize(Util.substituteType(extendsType, definedSubst))); } } else { @@ -731,21 +774,17 @@ public class SystemBuilder { System system = new System(myProject, victims, myTypes, myTypeVariableFactory); for (Iterator i = victims.iterator(); i.hasNext();) { - PsiElement element = i.next(); + final PsiElement element = i.next(); if (element instanceof PsiParameter) { if (!verifyMethod(element, victims, helper)) { - continue; + continue; } - - element = myParameters.get(element); } else if (element instanceof PsiMethod) { if (!verifyMethod(element, victims, helper)) { - continue; + continue; } - - element = mySuper.get(element); } } @@ -761,17 +800,17 @@ public class SystemBuilder { setType(element, definedType = defineType(p)); } else { - definedType = defineType(element); + continue; } } else if (element instanceof PsiMethod) { - final PsiMethod m = mySuper.get(element); + final PsiMethod m = myMethods.get(element); if (m != null) { system.addSubtypeConstraint(defineType(element), definedType = defineType(m)); } else { - definedType = defineType(element); + continue; } } else { @@ -784,6 +823,21 @@ public class SystemBuilder { for (Iterator i = victims.iterator(); i.hasNext();) { final PsiElement element = i.next(); + if (element instanceof PsiParameter) { + final PsiParameter p = myParameters.get(element); + + if (p == null) { + continue; + } + } + else if (element instanceof PsiMethod) { + final PsiMethod m = myMethods.get(element); + + if (m == null) { + continue; + } + } + addUsage(system, element); if (!(element instanceof PsiExpression)) { diff --git a/source/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java b/source/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java index bcadd41bf149..96c166ca145a 100644 --- a/source/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java +++ b/source/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java @@ -6,6 +6,8 @@ import com.intellij.refactoring.typeCook.deductive.PsiExtendedTypeVisitor; import com.intellij.refactoring.typeCook.Util; import com.intellij.refactoring.typeCook.Bottom; import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.psi.util.InheritanceUtil; import com.intellij.openapi.diagnostic.Logger; @@ -13,10 +15,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.project.Project; import com.intellij.util.IncorrectOperationException; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.HashSet; -import java.util.Arrays; +import java.util.*; /** * Created by IntelliJ IDEA. @@ -33,6 +32,35 @@ public class BindingFactory { private HashSet myBoundVariables; private Project myProject; + private PsiClass[] getGreatestLowerClasses(final PsiClass aClass, final PsiClass bClass) { + if (InheritanceUtil.isInheritorOrSelf(aClass, bClass, true)) { + return new PsiClass[]{aClass}; + } + + if (InheritanceUtil.isInheritorOrSelf(bClass, aClass, true)) { + return new PsiClass[]{bClass}; + } + + final Set descendants = new LinkedHashSet(); + + new Object() { + public void getGreatestLowerClasses(final PsiClass aClass, final PsiClass bClass, final Set descendants) { + if (aClass.isInheritor(bClass, true)) { + descendants.add(bClass); + } + else { + final PsiSearchHelper helper = aClass.getManager().getSearchHelper(); + final PsiClass[] bSubs = helper.findInheritors(bClass, GlobalSearchScope.allScope(myProject), false); + for (int i = 0; i < bSubs.length; i++) { + getGreatestLowerClasses(bSubs[i], aClass, descendants); + } + } + } + }.getGreatestLowerClasses(aClass, bClass, descendants); + + return descendants.toArray(new PsiClass[descendants.size()]); + } + private class BindingImpl extends Binding { private PsiType[] myBindings; private boolean myCyclic; @@ -107,35 +135,35 @@ public class BindingFactory { final int flag = (b1i == null ? 0 : 1) + (b2i == null ? 0 : 2); switch (flag) { - case 0: - break; + case 0: + break; - case 1: /* b1(i)\b2(i) */ - { - final PsiType type = b2.apply(b1i); - b3.myBindings[i] = type; - b3.myCyclic = type instanceof PsiTypeVariable; - } - break; + case 1: /* b1(i)\b2(i) */ + { + final PsiType type = b2.apply(b1i); + b3.myBindings[i] = type; + b3.myCyclic = type instanceof PsiTypeVariable; + } + break; - case 2: /* b2(i)\b1(i) */ - { - final PsiType type = b1.apply(b2i); - b3.myBindings[i] = type; - b3.myCyclic = type instanceof PsiTypeVariable; - } - break; + case 2: /* b2(i)\b1(i) */ + { + final PsiType type = b1.apply(b2i); + b3.myBindings[i] = type; + b3.myCyclic = type instanceof PsiTypeVariable; + } + break; - case 3: /* b2(i) \cap b1(i) */ - final Binding common = rise(b1i, b2i); + case 3: /* b2(i) \cap b1(i) */ + final Binding common = rise(b1i, b2i); - if (common == null) { - return null; - } + if (common == null) { + return null; + } - final PsiType type = b2.apply(common.apply(b1i)); - b3.myBindings[i] = type; - b3.myCyclic = type instanceof PsiTypeVariable; + final PsiType type = b2.apply(common.apply(b1i)); + b3.myBindings[i] = type; + b3.myCyclic = type instanceof PsiTypeVariable; } } @@ -157,7 +185,7 @@ public class BindingFactory { } private PsiType normalize(final PsiType t) { - if (t == null || t instanceof PsiTypeVariable){ + if (t == null || t instanceof PsiTypeVariable) { return Bottom.BOTTOM; } @@ -234,12 +262,40 @@ public class BindingFactory { } if (kindX != kindY) { - if (kindX == 4){ + if (kindX == 4) { return Binding.WORSE; } - if (kindY == 4){ - return Binding.BETTER; + if (kindY == 4) { + return Binding.BETTER; + } + + if (kindX + kindY == 5) { + try { + final PsiElementFactory f = PsiManager.getInstance(myProject).getElementFactory(); + final PsiType cloneable = f.createTypeFromText("java.lang.Cloneable", null); + final PsiType object = f.createTypeFromText("java.lang.Object", null); + final PsiType serializable = f.createTypeFromText("java.io.Serializable", null); + + PsiType type = null; + int flag = 0; + + if (kindX == 3) { + type = x; + flag = Binding.WORSE; + } + else { + type = y; + flag = Binding.BETTER; + } + + if (type.equals(object) || type.equals(cloneable) || type.equals(serializable)) { + return flag; + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } return Binding.NONCOMPARABLE; @@ -351,7 +407,7 @@ public class BindingFactory { final PsiType type = binding.myBindings[i]; if (type == null) { - continue; + continue; } final int index = i; @@ -393,78 +449,164 @@ public class BindingFactory { Binding typeVar(PsiType x, PsiTypeVariable y); } + interface Unifier { + Binding unify(PsiType x, PsiType y); + } + public Binding balance(final PsiType x, final PsiType y, final Balancer balancer) { final int indicator = (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0); switch (indicator) { - case 0: - if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) { - final PsiType xType = x instanceof PsiWildcardType ? ((PsiWildcardType)x).getBound() : x; - final PsiType yType = y instanceof PsiWildcardType ? ((PsiWildcardType)y).getBound() : y; + case 0: + if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) { + final PsiType xType = x instanceof PsiWildcardType ? ((PsiWildcardType)x).getBound() : x; + final PsiType yType = y instanceof PsiWildcardType ? ((PsiWildcardType)y).getBound() : y; - return balance(xType, yType, balancer); - } - else if (x instanceof PsiArrayType || y instanceof PsiArrayType) { - final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType)x).getComponentType() : x; - final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType)y).getComponentType() : y; + return balance(xType, yType, balancer); + } + else if (x instanceof PsiArrayType || y instanceof PsiArrayType) { + final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType)x).getComponentType() : x; + final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType)y).getComponentType() : y; - return balance(xType, yType, balancer); - } - else if (x instanceof PsiClassType && y instanceof PsiClassType) { - final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); - final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); + return balance(xType, yType, balancer); + } + else if (x instanceof PsiClassType && y instanceof PsiClassType) { + final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); + final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); - final PsiClass xClass = resultX.getElement(); - final PsiClass yClass = resultY.getElement(); + final PsiClass xClass = resultX.getElement(); + final PsiClass yClass = resultY.getElement(); - if (xClass != null && yClass != null) { - final PsiSubstitutor ySubst = resultY.getSubstitutor(); + if (xClass != null && yClass != null) { + final PsiSubstitutor ySubst = resultY.getSubstitutor(); - PsiSubstitutor xSubst = resultX.getSubstitutor(); + PsiSubstitutor xSubst = resultX.getSubstitutor(); - if (!xClass.equals(yClass)) { - if (InheritanceUtil.isCorrectDescendant(xClass, yClass, true)) { - xSubst = TypeConversionUtil.getSuperClassSubstitutor(yClass, xClass, xSubst); - } - else { - return null; - } - } + if (!xClass.equals(yClass)) { + if (InheritanceUtil.isCorrectDescendant(xClass, yClass, true)) { + xSubst = TypeConversionUtil.getSuperClassSubstitutor(yClass, xClass, xSubst); + } + else { + return null; + } + } - Binding b = create(); + Binding b = create(); - for (Iterator p = xSubst.getSubstitutionMap().keySet().iterator(); p.hasNext();) { - final PsiTypeParameter aParm = p.next(); - final PsiType xType = xSubst.substitute(aParm); - final PsiType yType = ySubst.substitute(aParm); + for (Iterator p = xSubst.getSubstitutionMap().keySet().iterator(); p.hasNext();) { + final PsiTypeParameter aParm = p.next(); + final PsiType xType = xSubst.substitute(aParm); + final PsiType yType = ySubst.substitute(aParm); - final Binding b1 = balance(xType, yType, balancer); + final Binding b1 = unify(xType, yType, new Unifier() { + public Binding unify(final PsiType x, final PsiType y) { + return balance(x, y, balancer); + } + }); - if (b1 == null) { - return null; - } + if (b1 == null) { + return null; + } - b = b.compose(b1); - } + b = b.compose(b1); + } - return b; - } - } - else if (x instanceof Bottom || y instanceof Bottom) { - return create(); - } - else { - return null; - } + return b; + } + } + else if (y instanceof Bottom) { + return create(); + } + else { + return null; + } - case 1: - return balancer.varType((PsiTypeVariable)x, y); + case 1: + return balancer.varType((PsiTypeVariable)x, y); - case 2: - return balancer.typeVar(x, (PsiTypeVariable)y); + case 2: + return balancer.typeVar(x, (PsiTypeVariable)y); - case 3: - return balancer.varVar((PsiTypeVariable)x, (PsiTypeVariable)y); + case 3: + return balancer.varVar((PsiTypeVariable)x, (PsiTypeVariable)y); + } + + return null; + } + + private Binding unify(final PsiType x, final PsiType y, final Unifier unifier) { + final int indicator = (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0); + + switch (indicator) { + case 0: + if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) { + return unifier.unify(x, y); + } + else if (x instanceof PsiArrayType || y instanceof PsiArrayType) { + final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType)x).getComponentType() : x; + final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType)y).getComponentType() : y; + + return unify(xType, yType, unifier); + } + else if (x instanceof PsiClassType && y instanceof PsiClassType) { + final PsiClassType.ClassResolveResult resultX = Util.resolveType(x); + final PsiClassType.ClassResolveResult resultY = Util.resolveType(y); + + final PsiClass xClass = resultX.getElement(); + final PsiClass yClass = resultY.getElement(); + + if (xClass != null && yClass != null) { + final PsiSubstitutor ySubst = resultY.getSubstitutor(); + + PsiSubstitutor xSubst = resultX.getSubstitutor(); + + if (!xClass.equals(yClass)) { + return null; + } + + Binding b = create(); + + for (Iterator p = xSubst.getSubstitutionMap().keySet().iterator(); p.hasNext();) { + final PsiTypeParameter aParm = p.next(); + final PsiType xType = xSubst.substitute(aParm); + final PsiType yType = ySubst.substitute(aParm); + + final Binding b1 = unify(xType, yType, unifier); + + if (b1 == null) { + return null; + } + + b = b.compose(b1); + } + + return b; + } + } + else if (y instanceof Bottom) { + return create(); + } + else { + return null; + } + + case 1: + return create((PsiTypeVariable)x, y); + + case 2: + return create((PsiTypeVariable)y, x); + + case 3: + { + final PsiTypeVariable xVar = ((PsiTypeVariable)x); + final PsiTypeVariable yVar = ((PsiTypeVariable)y); + + if (xVar.getIndex() == yVar.getIndex()) { + return create(); + } + + return xVar.getIndex() < yVar.getIndex() ? create(xVar, y) : create(yVar, x); + } } return null; @@ -472,47 +614,45 @@ public class BindingFactory { public Binding rise(final PsiType x, final PsiType y) { return balance(x, y, new Balancer() { + public Binding varType(PsiTypeVariable x, PsiType y) { + return create(x, y); + } - public Binding varType(PsiTypeVariable x, PsiType y) { - return create(x, y); - } + public Binding varVar(PsiTypeVariable x, PsiTypeVariable y) { + final int xi = x.getIndex(); + final int yi = y.getIndex(); - public Binding varVar(PsiTypeVariable x, PsiTypeVariable y) { - final int xi = x.getIndex(); - final int yi = y.getIndex(); + if (xi < yi) { + return create(((PsiTypeVariable)x), y); + } + else if (yi < xi) { + return create(((PsiTypeVariable)y), x); + } + else { + return create(); + } + } - if (xi < yi) { - return create(((PsiTypeVariable)x), y); - } - else if (yi < xi) { - return create(((PsiTypeVariable)y), x); - } - else { - return create(); - } - } - - public Binding typeVar(PsiType x, PsiTypeVariable y) { - return create(y, x); - } - }); + public Binding typeVar(PsiType x, PsiTypeVariable y) { + return create(y, x); + } + }); } public Binding sink(final PsiType x, final PsiType y) { return balance(x, y, new Balancer() { + public Binding varType(PsiTypeVariable x, PsiType y) { + return create(x, Bottom.BOTTOM); + } - public Binding varType(PsiTypeVariable x, PsiType y) { - return create(x, Bottom.BOTTOM); - } + public Binding varVar(PsiTypeVariable x, PsiTypeVariable y) { + return create(x, Bottom.BOTTOM); + } - public Binding varVar(PsiTypeVariable x, PsiTypeVariable y) { - return create(x, Bottom.BOTTOM); - } - - public Binding typeVar(PsiType x, PsiTypeVariable y) { - return create(y, x); - } - }); + public Binding typeVar(PsiType x, PsiTypeVariable y) { + return create(y, x); + } + }); } public LinkedList> union(final PsiType x, final PsiType y) { @@ -547,7 +687,7 @@ public class BindingFactory { list.addFirst(new Pair(risen.apply(x), risen)); } else { - final PsiClass[] descendants = GenericsUtil.getGreatestLowerClasses(xClass, yClass); + final PsiClass[] descendants = getGreatestLowerClasses(xClass, yClass); for (int i = 0; i < descendants.length; i++) { final PsiClass descendant = descendants[i]; @@ -613,10 +753,14 @@ public class BindingFactory { final Binding risen = rise(x, y); if (risen == null) { - return; - } + final PsiElementFactory factory = xClass.getManager().getElementFactory(); - list.addFirst(new Pair(risen.apply(x), risen)); + list.addFirst(new Pair(Util.banalize(factory.createType(xClass, factory.createRawSubstitutor(xClass))), + create())); + } + else { + list.addFirst(new Pair(risen.apply(x), risen)); + } } else { final PsiClass[] ancestors = GenericsUtil.getLeastUpperClasses(xClass, yClass); @@ -625,7 +769,7 @@ public class BindingFactory { final PsiClass ancestor = ancestors[i]; if (ancestor.getQualifiedName().equals("java.lang.Object") && ancestors.length > 1) { - continue; + continue; } final PsiSubstitutor x2aSubst = TypeConversionUtil.getSuperClassSubstitutor(ancestor, xClass, xSubst); diff --git a/testData/refactoring/typeCook/t146/after/test.java b/testData/refactoring/typeCook/t146/after/test.java new file mode 100644 index 000000000000..8207808716f7 --- /dev/null +++ b/testData/refactoring/typeCook/t146/after/test.java @@ -0,0 +1,17 @@ +class List { + T t; +} + +class Test{ + class Super { + void f (List x){ + x = new List(); + } + } + + class Middle extends Super { + void f (List x){ + x.t = ""; + } + } +} \ No newline at end of file diff --git a/testData/refactoring/typeCook/t146/before/test.java b/testData/refactoring/typeCook/t146/before/test.java new file mode 100644 index 000000000000..8207808716f7 --- /dev/null +++ b/testData/refactoring/typeCook/t146/before/test.java @@ -0,0 +1,17 @@ +class List { + T t; +} + +class Test{ + class Super { + void f (List x){ + x = new List(); + } + } + + class Middle extends Super { + void f (List x){ + x.t = ""; + } + } +} \ No newline at end of file diff --git a/testData/refactoring/typeCook/t91/after/test.java b/testData/refactoring/typeCook/t91/after/test.java index e96b88501f8c..2fecd3b51deb 100644 --- a/testData/refactoring/typeCook/t91/after/test.java +++ b/testData/refactoring/typeCook/t91/after/test.java @@ -10,6 +10,7 @@ class Test{ class Middle extends Super { void f (List x){ + g(x); x.t = ""; } diff --git a/testData/refactoring/typeCook/t91/before/test.java b/testData/refactoring/typeCook/t91/before/test.java index e96b88501f8c..2fecd3b51deb 100644 --- a/testData/refactoring/typeCook/t91/before/test.java +++ b/testData/refactoring/typeCook/t91/before/test.java @@ -10,6 +10,7 @@ class Test{ class Middle extends Super { void f (List x){ + g(x); x.t = ""; } diff --git a/testData/refactoring/typeCook/t92/after/test.java b/testData/refactoring/typeCook/t92/after/test.java index 17c02e6d41db..a204b246a5df 100644 --- a/testData/refactoring/typeCook/t92/after/test.java +++ b/testData/refactoring/typeCook/t92/after/test.java @@ -3,17 +3,7 @@ class List { } class Test{ - class Super { - void f (List x){ - x = new List(); - } - } - class Middle extends Super { - void f (List x){ - x.t = ""; - } - List g (){ return new List(); } @@ -21,7 +11,6 @@ class Test{ class Sub extends Middle{ List g (){ - } } } \ No newline at end of file diff --git a/testData/refactoring/typeCook/t92/before/test.java b/testData/refactoring/typeCook/t92/before/test.java index 17c02e6d41db..a204b246a5df 100644 --- a/testData/refactoring/typeCook/t92/before/test.java +++ b/testData/refactoring/typeCook/t92/before/test.java @@ -3,17 +3,7 @@ class List { } class Test{ - class Super { - void f (List x){ - x = new List(); - } - } - class Middle extends Super { - void f (List x){ - x.t = ""; - } - List g (){ return new List(); } @@ -21,7 +11,6 @@ class Test{ class Sub extends Middle{ List g (){ - } } } \ No newline at end of file