Type Cook Advanced

This commit is contained in:
Dmitri Boulytchev
2005-02-21 14:55:05 +03:00
parent a880dfebca
commit 72a71dd7ac
16 changed files with 204 additions and 30 deletions
@@ -64,7 +64,8 @@ public abstract class RefactoringFactory {
boolean dropObsoleteCasts,
boolean leaveObjectsRaw,
boolean preserveRawArrays,
boolean exhaustive);
boolean exhaustive,
boolean cookObjects);
/**
* Creates Introduce Parameter refactoring that replaces local variable with parameter.
@@ -55,6 +55,7 @@ public class RefactoringSettings implements JDOMExternalizable, ApplicationCompo
public boolean TYPE_COOK_PRESERVE_RAW_ARRAYS = true;
public boolean TYPE_COOK_LEAVE_OBJECT_PARAMETERIZED_TYPES_RAW = true;
public boolean TYPE_COOK_EXHAUSTIVE = false;
public final boolean TYPE_COOK_COOK_OBJECTS = false;
public boolean TYPE_MIGRATION_PREVIEW_USAGES = true;
@@ -113,8 +113,9 @@ public class RefactoringFactoryImpl extends RefactoringFactory implements Projec
boolean dropObsoleteCasts,
boolean leaveObjectsRaw,
boolean preserveRawArrays,
boolean exhaustive) {
return new TypeCookRefactoringImpl(myProject, elements, dropObsoleteCasts, leaveObjectsRaw, preserveRawArrays, exhaustive);
boolean exhaustive,
boolean cookObjects) {
return new TypeCookRefactoringImpl(myProject, elements, dropObsoleteCasts, leaveObjectsRaw, preserveRawArrays, exhaustive, cookObjects);
}
public IntroduceParameterRefactoring createIntroduceParameterRefactoring(PsiMethod methodToReplaceIn,
@@ -22,7 +22,8 @@ public class TypeCookRefactoringImpl extends RefactoringImpl<TypeCookProcessor>
final boolean dropObsoleteCasts,
final boolean leaveObjectsRaw,
final boolean preserveRawArrays,
final boolean exh) {
final boolean exhaustiveSearch,
final boolean cookObjects) {
super(new TypeCookProcessor(project, elements, new Settings() {
public boolean dropObsoleteCasts() {
return dropObsoleteCasts;
@@ -33,7 +34,11 @@ public class TypeCookRefactoringImpl extends RefactoringImpl<TypeCookProcessor>
}
public boolean exhaustive() {
return exh;
return exhaustiveSearch;
}
public boolean cookObjects() {
return cookObjects;
}
public boolean preserveRawArrays() {
@@ -12,4 +12,5 @@ public interface Settings {
boolean preserveRawArrays();
boolean leaveObjectParameterizedTypesRaw();
boolean exhaustive();
boolean cookObjects();
}
@@ -27,6 +27,7 @@ public class TypeCookDialog extends RefactoringDialog {
private JCheckBox myCbPreserveRawArrays = new JCheckBox("Preserve raw arrays");
private JCheckBox myCbLeaveObjectParameterizedTypesRaw = new JCheckBox("Leave Object-parameterized types raw");
private JCheckBox myCbExhaustive = new JCheckBox("Perform exhaustive search");
private JCheckBox myCbCookObjects = new JCheckBox("Generify Objects");
public TypeCookDialog(Project project, PsiElement[] elements) {
super(project, true);
@@ -96,10 +97,16 @@ public class TypeCookDialog extends RefactoringDialog {
RefactoringSettings.getInstance().TYPE_COOK_EXHAUSTIVE);
}
if (myCbCookObjects.isEnabled()) {
myCbCookObjects.setSelected(
RefactoringSettings.getInstance().TYPE_COOK_COOK_OBJECTS);
}
myCbDropCasts.setMnemonic('D');
myCbPreserveRawArrays.setMnemonic('P');
myCbLeaveObjectParameterizedTypesRaw.setMnemonic('L');
myCbExhaustive.setMnemonic('E');
myCbCookObjects.setMnemonic('O');
gbConstraints.insets = new Insets(4, 8, 4, 8);
@@ -129,6 +136,10 @@ public class TypeCookDialog extends RefactoringDialog {
gbConstraints.gridwidth = 2;
optionsPanel.add(myCbExhaustive, gbConstraints);
gbConstraints.gridx = 0;
gbConstraints.gridwidth = 2;
optionsPanel.add(myCbCookObjects, gbConstraints);
return optionsPanel;
}
@@ -145,7 +156,8 @@ public class TypeCookDialog extends RefactoringDialog {
final boolean dropCasts = myCbDropCasts.isSelected();
final boolean preserveRawArrays = true; //myCbPreserveRawArrays.isSelected();
final boolean leaveObjectParameterizedTypesRaw = myCbLeaveObjectParameterizedTypesRaw.isSelected();
final boolean exh = myCbExhaustive.isSelected();
final boolean exhaustive = myCbExhaustive.isSelected();
final boolean cookObjects = myCbCookObjects.isSelected();
return new Settings() {
public boolean dropObsoleteCasts() {
@@ -161,7 +173,11 @@ public class TypeCookDialog extends RefactoringDialog {
}
public boolean exhaustive() {
return exh;
return exhaustive;
}
public boolean cookObjects() {
return cookObjects;
}
};
}
@@ -87,6 +87,8 @@ public class TypeCookProcessor extends BaseRefactoringProcessor {
myResult.apply (victims);
java.lang.System.out.println(myResult.getReport());
UndoManager.getInstance(myProject).undoableActionPerformed(new DummyComplexUndoableAction()); // force confirmation dialog for undo
}
@@ -2,6 +2,7 @@ package com.intellij.refactoring.typeCook;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -117,7 +118,11 @@ public class Util {
}
}
public static boolean isRaw(PsiType t, boolean arrays) {
public static boolean isRaw(PsiType t, final Settings settings) {
return isRaw(t, settings, true);
}
private static boolean isRaw(PsiType t, final Settings settings, final boolean upper) {
if (t instanceof PsiClassType) {
final PsiClassType.ClassResolveResult resolveResult = resolveType(t);
@@ -131,18 +136,24 @@ public class Util {
final PsiSubstitutor subst = resolveResult.getSubstitutor();
final PsiClass element = resolveResult.getElement();
final PsiManager manager = element.getManager();
if (settings.cookObjects() && upper &&
t.equals(PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject())))) {
return true;
}
final PsiTypeParameter[] parameters = getTypeParametersList(element);
for (int i = 0; i < parameters.length; i++) {
final PsiType actual = subst.substitute(parameters[i]);
if (!(actual instanceof PsiTypeParameter) && isRaw(actual, arrays)) return true;
if (!(actual instanceof PsiTypeParameter) && isRaw(actual, settings, false)) return true;
}
return false;
}
else if (t instanceof PsiArrayType) {
return arrays ? false : isRaw(((PsiArrayType)t).getComponentType(), arrays);
return settings.preserveRawArrays() ? false : isRaw(((PsiArrayType)t).getComponentType(), settings, upper);
}
return false;
@@ -308,9 +319,20 @@ public class Util {
return type;
}
public static PsiType createParameterizedType(final PsiType t, final PsiTypeVariableFactory factory, final PsiElement context) {
return createParameterizedType(t, factory, true, context);
}
public static PsiType createParameterizedType(final PsiType t, final PsiTypeVariableFactory factory) {
if (t == null) {
return factory.create();
return createParameterizedType(t, factory, true, null);
}
private static PsiType createParameterizedType(final PsiType t,
final PsiTypeVariableFactory factory,
final boolean upper,
final PsiElement context) {
if (t == null || (upper && t.getCanonicalText().equals("java.lang.Object"))) {
return factory.create(context);
}
if (t instanceof PsiClassType) {
@@ -324,7 +346,7 @@ public class Util {
for (Iterator<PsiTypeParameter> i = aSubst.getSubstitutionMap().keySet().iterator(); i.hasNext();) {
final PsiTypeParameter parm = i.next();
final PsiType type = createParameterizedType(aSubst.substitute(parm), factory);
final PsiType type = createParameterizedType(aSubst.substitute(parm), factory, false, context);
if (type instanceof PsiTypeVariable) {
cluster.add((PsiTypeVariable)type);
@@ -340,7 +362,7 @@ public class Util {
return aClass.getManager().getElementFactory().createType(aClass, theSubst);
}
else if (t instanceof PsiArrayType) {
return createParameterizedType(((PsiArrayType)t).getComponentType(), factory).createArrayType();
return createParameterizedType(((PsiArrayType)t).getComponentType(), factory, upper, context).createArrayType();
}
return t;
@@ -463,7 +485,7 @@ public class Util {
final PsiSubstitutor subst = result.getSubstitutor();
final PsiTypeParameter[] parms = Util.getTypeParametersList(result.getElement());
if (parms.length >= 0 && subst.substitute(parms[0]) != null) {
if (parms.length > 0 && subst.substitute(parms[0]) != null) {
PsiJavaCodeReferenceElement classReference = newx.getClassReference();
PsiReferenceParameterList list = null;
@@ -488,7 +510,7 @@ public class Util {
for (int i = 0; i < parms.length; i++) {
PsiType aType = subst.substitute(parms[i]);
if (aType instanceof PsiWildcardType){
if (aType instanceof PsiWildcardType) {
aType = ((PsiWildcardType)aType).getBound();
}
@@ -497,7 +519,7 @@ public class Util {
}
}
else {
LOG.error ("Unexpected element type " + element.getClass().getName());
LOG.error("Unexpected element type " + element.getClass().getName());
}
}
catch (IncorrectOperationException e) {
@@ -1,7 +1,8 @@
package com.intellij.refactoring.typeCook.deductive;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeVisitor;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.search.GlobalSearchScope;
import java.util.HashSet;
@@ -28,8 +29,8 @@ public class PsiTypeVariableFactory {
public final void registerCluster(final HashSet<PsiTypeVariable> cluster) {
myClusters.add(cluster);
for (final Iterator<PsiTypeVariable> v=cluster.iterator(); v.hasNext();){
myVarCluster.put (new Integer(v.next().getIndex()), cluster);
for (final Iterator<PsiTypeVariable> v = cluster.iterator(); v.hasNext();) {
myVarCluster.put(new Integer(v.next().getIndex()), cluster);
}
}
@@ -37,13 +38,101 @@ public class PsiTypeVariableFactory {
return myClusters;
}
public final HashSet<PsiTypeVariable> getClusterOf (final int var){
return myVarCluster.get(new Integer (var));
public final HashSet<PsiTypeVariable> getClusterOf(final int var) {
return myVarCluster.get(new Integer(var));
}
public final PsiTypeVariable create() {
return create(null);
}
public final PsiTypeVariable create(final PsiElement context) {
return new PsiTypeVariable() {
private int myIndex = myCurrent++;
private final PsiElement myContext = context;
public boolean isValidInContext(final PsiType type) {
if (myContext == null) {
return true;
}
if (type == null) {
return true;
}
return type.accept(new PsiTypeVisitor<Boolean>() {
public Boolean visitType(final PsiType type) {
return Boolean.TRUE;
}
public Boolean visitArrayType(final PsiArrayType arrayType) {
return arrayType.getDeepComponentType().accept(this);
}
public Boolean visitWildcardType(final PsiWildcardType wildcardType) {
final PsiType bound = wildcardType.getBound();
if (bound != null) {
bound.accept(this);
}
return Boolean.TRUE;
}
public Boolean visitClassType(final PsiClassType classType) {
final PsiClassType.ClassResolveResult result = classType.resolveGenerics();
final PsiClass aClass = result.getElement();
final PsiSubstitutor aSubst = result.getSubstitutor();
final PsiManager manager = aClass.getManager();
if (aClass != null) {
if (aClass instanceof PsiTypeParameter) {
final PsiTypeParameterListOwner owner =
PsiTreeUtil.getParentOfType(myContext, PsiTypeParameterListOwner.class);
if (owner != null) {
boolean found = false;
for (final Iterator<PsiTypeParameter> p = PsiUtil.typeParametersIterator(owner);
p.hasNext() && !found;) {
final PsiTypeParameter parm = p.next();
found = manager.areElementsEquivalent(parm, aClass);
}
if (!found) {
return Boolean.FALSE;
}
}
else {
return Boolean.FALSE;
}
}
else if (!manager.getResolveHelper().isAccessible(aClass, myContext, null)) {
return Boolean.FALSE;
}
for (final Iterator<PsiTypeParameter> p = aSubst.getSubstitutionMap().keySet().iterator(); p.hasNext();) {
final PsiTypeParameter parm = p.next();
final PsiType type = aSubst.substitute(parm);
if (type != null){
final Boolean b = type.accept(this);
if (! b.booleanValue()){
return Boolean.FALSE;
}
}
}
return Boolean.TRUE;
}
else {
return Boolean.FALSE;
}
}
}).booleanValue();
}
public String getPresentableText() {
return "$" + myIndex;
@@ -53,11 +53,19 @@ public class Result {
}
public PsiType getCookedType(final PsiElement element) {
final PsiType originalType = Util.getType(element);
if (myBinding != null) {
return myBinding.substitute(myTypes.get(element));
final PsiType type = myBinding.substitute(myTypes.get(element));
if (type == null && originalType.getCanonicalText().equals("java.lang.Object")){
return originalType;
}
return type;
}
return Util.getType(element);
return originalType;
}
public HashSet<PsiElement> getCookedElements() {
@@ -170,7 +170,7 @@ public class SystemBuilder {
t = Util.getType(e);
final PsiType parameterizedType = Util.createParameterizedType(t, myTypeVariableFactory);
final PsiType parameterizedType = Util.createParameterizedType(t, myTypeVariableFactory, e);
myTypes.put(e, parameterizedType);
@@ -810,6 +810,10 @@ public class SystemBuilder {
}
}
}.brrrr(definedType, elemenType);
if (mySettings.cookObjects() && elemenType.getCanonicalText().equals("java.lang.Object")){
system.addSubtypeConstraint(definedType, elemenType);
}
}
}
@@ -40,4 +40,6 @@ public abstract class Binding {
public abstract HashSet<PsiTypeVariable> getBoundVariables();
public abstract int getWidth();
public abstract boolean isValid();
}
@@ -121,7 +121,7 @@ public class BindingFactory {
return theClass.getManager().getElementFactory().createType(theClass, theSubst);
}
else {
return null;
return type;
}
}
else if (type instanceof PsiWildcardType) {
@@ -541,6 +541,19 @@ public class BindingFactory {
return w;
}
public boolean isValid() {
for (final Iterator<PsiTypeVariable> v = myBoundVariables.iterator(); v.hasNext();) {
final PsiTypeVariable var = v.next();
final PsiType type = substitute(var);
if (!var.isValidInContext(type)) {
return false;
}
}
return true;
}
public PsiType substitute(final PsiType t) {
if (t instanceof PsiWildcardType) {
final PsiWildcardType wcType = (PsiWildcardType)t;
@@ -677,6 +690,7 @@ public class BindingFactory {
else {
return null;
}
break;
case 1:
return balancer.varType((PsiTypeVariable)x, y);
@@ -47,7 +47,7 @@ public class SolutionHolder {
final Binding binding = b.next();
final int w = binding.getWidth();
if (w > width) {
if (w > width && binding.isValid()) {
width = w;
best = binding;
}
@@ -24,7 +24,11 @@ public class VictimCollector extends Visitor {
}
private void testNAdd(final PsiElement element, final PsiType t) {
if (Util.isRaw(t, mySettings.preserveRawArrays())) {
if (Util.isRaw(t, mySettings)) {
if (element instanceof PsiNewExpression && t.getCanonicalText().equals("java.lang.Object")){
return;
}
myVictims.add(element);
}
}
@@ -48,7 +52,7 @@ public class VictimCollector extends Visitor {
testNAdd(parms[i], parms[i].getType());
}
if (Util.isRaw(method.getReturnType(), mySettings.preserveRawArrays())) {
if (Util.isRaw(method.getReturnType(), mySettings)) {
myVictims.add(method);
}
@@ -649,6 +649,10 @@ public class TypeCookTest extends MultiFileTestCase {
public boolean exhaustive() {
return false;
}
public boolean cookObjects(){
return false;
}
});
final com.intellij.refactoring.typeCook.deductive.builder.System commonSystem = b.build(new PsiElement[]{aClass});