diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index 8bc87714a4cd..bc60ac50d75f 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -1444,6 +1444,8 @@
implementation="org.jetbrains.plugins.groovy.springloaded.SpringLoadedPositionManagerFactory"/>
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyChangeContextUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyChangeContextUtil.java
index 422b5573c00c..0dd6b2c8b9f9 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyChangeContextUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyChangeContextUtil.java
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.refactoring;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
@@ -114,6 +115,7 @@ public class GroovyChangeContextUtil {
final PsiElement qualifier = refExpr.getQualifier();
if (!(qualifier instanceof GrReferenceExpression)) {
refExpr.setQualifier(factory.createReferenceExpressionFromText(memberClass.getQualifiedName()));
+ JavaCodeStyleManager.getInstance(manager.getProject()).shortenClassReferences(refExpr.getQualifier());
return;
}
}
@@ -140,4 +142,13 @@ public class GroovyChangeContextUtil {
}
}
}
+
+ public static void clearContextInfo(PsiElement scope) {
+ scope.putCopyableUserData(QUALIFIER_CLASS_KEY, null);
+ scope.putCopyableUserData(REF_TO_CLASS, null);
+ scope.putCopyableUserData(REF_TO_MEMBER, null);
+ for (PsiElement child = scope.getFirstChild(); child != null; child = child.getNextSibling()) {
+ clearContextInfo(child);
+ }
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java
index 5e2e2af4210c..b8b2857fb551 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java
@@ -41,6 +41,7 @@ import org.jetbrains.plugins.groovy.refactoring.introduce.constant.GrIntroduceCo
import org.jetbrains.plugins.groovy.refactoring.introduce.field.GrIntroduceFieldHandler;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterHandler;
import org.jetbrains.plugins.groovy.refactoring.introduce.variable.GrIntroduceVariableHandler;
+import org.jetbrains.plugins.groovy.refactoring.memberPullUp.GrPullUpHandler;
/**
* @author ilyas
@@ -129,4 +130,17 @@ public class GroovyRefactoringSupportProvider extends RefactoringSupportProvider
public RefactoringActionHandler getIntroduceConstantHandler() {
return new GrIntroduceConstantHandler();
}
+
+ @Nullable
+ @Override
+ public RefactoringActionHandler getPullUpHandler() {
+ return new GrPullUpHandler();
+ }
+
+ @Nullable
+ @Override
+ public RefactoringActionHandler getExtractInterfaceHandler() {
+ //return new ExtractInterfaceHandler();
+ return null;
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrClassMemberReferenceVisitor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrClassMemberReferenceVisitor.java
new file mode 100644
index 000000000000..92a073521bc2
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrClassMemberReferenceVisitor.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.classMembers;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
+
+/**
+ * @author Max Medvedev
+ */
+public abstract class GrClassMemberReferenceVisitor extends GroovyRecursiveElementVisitor {
+ private final PsiClass myClass;
+
+ public GrClassMemberReferenceVisitor(@NotNull PsiClass aClass) {
+ myClass = aClass;
+ }
+
+ @Override
+ public void visitReferenceExpression(GrReferenceExpression ref) {
+ GrExpression qualifier = ref.getQualifier();
+
+ if (qualifier != null && !(PsiUtil.isThisOrSuperRef(qualifier))) {
+ qualifier.accept(this);
+
+ if (!(qualifier instanceof GrReferenceExpression) || !(((GrReferenceExpression) qualifier).resolve() instanceof PsiClass)) {
+ return;
+ }
+ }
+
+ PsiElement resolved = ref.resolve();
+ if (resolved instanceof GrMember) {
+ PsiClass containingClass = ((GrMember)resolved).getContainingClass();
+ if (isPartOf(myClass, containingClass)) {
+ visitClassMemberReferenceElement((GrMember)resolved, ref);
+ }
+ }
+ }
+
+ @Override
+ public void visitCodeReferenceElement(GrCodeReferenceElement reference) {
+ PsiElement referencedElement = reference.resolve();
+ if (referencedElement instanceof GrTypeDefinition) {
+ final GrTypeDefinition referencedClass = (GrTypeDefinition)referencedElement;
+ if (PsiTreeUtil.isAncestor(myClass, referencedElement, true) ||
+ isPartOf(myClass, referencedClass.getContainingClass())) {
+ visitClassMemberReferenceElement((GrMember)referencedElement, reference);
+ }
+ }
+ }
+
+ private static boolean isPartOf(@NotNull PsiClass aClass, @Nullable PsiClass containingClass) {
+ if (containingClass == null) return false;
+ return aClass.equals(containingClass) || aClass.isInheritor(containingClass, true);
+ }
+
+ protected abstract void visitClassMemberReferenceElement(GrMember resolved, GrReferenceElement ref);
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrDependantMembersCollector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrDependantMembersCollector.java
new file mode 100644
index 000000000000..1159e2e809f2
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrDependantMembersCollector.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.classMembers;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMember;
+import com.intellij.psi.PsiMethod;
+import com.intellij.refactoring.classMembers.DependentMembersCollectorBase;
+import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrDependantMembersCollector extends DependentMembersCollectorBase {
+ public GrDependantMembersCollector(PsiClass clazz, PsiClass superClass) {
+ super(clazz, superClass);
+ }
+
+ @Override
+ public void collect(GrMember member) {
+ member.accept(new GrClassMemberReferenceVisitor(getClazz()) {
+ @Override
+ protected void visitClassMemberReferenceElement(GrMember classMember, GrReferenceElement ref) {
+ if (!existsInSuperClass(classMember)) {
+ myCollection.add(classMember);
+ }
+ }
+ });
+ }
+
+ private boolean existsInSuperClass(PsiMember classMember) {
+ if (getSuperClass() == null) return false;
+ if (!(classMember instanceof PsiMethod)) return false;
+ final PsiMethod method = ((PsiMethod)classMember);
+ final PsiMethod methodBySignature = (getSuperClass()).findMethodBySignature(method, true);
+ return methodBySignature != null;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberInfo.java
new file mode 100644
index 000000000000..e1caae834ace
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberInfo.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.classMembers;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiFormatUtil;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.classMembers.MemberInfoBase;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrMemberInfo extends MemberInfoBase {
+ public GrMemberInfo(GrMember member) {
+ this(member, false, null);
+ }
+
+ public GrMemberInfo(GrMember member, boolean isSuperClass, GrReferenceList sourceReferenceList) {
+ super(member);
+ LOG.assertTrue(member.isValid());
+ mySourceReferenceList = sourceReferenceList;
+ if (member instanceof GrMethod) {
+ GrMethod method = (GrMethod)member;
+ displayName = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER | PsiFormatUtil.SHOW_PARAMETERS,
+ PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER);
+ PsiMethod[] superMethods = method.findSuperMethods();
+ if (superMethods.length > 0) {
+ overrides = !superMethods[0].hasModifierProperty(PsiModifier.ABSTRACT) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else {
+ overrides = null;
+ }
+
+ isStatic = method.hasModifierProperty(PsiModifier.STATIC);
+ }
+ else if (member instanceof GrField) {
+ GrField field = (GrField)member;
+ displayName = PsiFormatUtil
+ .formatVariable(field, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.TYPE_AFTER, PsiSubstitutor.EMPTY);
+ isStatic = field.hasModifierProperty(PsiModifier.STATIC);
+ overrides = null;
+ }
+ else if (member instanceof GrTypeDefinition) {
+ GrTypeDefinition aClass = (GrTypeDefinition)member;
+
+ if (isSuperClass) {
+ if (aClass.isInterface()) {
+ displayName = RefactoringBundle.message("member.info.implements.0", aClass.getName());
+ overrides = Boolean.FALSE;
+ }
+ else {
+ displayName = RefactoringBundle.message("member.info.extends.0", aClass.getName());
+ overrides = Boolean.TRUE;
+ }
+ }
+ else {
+ displayName = aClass.getName();
+ overrides = null;
+ }
+
+ isStatic = aClass.hasModifierProperty(PsiModifier.STATIC);
+ }
+ else {
+ LOG.assertTrue(false);
+ isStatic = false;
+ displayName = "";
+ overrides = null;
+ }
+ }
+
+ public GrReferenceList getSourceReferenceList() {
+ return mySourceReferenceList;
+ }
+
+ public static List extractClassMembers(GrTypeDefinition subclass, Filter filter, boolean extractInterfacesDeep) {
+ List members = new ArrayList();
+ extractClassMembers(subclass, members, filter, extractInterfacesDeep);
+ return members;
+ }
+
+ public static void extractClassMembers(PsiClass subclass,
+ List result,
+ Filter filter,
+ final boolean extractInterfacesDeep) {
+
+ if (!(subclass instanceof GrTypeDefinition)) return;
+
+
+ if (extractInterfacesDeep) {
+ extractSuperInterfaces(subclass, filter, result, ContainerUtil.newHashSet());
+ }
+ else {
+ PsiClass[] interfaces = subclass.getInterfaces();
+ GrReferenceList sourceRefList = subclass.isInterface()
+ ? ((GrTypeDefinition)subclass).getExtendsClause()
+ : ((GrTypeDefinition)subclass).getImplementsClause();
+ for (PsiClass anInterface : interfaces) {
+ if (anInterface instanceof GrTypeDefinition && filter.includeMember((GrMember)anInterface)) {
+ result.add(new GrMemberInfo((GrMember)anInterface, true, sourceRefList));
+ }
+ }
+ }
+
+
+ PsiClass[] innerClasses = subclass.getInnerClasses();
+ for (PsiClass innerClass : innerClasses) {
+ if (innerClass instanceof GrTypeDefinition && filter.includeMember((GrMember)innerClass)) {
+ result.add(new GrMemberInfo((GrMember)innerClass));
+ }
+ }
+
+ GrMethod[] methods = ((GrTypeDefinition)subclass).getCodeMethods();
+ for (GrMethod method : methods) {
+ if (!method.isConstructor() && filter.includeMember(method)) {
+ result.add(new GrMemberInfo(method));
+ }
+ }
+
+ GrField[] fields = ((GrTypeDefinition)subclass).getCodeFields();
+ for (final GrField field : fields) {
+ if (filter.includeMember(field)) {
+ result.add(new GrMemberInfo(field));
+ }
+ }
+ }
+
+ private static void extractSuperInterfaces(final PsiClass subclass,
+ final Filter filter,
+ final List result,
+ Set processed) {
+ if (!processed.contains(subclass)) {
+ processed.add(subclass);
+ if (subclass instanceof GrTypeDefinition) {
+ extractSuperInterfacesFromReferenceList(((GrTypeDefinition)subclass).getExtendsClause(), filter, result, processed);
+ extractSuperInterfacesFromReferenceList(((GrTypeDefinition)subclass).getImplementsClause(), filter, result, processed);
+ }
+ }
+ }
+
+ private static void extractSuperInterfacesFromReferenceList(final GrReferenceList referenceList,
+ final Filter filter,
+ final List result,
+ final Set processed) {
+ if (referenceList != null) {
+ final PsiClassType[] extendsListTypes = referenceList.getReferenceTypes();
+ for (PsiClassType extendsListType : extendsListTypes) {
+ final PsiClass aSuper = extendsListType.resolve();
+ if (aSuper instanceof GrTypeDefinition) {
+ if (aSuper.isInterface()) {
+ if (filter.includeMember((GrMember)aSuper)) {
+ result.add(new GrMemberInfo((GrMember)aSuper, true, referenceList));
+ }
+ }
+ else {
+ extractSuperInterfaces(aSuper, filter, result, processed);
+ }
+ }
+ }
+ }
+ }
+
+ private final GrReferenceList mySourceReferenceList;
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberInfoStorage.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberInfoStorage.java
new file mode 100644
index 000000000000..e2ad5864e81a
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberInfoStorage.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.classMembers;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassType;
+import com.intellij.psi.util.MethodSignatureUtil;
+import com.intellij.refactoring.classMembers.AbstractMemberInfoStorage;
+import com.intellij.refactoring.classMembers.MemberInfoBase;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+
+import java.util.ArrayList;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrMemberInfoStorage extends AbstractMemberInfoStorage {
+ public GrMemberInfoStorage(GrTypeDefinition aClass, MemberInfoBase.Filter memberInfoFilter) {
+ super(aClass, memberInfoFilter);
+ }
+
+ @Override
+ protected boolean isInheritor(PsiClass baseClass, PsiClass aClass) {
+ return aClass.isInheritor(baseClass, true);
+ }
+
+ @Override
+ protected void extractClassMembers(PsiClass aClass, ArrayList temp) {
+ GrMemberInfo.extractClassMembers(aClass, temp, myFilter, false);
+ }
+
+ @Override
+ protected boolean memberConflict(GrMember member1, GrMember member) {
+ if (member instanceof GrMethod && member1 instanceof GrMethod) {
+ return MethodSignatureUtil.areSignaturesEqual((GrMethod)member, (GrMethod)member1);
+ }
+ else if (member instanceof GrField && member1 instanceof GrField ||
+ member instanceof GrTypeDefinition && member1 instanceof GrTypeDefinition) {
+ return member.getName().equals(member1.getName());
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void buildSubClassesMap(PsiClass aClass) {
+ if (aClass instanceof GrTypeDefinition) {
+ final GrExtendsClause extendsList = ((GrTypeDefinition)aClass).getExtendsClause();
+ if (extendsList != null) {
+ buildSubClassesMapForList(extendsList.getReferenceTypes(), (GrTypeDefinition)aClass);
+ }
+
+ final GrImplementsClause implementsList = ((GrTypeDefinition)aClass).getImplementsClause();
+ if (implementsList != null) {
+ buildSubClassesMapForList(implementsList.getReferenceTypes(), (GrTypeDefinition)aClass);
+ }
+ }
+ }
+
+ private void buildSubClassesMapForList(final PsiClassType[] classesList, GrTypeDefinition aClass) {
+ for (int i = 0; i < classesList.length; i++) {
+ PsiClassType element = classesList[i];
+ PsiClass resolved = element.resolve();
+ if (resolved instanceof GrTypeDefinition) {
+ GrTypeDefinition superClass = (GrTypeDefinition)resolved;
+ getSubclasses(superClass).add(aClass);
+ buildSubClassesMap(superClass);
+ }
+ }
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberSelectionTable.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberSelectionTable.java
new file mode 100644
index 000000000000..e50828468907
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GrMemberSelectionTable.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.classMembers;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.psi.PsiMember;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
+import com.intellij.refactoring.ui.AbstractMemberSelectionTable;
+import com.intellij.ui.RowIcon;
+import com.intellij.util.IconUtil;
+import com.intellij.util.VisibilityIcons;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+
+import javax.swing.*;
+import java.util.List;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrMemberSelectionTable extends AbstractMemberSelectionTable {
+
+ public GrMemberSelectionTable(final List memberInfos, String abstractColumnHeader) {
+ this(memberInfos, null, abstractColumnHeader);
+ }
+
+ public GrMemberSelectionTable(final List memberInfos, MemberInfoModel memberInfoModel, String abstractColumnHeader) {
+ super(memberInfos, memberInfoModel, abstractColumnHeader);
+ }
+
+ @Nullable
+ @Override
+ protected Object getAbstractColumnValue(GrMemberInfo memberInfo) {
+ if (!(memberInfo.getMember() instanceof PsiMethod)) return null;
+ if (memberInfo.isStatic()) return null;
+
+ PsiMethod method = (PsiMethod)memberInfo.getMember();
+ if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ final Boolean fixedAbstract = myMemberInfoModel.isFixedAbstract(memberInfo);
+ if (fixedAbstract != null) return fixedAbstract;
+ }
+
+ if (!myMemberInfoModel.isAbstractEnabled(memberInfo)) {
+ return myMemberInfoModel.isAbstractWhenDisabled(memberInfo);
+ }
+ else {
+ return memberInfo.isToAbstract() ? Boolean.TRUE : Boolean.FALSE;
+ }
+ }
+
+ @Override
+ protected boolean isAbstractColumnEditable(int rowIndex) {
+ GrMemberInfo info = myMemberInfos.get(rowIndex);
+ if (!(info.getMember() instanceof PsiMethod)) return false;
+ if (info.isStatic()) return false;
+
+ PsiMethod method = (PsiMethod)info.getMember();
+ if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ if (myMemberInfoModel.isFixedAbstract(info) != null) {
+ return false;
+ }
+ }
+
+ return info.isChecked() && myMemberInfoModel.isAbstractEnabled(info);
+ }
+
+
+ @Override
+ protected void setVisibilityIcon(GrMemberInfo memberInfo, RowIcon icon) {
+ PsiMember member = memberInfo.getMember();
+ PsiModifierList modifiers = member != null ? member.getModifierList() : null;
+ if (modifiers != null) {
+ VisibilityIcons.setVisibilityIcon(modifiers, icon);
+ }
+ else {
+ icon.setIcon(IconUtil.getEmptyIcon(true), VISIBILITY_ICON_POSITION);
+ }
+ }
+
+ @Override
+ protected Icon getOverrideIcon(GrMemberInfo memberInfo) {
+ PsiMember member = memberInfo.getMember();
+ Icon overrideIcon = EMPTY_OVERRIDE_ICON;
+ if (member instanceof PsiMethod) {
+ if (Boolean.TRUE.equals(memberInfo.getOverrides())) {
+ overrideIcon = AllIcons.General.OverridingMethod;
+ }
+ else if (Boolean.FALSE.equals(memberInfo.getOverrides())) {
+ overrideIcon = AllIcons.General.ImplementingMethod;
+ }
+ else {
+ overrideIcon = EMPTY_OVERRIDE_ICON;
+ }
+ }
+ return overrideIcon;
+ }
+}
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GroovyClassMembersRefactoringSupport.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GroovyClassMembersRefactoringSupport.java
new file mode 100644
index 000000000000..46d9b72ff67a
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/classMembers/GroovyClassMembersRefactoringSupport.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.classMembers;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.refactoring.classMembers.ClassMembersRefactoringSupport;
+import com.intellij.refactoring.classMembers.DependentMembersCollectorBase;
+import com.intellij.refactoring.classMembers.MemberInfoBase;
+
+/**
+ * @author Max Medvedev
+ */
+public class GroovyClassMembersRefactoringSupport implements ClassMembersRefactoringSupport {
+ @Override
+ public DependentMembersCollectorBase createDependentMembersCollector(Object clazz, Object superClass) {
+ return new GrDependantMembersCollector((PsiClass)clazz, (PsiClass)superClass);
+ }
+
+ @Override
+ public boolean isProperMember(MemberInfoBase member) {
+ return member instanceof GrMemberInfo;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractInterface/GrExtractInterfaceHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractInterface/GrExtractInterfaceHandler.java
new file mode 100644
index 000000000000..1b7a112e49f5
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractInterface/GrExtractInterfaceHandler.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.extractInterface;
+
+import com.intellij.history.LocalHistory;
+import com.intellij.history.LocalHistoryAction;
+import com.intellij.lang.findUsages.DescriptiveNameUtil;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.refactoring.HelpID;
+import com.intellij.refactoring.RefactoringActionHandler;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.extractInterface.ExtractClassUtil;
+import com.intellij.refactoring.extractSuperclass.ExtractSuperClassUtil;
+import com.intellij.refactoring.lang.ElementsHandler;
+import com.intellij.refactoring.memberPullUp.PullUpHelper;
+import com.intellij.refactoring.util.CommonRefactoringUtil;
+import com.intellij.refactoring.util.DocCommentPolicy;
+import com.intellij.refactoring.util.classMembers.MemberInfo;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+
+import javax.swing.*;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrExtractInterfaceHandler implements RefactoringActionHandler, ElementsHandler {
+ public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
+ int offset = editor.getCaretModel().getOffset();
+ editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
+ PsiElement element = file.findElementAt(offset);
+ while (true) {
+ if (element == null || element instanceof PsiFile) {
+ String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("error.wrong.caret.position.class"));
+ CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.EXTRACT_INTERFACE);
+ return;
+ }
+
+ if (element instanceof GrTypeDefinition && !(element instanceof GrAnonymousClassDefinition)) {
+ invoke(project, new PsiElement[]{element}, dataContext);
+ return;
+ }
+
+ element = element.getParent();
+ }
+ }
+
+ public void invoke(@NotNull final Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
+ if (elements.length != 1) return;
+
+
+ myProject = project;
+ myClass = (PsiClass)elements[0];
+
+
+ if (!CommonRefactoringUtil.checkReadOnlyStatus(project, myClass)) return;
+
+/* todo
+ final JavaExtractSuperBaseDialog dialog = new ExtractInterfaceDialog(myProject, myClass);
+ dialog.show();
+ if (!dialog.isOK() || !dialog.isExtractSuperclass()) return;
+
+ final MultiMap conflicts = new MultiMap();
+ ExtractSuperClassUtil.checkSuperAccessible(dialog.getTargetDirectory(), conflicts, myClass);
+ if (!ExtractSuperClassUtil.showConflicts(dialog, conflicts, myProject)) return;
+
+ CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ myInterfaceName = dialog.getExtractedSuperName();
+ mySelectedMembers = ArrayUtil.toObjectArray(dialog.getSelectedMemberInfos(), MemberInfo.class);
+ myTargetDir = dialog.getTargetDirectory();
+ myJavaDocPolicy = new DocCommentPolicy(dialog.getDocCommentPolicy());
+ try {
+ doRefactoring();
+ }
+ catch (IncorrectOperationException e) {
+ LOG.error(e);
+ }
+ }
+ });
+ }
+ }, REFACTORING_NAME, null);*/
+ }
+
+ private void doRefactoring() throws IncorrectOperationException {
+ LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName());
+ final PsiClass anInterface;
+ try {
+ anInterface = extractInterface(myTargetDir, myClass, myInterfaceName, mySelectedMembers, myJavaDocPolicy);
+ }
+ finally {
+ a.finish();
+ }
+
+
+ if (anInterface != null) {
+ final SmartPsiElementPointer classPointer =
+ SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(myClass);
+ final SmartPsiElementPointer interfacePointer =
+ SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(anInterface);
+ final Runnable turnRefsToSuperRunnable = new Runnable() {
+ @Override
+ public void run() {
+ ExtractClassUtil.askAndTurnRefsToSuper(myProject, classPointer, interfacePointer);
+ }
+ };
+ SwingUtilities.invokeLater(turnRefsToSuperRunnable);
+ }
+ }
+
+ public static PsiClass extractInterface(PsiDirectory targetDir,
+ PsiClass aClass,
+ String interfaceName,
+ MemberInfo[] selectedMembers,
+ DocCommentPolicy javaDocPolicy) throws IncorrectOperationException {
+ PsiClass anInterface = JavaDirectoryService.getInstance().createInterface(targetDir, interfaceName);
+ PsiJavaCodeReferenceElement ref = ExtractSuperClassUtil.createExtendingReference(anInterface, aClass, selectedMembers);
+ final PsiReferenceList referenceList = aClass.isInterface() ? aClass.getExtendsList() : aClass.getImplementsList();
+ assert referenceList != null;
+ referenceList.add(ref);
+ PullUpHelper pullUpHelper = new PullUpHelper(aClass, anInterface, selectedMembers, javaDocPolicy);
+ pullUpHelper.moveMembersToBase();
+ return anInterface;
+ }
+
+ private String getCommandName() {
+ return RefactoringBundle.message("extract.interface.command.name", myInterfaceName, DescriptiveNameUtil.getDescriptiveName(myClass));
+ }
+
+ public boolean isEnabledOnElements(PsiElement[] elements) {
+ return elements.length == 1 && elements[0] instanceof PsiClass;
+ }
+
+ private static final Logger LOG = Logger.getInstance(GrExtractInterfaceHandler.class);
+ public static final String REFACTORING_NAME = RefactoringBundle.message("extract.interface.title");
+ private Project myProject;
+ private PsiClass myClass;
+ private String myInterfaceName;
+ private MemberInfo[] mySelectedMembers;
+ private PsiDirectory myTargetDir;
+ private DocCommentPolicy myJavaDocPolicy;
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpDialog.java
new file mode 100644
index 000000000000..5fc3aa9dbf80
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpDialog.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.memberPullUp;
+
+import com.intellij.openapi.help.HelpManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocCommentOwner;
+import com.intellij.psi.PsiMember;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.statistics.StatisticsInfo;
+import com.intellij.psi.statistics.StatisticsManager;
+import com.intellij.refactoring.HelpID;
+import com.intellij.refactoring.JavaRefactoringSettings;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.classMembers.AbstractUsesDependencyMemberInfoModel;
+import com.intellij.refactoring.classMembers.MemberInfoModel;
+import com.intellij.refactoring.memberPullUp.PullUpDialogBase;
+import com.intellij.refactoring.memberPullUp.PullUpHelper;
+import com.intellij.refactoring.ui.AbstractMemberSelectionTable;
+import com.intellij.refactoring.ui.ClassCellRenderer;
+import com.intellij.refactoring.ui.DocCommentPanel;
+import com.intellij.refactoring.util.DocCommentPolicy;
+import com.intellij.refactoring.util.RefactoringHierarchyUtil;
+import com.intellij.refactoring.util.classMembers.InterfaceContainmentVerifier;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberInfo;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberInfoStorage;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberSelectionTable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.List;
+
+/**
+ * @author Max Medvedev
+ */
+class GrPullUpDialog extends PullUpDialogBase {
+ private final Callback myCallback;
+ private DocCommentPanel myJavaDocPanel;
+
+ private final InterfaceContainmentVerifier myInterfaceContainmentVerifier = new InterfaceContainmentVerifier() {
+ public boolean checkedInterfacesContain(PsiMethod psiMethod) {
+ return PullUpHelper.checkedInterfacesContain(myMemberInfos, psiMethod);
+ }
+ };
+
+ private static final String PULL_UP_STATISTICS_KEY = "pull.up##";
+
+ public interface Callback {
+ boolean checkConflicts(GrPullUpDialog dialog);
+ }
+
+ public GrPullUpDialog(Project project,
+ PsiClass typeDefinition,
+ List superClasses,
+ GrMemberInfoStorage storage,
+ GrPullUpHandler handler) {
+ super(project, typeDefinition, superClasses, storage, GrPullUpHandler.REFACTORING_NAME);
+
+ myCallback = handler;
+
+ init();
+ }
+
+ public int getJavaDocPolicy() {
+ return myJavaDocPanel.getPolicy();
+ }
+
+ protected String getDimensionServiceKey() {
+ return "#com.intellij.refactoring.memberPullUp.PullUpDialog";
+ }
+
+ InterfaceContainmentVerifier getContainmentVerifier() {
+ return myInterfaceContainmentVerifier;
+ }
+
+ @Override
+ protected void initClassCombo(JComboBox classCombo) {
+ classCombo.setRenderer(new ClassCellRenderer(classCombo.getRenderer()));
+ classCombo.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ if (myMemberSelectionPanel != null) {
+ // ((MyMemberInfoModel)myMemberInfoModel).setSuperClass(getSuperClass());
+ myMemberSelectionPanel.getTable().setMemberInfos(myMemberInfos);
+ myMemberSelectionPanel.getTable().fireExternalDataChange();
+ }
+ }
+ }
+ });
+ }
+
+ protected PsiClass getPreselection() {
+ PsiClass preselection = RefactoringHierarchyUtil.getNearestBaseClass(myClass, false);
+
+ final String statKey = PULL_UP_STATISTICS_KEY + myClass.getQualifiedName();
+ for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(statKey)) {
+ final String superClassName = info.getValue();
+ PsiClass superClass = null;
+ for (PsiClass aClass : mySuperClasses) {
+ if (Comparing.strEqual(superClassName, aClass.getQualifiedName())) {
+ superClass = aClass;
+ break;
+ }
+ }
+ if (superClass != null && StatisticsManager.getInstance().getUseCount(info) > 0) {
+ preselection = superClass;
+ break;
+ }
+ }
+ return preselection;
+ }
+
+ protected void doHelpAction() {
+ HelpManager.getInstance().invokeHelp(HelpID.MEMBERS_PULL_UP);
+ }
+
+ protected void doAction() {
+ if (!myCallback.checkConflicts(this)) return;
+ JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC = myJavaDocPanel.getPolicy();
+ final PsiClass superClass = getSuperClass();
+ String name = superClass.getQualifiedName();
+ if (name != null) {
+ StatisticsManager
+ .getInstance().incUseCount(new StatisticsInfo(PULL_UP_STATISTICS_KEY + myClass.getQualifiedName(), name));
+ }
+
+ List infos = getSelectedMemberInfos();
+ GrPullUpHelper processor =
+ new GrPullUpHelper(myClass, superClass, infos.toArray(new GrMemberInfo[infos.size()]), new DocCommentPolicy(getJavaDocPolicy()));
+ invokeRefactoring(processor);
+ close(OK_EXIT_CODE);
+ }
+
+ @Override
+ protected void addCustomElementsToCentralPanel(JPanel panel) {
+ myJavaDocPanel = new DocCommentPanel(RefactoringBundle.message("javadoc.for.abstracts"));
+ myJavaDocPanel.setPolicy(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC);
+ boolean hasJavadoc = false;
+ for (GrMemberInfo info : myMemberInfos) {
+ final PsiMember member = info.getMember();
+ if (myMemberInfoModel.isAbstractEnabled(info) &&
+ member instanceof PsiDocCommentOwner &&
+ ((PsiDocCommentOwner)member).getDocComment() != null) {
+ hasJavadoc = true;
+ break;
+ }
+ }
+ UIUtil.setEnabled(myJavaDocPanel, hasJavadoc, true);
+ panel.add(myJavaDocPanel, BorderLayout.EAST);
+ }
+
+ @Override
+ protected AbstractMemberSelectionTable createMemberSelectionTable(List infos) {
+ return new GrMemberSelectionTable(infos, RefactoringBundle.message("make.abstract"));
+ }
+
+ @Override
+ protected MemberInfoModel createMemberInfoModel() {
+ //return new UsedByDependencyMemberInfoModel(myClass);
+ return new MyMemberInfoModel(myClass, getSuperClass(), false);
+ }
+
+ private static class MyMemberInfoModel extends AbstractUsesDependencyMemberInfoModel {
+ public MyMemberInfoModel(PsiClass aClass, PsiClass superClass, boolean recursive) {
+ super(aClass, superClass, recursive);
+ }
+
+ @Override
+ protected int doCheck(@NotNull GrMemberInfo memberInfo, int problem) {
+ if (problem == ERROR && memberInfo.isStatic()) {
+ return WARNING;
+ }
+ return problem;
+ }
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpHandler.java
new file mode 100644
index 000000000000..533615048f0a
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpHandler.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.memberPullUp;
+
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.psi.*;
+import com.intellij.refactoring.HelpID;
+import com.intellij.refactoring.RefactoringActionHandler;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.classMembers.MemberInfoBase;
+import com.intellij.refactoring.lang.ElementsHandler;
+import com.intellij.refactoring.memberPullUp.PullUpConflictsUtil;
+import com.intellij.refactoring.ui.ConflictsDialog;
+import com.intellij.refactoring.util.CommonRefactoringUtil;
+import com.intellij.refactoring.util.RefactoringHierarchyUtil;
+import com.intellij.util.containers.MultiMap;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberInfo;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberInfoStorage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrPullUpHandler implements RefactoringActionHandler, GrPullUpDialog.Callback, ElementsHandler {
+ private static final Logger LOG = Logger.getInstance(GrPullUpHandler.class);
+ public static final String REFACTORING_NAME = RefactoringBundle.message("pull.members.up.title");
+
+ private PsiClass mySubclass;
+ private Project myProject;
+
+ public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
+ int offset = editor.getCaretModel().getOffset();
+ editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
+ PsiElement element = file.findElementAt(offset);
+
+ while (true) {
+ if (element == null || element instanceof PsiFile) {
+ String message = RefactoringBundle
+ .getCannotRefactorMessage(RefactoringBundle.message("the.caret.should.be.positioned.inside.a.class.to.pull.members.from"));
+ CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PULL_UP);
+ return;
+ }
+
+
+ if (!CommonRefactoringUtil.checkReadOnlyStatus(project, element)) return;
+
+
+ if (element instanceof GrTypeDefinition || element instanceof GrField || element instanceof GrMethod) {
+ invoke(project, new PsiElement[]{element}, dataContext);
+ return;
+ }
+
+ element = element.getParent();
+ }
+ }
+
+ public void invoke(@NotNull final Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
+ if (elements.length != 1) return;
+
+ myProject = project;
+
+ PsiElement element = elements[0];
+ GrTypeDefinition aClass;
+ PsiElement aMember = null;
+
+ if (element instanceof GrTypeDefinition) {
+ aClass = (GrTypeDefinition)element;
+ }
+ else if (element instanceof GrMethod) {
+ aClass = DefaultGroovyMethods.asType(((GrMethod)element).getContainingClass(), GrTypeDefinition.class);
+ aMember = element;
+ }
+ else if (element instanceof GrField) {
+ aClass = DefaultGroovyMethods.asType(((GrField)element).getContainingClass(), GrTypeDefinition.class);
+ aMember = element;
+ }
+ else {
+ return;
+ }
+
+
+ invokeImpl(project, dataContext, aClass, aMember);
+ }
+
+ private void invokeImpl(Project project, DataContext dataContext, GrTypeDefinition aClass, PsiElement aMember) {
+ final Editor editor = dataContext != null ? PlatformDataKeys.EDITOR.getData(dataContext) : null;
+ if (aClass == null) {
+ String message =
+ RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("is.not.supported.in.the.current.context", REFACTORING_NAME));
+ CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PULL_UP);
+ return;
+ }
+
+
+ ArrayList bases = RefactoringHierarchyUtil.createBasesList(aClass, false, true);
+
+ if (bases.isEmpty()) {
+ final GrTypeDefinition containingClass = DefaultGroovyMethods.asType(aClass.getContainingClass(), GrTypeDefinition.class);
+ if (containingClass != null) {
+ invokeImpl(project, dataContext, containingClass, aClass);
+ return;
+ }
+
+ String message = RefactoringBundle.getCannotRefactorMessage(
+ RefactoringBundle.message("class.does.not.have.base.classes.interfaces.in.current.project", aClass.getQualifiedName()));
+ CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.MEMBERS_PULL_UP);
+ return;
+ }
+
+
+ mySubclass = aClass;
+ GrMemberInfoStorage memberInfoStorage = new GrMemberInfoStorage((GrTypeDefinition)mySubclass, new MemberInfoBase.Filter() {
+ public boolean includeMember(GrMember element) {
+ return true;
+ }
+ });
+ List members = memberInfoStorage.getClassMemberInfos(mySubclass);
+ PsiManager manager = mySubclass.getManager();
+
+ for (GrMemberInfo member : members) {
+ if (manager.areElementsEquivalent(member.getMember(), aMember)) {
+ member.setChecked(true);
+ break;
+ }
+ }
+
+
+ final GrPullUpDialog dialog = new GrPullUpDialog(project, aClass, bases, memberInfoStorage, this);
+ dialog.show();
+ }
+
+ public boolean checkConflicts(final GrPullUpDialog dialog) {
+ /* todo */
+ List _infos = dialog.getSelectedMemberInfos();
+ final GrMemberInfo[] infos = _infos.toArray(new GrMemberInfo[_infos.size()]);
+ final PsiClass superClass = dialog.getSuperClass();
+ if (!checkWritable(superClass, infos)) return false;
+ final MultiMap conflicts = new MultiMap();
+ if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
+ public void run() {
+ final PsiDirectory targetDirectory = superClass.getContainingFile().getContainingDirectory();
+ final PsiPackage targetPackage = targetDirectory != null ? JavaDirectoryService.getInstance().getPackage(targetDirectory) : null;
+ conflicts.putAllValues(PullUpConflictsUtil.checkConflicts(infos, mySubclass, superClass, targetPackage, targetDirectory,
+ dialog.getContainmentVerifier()));
+ }
+ }, RefactoringBundle.message("detecting.possible.conflicts"), true, myProject)) {
+ return false;
+ }
+ if (!conflicts.isEmpty()) {
+ ConflictsDialog conflictsDialog = new ConflictsDialog(myProject, conflicts);
+ conflictsDialog.show();
+ final boolean ok = conflictsDialog.isOK();
+ if (!ok && conflictsDialog.isShowConflicts()) dialog.close(DialogWrapper.CANCEL_EXIT_CODE);
+ return ok;
+ }
+
+ return true;
+ }
+
+ private boolean checkWritable(PsiClass superClass, GrMemberInfo[] infos) {
+ if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, superClass)) return false;
+ for (GrMemberInfo info : infos) {
+ if (info.getMember() instanceof PsiClass && info.getOverrides() != null) continue;
+ if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, info.getMember())) return false;
+ }
+
+ return true;
+ }
+
+ public boolean isEnabledOnElements(PsiElement[] elements) {
+ return elements.length == 1 && elements[0] instanceof PsiClass;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpHelper.java
new file mode 100644
index 000000000000..0a9972ca276d
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpHelper.java
@@ -0,0 +1,711 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.memberPullUp;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.codeInsight.intention.AddAnnotationFix;
+import com.intellij.lang.findUsages.DescriptiveNameUtil;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.searches.OverridingMethodsSearch;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.util.MethodSignatureUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.TypeConversionUtil;
+import com.intellij.refactoring.BaseRefactoringProcessor;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.listeners.JavaRefactoringListenerManager;
+import com.intellij.refactoring.listeners.impl.JavaRefactoringListenerManagerImpl;
+import com.intellij.refactoring.util.DocCommentPolicy;
+import com.intellij.refactoring.util.RefactoringHierarchyUtil;
+import com.intellij.refactoring.util.RefactoringUIUtil;
+import com.intellij.refactoring.util.RefactoringUtil;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.usageView.UsageViewDescriptor;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.containers.ContainerUtil;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
+import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrClassMemberReferenceVisitor;
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberInfo;
+
+import java.util.*;
+
+/**
+ * @author Max Medvedev
+ */
+public class GrPullUpHelper extends BaseRefactoringProcessor {
+ private static final Logger LOG = Logger.getInstance(GrPullUpHelper.class);
+ private static final Key SUPER_REF = Key.create("SUPER_REF");
+ private static final Key THIS_REF = Key.create("THIS_REF");
+ private static final Key PRESERVE_QUALIFIER = Key.create("PRESERVE_QUALIFIER");
+
+ private PsiClass mySourceClass;
+ private GrTypeDefinition myTargetSuperClass;
+ private GrMemberInfo[] myMembersToMove;
+ private DocCommentPolicy myDocCommentPolicy;
+ private Set myMembersAfterMove;
+
+
+ public GrPullUpHelper(PsiClass aClass, PsiClass superClass, GrMemberInfo[] infos, DocCommentPolicy policy) {
+ super(aClass.getProject());
+
+ mySourceClass = aClass;
+ myTargetSuperClass = (GrTypeDefinition)superClass;
+ myMembersToMove = infos;
+ myDocCommentPolicy = policy;
+ }
+
+ @NotNull
+ @Override
+ protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
+ return new UsageViewDescriptor() {
+ public String getProcessedElementsHeader() {
+ return "Pull up members from";
+ }
+
+ @NotNull
+ public PsiElement[] getElements() {
+ return new PsiClass[]{mySourceClass};
+ }
+
+ public String getCodeReferencesText(int usagesCount, int filesCount) {
+ return "Class to pull up members to \"" + RefactoringUIUtil.getDescription(myTargetSuperClass, true) + "\"";
+ }
+
+ public String getCommentReferencesText(int usagesCount, int filesCount) {
+ return null;
+ }
+ };
+ }
+
+ @NotNull
+ @Override
+ protected UsageInfo[] findUsages() {
+ final List result = new ArrayList();
+ for (GrMemberInfo info : myMembersToMove) {
+ final PsiMember member = info.getMember();
+ if (member.hasModifierProperty(PsiModifier.STATIC)) {
+ for (PsiReference reference : ReferencesSearch.search(member)) {
+ result.add(new UsageInfo(reference));
+ }
+ }
+ }
+
+ return DefaultGroovyMethods.asType(result, UsageInfo[].class);
+ }
+
+ @Override
+ protected void performRefactoring(UsageInfo[] usages) {
+ moveMembersToBase();
+ //moveFieldInitializations(); todo
+ for (UsageInfo usage : usages) {
+ PsiElement element = usage.getElement();
+ if (element instanceof GrReferenceExpression) {
+ GrExpression qualifier = ((GrReferenceExpression)element).getQualifier();
+ if (qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).resolve().equals(mySourceClass)) {
+ ((GrReferenceExpression)qualifier).bindToElement(myTargetSuperClass);
+ }
+ }
+ }
+
+ /*
+ todo
+ ApplicationManager.application.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ processMethodsDuplicates();
+ }
+ }, ModalityState.NON_MODAL, myProject.getDisposed());*/
+
+ }
+
+ @Override
+ protected String getCommandName() {
+ return RefactoringBundle.message("pullUp.command", DescriptiveNameUtil.getDescriptiveName(mySourceClass));
+ }
+
+ public void moveMembersToBase() throws IncorrectOperationException {
+ final HashSet movedMembers = ContainerUtil.newHashSet();
+ myMembersAfterMove = ContainerUtil.newHashSet();
+
+ // build aux sets
+ for (GrMemberInfo info : myMembersToMove) {
+ movedMembers.add(info.getMember());
+ }
+
+
+ // correct private member visibility
+ for (GrMemberInfo info : myMembersToMove) {
+ if (info.getMember() instanceof PsiClass && info.getOverrides() != null) continue;
+ setCorrectVisibility(movedMembers, info);
+ GroovyChangeContextUtil.encodeContextInfo(info.getMember());
+ info.getMember().accept(new QualifiedThisSuperSearcher());
+ fixReferencesToStatic(info.getMember(), movedMembers);
+ }
+
+
+
+
+ final PsiSubstitutor substitutor = upDownSuperClassSubstitutor();
+
+ // do actual move
+ for (GrMemberInfo info : myMembersToMove) {
+ if (info.getMember() instanceof PsiMethod) {
+ doMoveMethod(movedMembers, substitutor, info);
+ }
+ else if (info.getMember() instanceof GrField) {
+ doMoveField(movedMembers, substitutor, info);
+ }
+ else if (info.getMember() instanceof PsiClass) {
+ doMoveClass(movedMembers, substitutor, info);
+ }
+ }
+
+
+ ExplicitSuperDeleter explicitSuperDeleter = new ExplicitSuperDeleter();
+ for (PsiMember member : myMembersAfterMove) {
+ ((GrMember)member).accept(explicitSuperDeleter);
+ }
+ explicitSuperDeleter.fixSupers();
+
+ final QualifiedThisSuperAdjuster qualifiedThisSuperAdjuster = new QualifiedThisSuperAdjuster();
+ for (PsiMember member : myMembersAfterMove) {
+ ((GrMember)member).accept(qualifiedThisSuperAdjuster);
+ }
+
+ for (PsiMember member : myMembersAfterMove) {
+ GroovyChangeContextUtil.decodeContextInfo(member, null, null);
+ }
+
+
+ final JavaRefactoringListenerManagerImpl listenerManager = (JavaRefactoringListenerManagerImpl)JavaRefactoringListenerManager.getInstance(myProject);
+ for (final PsiMember movedMember : myMembersAfterMove) {
+ ((GroovyPsiElement)movedMember).accept(new GroovyRecursiveElementVisitor() {
+ @Override
+ public void visitReferenceExpression(GrReferenceExpression referenceExpression) {
+ if (processRef(referenceExpression)) return;
+ super.visitReferenceExpression(referenceExpression);
+ }
+
+ @Override
+ public void visitCodeReferenceElement(GrCodeReferenceElement refElement) {
+ if (processRef(refElement)) return;
+ super.visitCodeReferenceElement(refElement);
+ }
+
+ private boolean processRef(@NotNull GrReferenceElement extends GroovyPsiElement> refElement) {
+ final PsiElement qualifier = refElement.getQualifier();
+ if (qualifier != null) {
+ final Boolean preserveQualifier = qualifier.getCopyableUserData(PRESERVE_QUALIFIER);
+ if (preserveQualifier != null && !preserveQualifier) {
+ refElement.setQualifier(null);
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ listenerManager.fireMemberMoved(mySourceClass, movedMember);
+ }
+ }
+
+ private PsiSubstitutor upDownSuperClassSubstitutor() {
+ PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
+ for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(mySourceClass)) {
+ substitutor = substitutor.put(parameter, null);
+ }
+
+ final Map substitutionMap =
+ TypeConversionUtil.getSuperClassSubstitutor(myTargetSuperClass, mySourceClass, PsiSubstitutor.EMPTY).getSubstitutionMap();
+ for (PsiTypeParameter parameter : substitutionMap.keySet()) {
+ final PsiType type = substitutionMap.get(parameter);
+ final PsiClass resolvedClass = PsiUtil.resolveClassInType(type);
+ if (resolvedClass instanceof PsiTypeParameter) {
+ substitutor = substitutor.put((PsiTypeParameter)resolvedClass, JavaPsiFacade.getElementFactory(myProject).createType(parameter));
+ }
+ }
+
+ return substitutor;
+ }
+
+ public void setCorrectVisibility(final HashSet movedMembers, GrMemberInfo info) {
+ PsiModifierListOwner modifierListOwner = info.getMember();
+ if (myTargetSuperClass.isInterface()) {
+ PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PUBLIC, true);
+ }
+ else if (modifierListOwner.hasModifierProperty(PsiModifier.PRIVATE)) {
+ if (info.isToAbstract() || willBeUsedInSubclass(modifierListOwner, movedMembers, myTargetSuperClass, mySourceClass)) {
+ PsiUtil.setModifierProperty(modifierListOwner, PsiModifier.PROTECTED, true);
+ }
+
+ if (modifierListOwner instanceof GrTypeDefinition) {
+ ((GrTypeDefinition)modifierListOwner).accept(new GroovyRecursiveElementVisitor() {
+ @Override
+ public void visitMethod(GrMethod method) {
+ check(method);
+ }
+
+ @Override
+ public void visitField(GrField field) {
+ check(field);
+ }
+
+ @Override
+ public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
+ check(typeDefinition);
+ super.visitTypeDefinition(typeDefinition);
+ }
+
+ private void check(PsiMember member) {
+ if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
+ if (willBeUsedInSubclass(member, movedMembers, myTargetSuperClass, mySourceClass)) {
+ PsiUtil.setModifierProperty(member, PsiModifier.PROTECTED, true);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private static boolean willBeUsedInSubclass(PsiElement member, Set movedMembers, PsiClass superclass, PsiClass subclass) {
+ for (PsiReference ref : ReferencesSearch.search(member, new LocalSearchScope(subclass), false)) {
+ PsiElement element = ref.getElement();
+ if (!RefactoringHierarchyUtil.willBeInTargetClass(element, movedMembers, superclass, false)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void doMoveMethod(Set movedMembers, PsiSubstitutor substitutor, GrMemberInfo info) {
+ GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
+ GrMethod method = (GrMethod)info.getMember();
+ PsiMethod sibling = method;
+ PsiMethod anchor = null;
+ while (sibling != null) {
+ sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class);
+ if (sibling != null) {
+ anchor = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(method.getContainingClass(), myTargetSuperClass,
+ sibling.getSignature(PsiSubstitutor.EMPTY), false);
+ if (anchor != null) {
+ break;
+ }
+ }
+ }
+
+ GrMethod methodCopy = (GrMethod)method.copy();
+ if (method.findSuperMethods(myTargetSuperClass).length == 0) {
+ deleteOverrideAnnotationIfFound(methodCopy);
+ }
+
+ final boolean isOriginalMethodAbstract =
+ method.hasModifierProperty(PsiModifier.ABSTRACT) || method.hasModifierProperty(PsiModifier.DEFAULT);
+ if (myTargetSuperClass.isInterface() || info.isToAbstract()) {
+ GroovyChangeContextUtil.clearContextInfo(method);
+ RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy);
+ replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
+
+ myDocCommentPolicy.processCopiedJavaDoc(methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract);
+
+ final PsiMember movedElement =
+ anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy);
+ CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject());
+ if (styleSettings.INSERT_OVERRIDE_ANNOTATION) {
+ if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myTargetSuperClass.isInterface() ||
+ PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) {
+ new AddAnnotationFix(CommonClassNames.JAVA_LANG_OVERRIDE, method)
+ .invoke(method.getProject(), null, mySourceClass.getContainingFile());
+ }
+ }
+
+ if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myTargetSuperClass.isInterface()) {
+ if (isOriginalMethodAbstract) {
+ for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) {
+ deleteOverrideAnnotationIfFound(oMethod);
+ }
+ }
+
+ deleteOverrideAnnotationIfFound(method);
+ }
+
+ myMembersAfterMove.add(movedElement);
+ if (isOriginalMethodAbstract) {
+ method.delete();
+ }
+ }
+ else {
+ if (isOriginalMethodAbstract) {
+ PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true);
+ }
+
+ //fixReferencesToStatic(methodCopy, movedMembers);
+ replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
+ final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false);
+ if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ superClassMethod.replace(methodCopy);
+ }
+ else {
+ final PsiMember movedElement =
+ anchor != null ? (PsiMember)myTargetSuperClass.addBefore(methodCopy, anchor) : (PsiMember)myTargetSuperClass.add(methodCopy);
+ myMembersAfterMove.add(movedElement);
+ }
+
+ method.delete();
+ }
+ }
+
+ private static void deleteOverrideAnnotationIfFound(PsiMethod oMethod) {
+ final PsiAnnotation annotation = AnnotationUtil.findAnnotation(oMethod, CommonClassNames.JAVA_LANG_OVERRIDE);
+ if (annotation != null) {
+ annotation.delete();
+ }
+ }
+
+ public static void replaceMovedMemberTypeParameters(final PsiElement member,
+ final Iterable parametersIterable,
+ final PsiSubstitutor substitutor,
+ final GroovyPsiElementFactory factory) {
+ final Map replacement = new LinkedHashMap();
+ for (PsiTypeParameter parameter : parametersIterable) {
+ PsiType substitutedType = substitutor.substitute(parameter);
+ if (substitutedType == null) {
+ substitutedType = TypeConversionUtil.erasure(factory.createType(parameter));
+ }
+
+ PsiElement scopeElement = member instanceof GrField ? member.getParent() : member;
+ for (PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(scopeElement))) {
+ final PsiElement element = reference.getElement();
+ final PsiElement parent = element.getParent();
+ if (parent instanceof PsiTypeElement) {
+ replacement.put(parent, factory.createTypeElement(substitutedType));
+ }
+ else if (element instanceof GrCodeReferenceElement && substitutedType instanceof PsiClassType) {
+ replacement.put(element, factory.createReferenceElementByType((PsiClassType)substitutedType));
+ }
+ }
+ }
+
+ for (PsiElement element : replacement.keySet()) {
+ if (element.isValid()) {
+ element.replace(replacement.get(element));
+ }
+ }
+ }
+
+ private void fixReferencesToStatic(GroovyPsiElement classMember, Set movedMembers) throws IncorrectOperationException {
+ final StaticReferencesCollector collector = new StaticReferencesCollector(movedMembers);
+ classMember.accept(collector);
+ ArrayList refs = collector.getReferences();
+ ArrayList members = collector.getReferees();
+ ArrayList classes = collector.getRefereeClasses();
+ GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject);
+
+ for (int i = 0; i < refs.size(); i++) {
+ GrReferenceElement ref = refs.get(i);
+ PsiElement namedElement = members.get(i);
+ PsiClass aClass = classes.get(i);
+
+ if (namedElement instanceof PsiNamedElement) {
+ GrReferenceExpression newRef = (GrReferenceExpression)factory.createExpressionFromText("a." + ((PsiNamedElement)namedElement).getName(), null);
+ GrExpression qualifier = newRef.getQualifierExpression();
+ assert qualifier != null;
+ qualifier = (GrExpression)qualifier.replace(factory.createReferenceExpressionFromText(aClass.getQualifiedName()));
+ qualifier.putCopyableUserData(PRESERVE_QUALIFIER, ref.isQualified());
+ PsiElement replaced = ref.replace(newRef);
+ JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(replaced);
+ }
+ }
+ }
+
+
+ private class StaticReferencesCollector extends GrClassMemberReferenceVisitor {
+ private final ArrayList myReferences = new ArrayList();
+ private final ArrayList myReferees = new ArrayList();
+ private final ArrayList myRefereeClasses = new ArrayList();
+ private final Set myMovedMembers;
+
+ private StaticReferencesCollector(Set movedMembers) {
+ super(mySourceClass);
+ myMovedMembers = movedMembers;
+ }
+
+ public ArrayList getReferees() {
+ return myReferees;
+ }
+
+ public ArrayList getRefereeClasses() {
+ return myRefereeClasses;
+ }
+
+ public ArrayList getReferences() {
+ return myReferences;
+ }
+
+ @Override
+ protected void visitClassMemberReferenceElement(GrMember classMember, GrReferenceElement classMemberReference) {
+ if (classMember.hasModifierProperty(PsiModifier.STATIC) /*&& classMemberReference.isQualified()*/) {
+ if (!myMovedMembers.contains(classMember) &&
+ RefactoringHierarchyUtil.isMemberBetween(myTargetSuperClass, mySourceClass, classMember)) {
+ myReferences.add(classMemberReference);
+ myReferees.add(classMember);
+ myRefereeClasses.add(classMember.getContainingClass());
+ }
+ else if (myMovedMembers.contains(classMember) || myMembersAfterMove.contains(classMember)) {
+ myReferences.add(classMemberReference);
+ myReferees.add(classMember);
+ myRefereeClasses.add(myTargetSuperClass);
+ }
+ }
+ }
+ }
+
+ private class ExplicitSuperDeleter extends GroovyRecursiveElementVisitor {
+ private final ArrayList mySupersToDelete = ContainerUtil.newArrayList();
+ private final ArrayList mySupersToChangeToThis = ContainerUtil.newArrayList();
+
+ @Override
+ public void visitReferenceExpression(GrReferenceExpression expression) {
+ super.visitReferenceExpression(expression);
+ if(org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isSuperReference(expression.getQualifierExpression())) {
+ PsiElement resolved = expression.resolve();
+ if (resolved == null || resolved instanceof PsiMethod && shouldFixSuper((PsiMethod) resolved)) {
+ mySupersToDelete.add(expression.getQualifierExpression());
+ }
+ }
+ else if (org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isSuperReference(expression)) {
+ mySupersToChangeToThis.add(expression);
+ }
+ }
+
+ @Override
+ public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
+ //do nothing
+ }
+
+ private boolean shouldFixSuper(PsiMethod method) {
+ for (PsiMember element : myMembersAfterMove) {
+ if (element instanceof PsiMethod) {
+ PsiMethod member = (PsiMethod)element;
+ // if there is such member among moved members, super qualifier
+ // should not be removed
+ final PsiManager manager = method.getManager();
+ if (manager.areElementsEquivalent(member.getContainingClass(), method.getContainingClass()) &&
+ MethodSignatureUtil.areSignaturesEqual(member, method)) {
+ return false;
+ }
+ }
+ }
+
+ final PsiMethod methodFromSuper = myTargetSuperClass.findMethodBySignature(method, false);
+ return methodFromSuper == null;
+ }
+
+ public void fixSupers() throws IncorrectOperationException {
+ final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject);
+ GrReferenceExpression thisExpression = (GrReferenceExpression) factory.createExpressionFromText("this", null);
+ for (GrExpression expression : mySupersToDelete) {
+ expression.delete();
+ }
+
+ for (GrReferenceExpression superExpression : mySupersToChangeToThis) {
+ superExpression.replace(thisExpression);
+ }
+ }
+ }
+
+ private class QualifiedThisSuperAdjuster extends GroovyRecursiveElementVisitor {
+ @Override
+ public void visitReferenceExpression(GrReferenceExpression expression) {
+ super.visitReferenceExpression(expression);
+ if (expression.getCopyableUserData(SUPER_REF) != null) {
+ expression.putCopyableUserData(SUPER_REF, null);
+ final GrExpression qualifier = expression.getQualifier();
+ if (qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).isReferenceTo(mySourceClass)) {
+ try {
+ GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject);
+ GrExpression newExpr = factory.createExpressionFromText(myTargetSuperClass.getName() + ".this", null);
+ expression.replace(newExpr);
+ }
+ catch (IncorrectOperationException e) {
+ LOG.error(e);
+ }
+ }
+ }
+ else if (expression.getCopyableUserData(THIS_REF) != null) {
+ expression.putCopyableUserData(THIS_REF, null);
+ final GrExpression qualifier = expression.getQualifier();
+ if (qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).isReferenceTo(mySourceClass)) {
+ try {
+ ((GrReferenceExpression)qualifier).bindToElement(myTargetSuperClass);
+ GroovyChangeContextUtil.clearContextInfo(qualifier);
+ }
+ catch (IncorrectOperationException e) {
+ LOG.error(e);
+ }
+ }
+ }
+ }
+ }
+
+ private void doMoveField(Set movedMembers, PsiSubstitutor substitutor, GrMemberInfo info) {
+ GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
+ GrField field = (GrField)info.getMember();
+ field.normalizeDeclaration();
+ replaceMovedMemberTypeParameters(field, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
+ //fixReferencesToStatic(field, movedMembers);
+ if (myTargetSuperClass.isInterface()) {
+ PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true);
+ }
+ final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(field);
+ myMembersAfterMove.add(movedElement);
+ field.delete();
+ }
+
+ private void doMoveClass(Set movedMembers, PsiSubstitutor substitutor, GrMemberInfo info) {
+ GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(myProject);
+ GrTypeDefinition aClass = (GrTypeDefinition)info.getMember();
+ if (Boolean.FALSE.equals(info.getOverrides())) {
+ final GrReferenceList sourceReferenceList = info.getSourceReferenceList();
+ LOG.assertTrue(sourceReferenceList != null);
+ GrCodeReferenceElement ref = mySourceClass.equals(sourceReferenceList.getParent()) ?
+ removeFromReferenceList(sourceReferenceList, aClass) :
+ findReferenceToClass(sourceReferenceList, aClass);
+ if (ref != null && !myTargetSuperClass.isInheritor(aClass, false)) {
+ replaceMovedMemberTypeParameters(ref, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
+ GrReferenceList referenceList;
+ if (myTargetSuperClass.isInterface()) {
+ referenceList = myTargetSuperClass.getExtendsClause();
+ if (referenceList == null) {
+ GrExtendsClause newClause = GroovyPsiElementFactory.getInstance(myProject).createExtendsClause();
+ PsiElement anchor = myTargetSuperClass.getTypeParameterList() != null ? myTargetSuperClass.getTypeParameterList():
+ myTargetSuperClass.getNameIdentifierGroovy();
+ referenceList = (GrReferenceList)myTargetSuperClass.addAfter(newClause, anchor);
+ //CodeStyleManager.getInstance(myProject).reformat(referenceList);
+ //myTargetSuperClass.getNode().addLeaf(TokenType.WHITE_SPACE, " ", referenceList.getNode());
+ }
+ }
+ else {
+ referenceList = myTargetSuperClass.getImplementsClause();
+
+ if (referenceList == null) {
+ GrImplementsClause newClause = GroovyPsiElementFactory.getInstance(myProject).createImplementsClause();
+ PsiElement anchor = myTargetSuperClass.getExtendsClause() != null ? myTargetSuperClass.getExtendsClause() :
+ myTargetSuperClass.getTypeParameterList() != null ? myTargetSuperClass.getTypeParameterList() :
+ myTargetSuperClass.getNameIdentifierGroovy();
+ referenceList = (GrReferenceList)myTargetSuperClass.addAfter(newClause, anchor);
+ //CodeStyleManager.getInstance(myProject).reformat(referenceList);
+ //myTargetSuperClass.getNode().addLeaf(TokenType.WHITE_SPACE, " ", referenceList.getNode());
+ }
+
+ }
+
+ assert referenceList != null;
+ referenceList.add(ref);
+ }
+ }
+ else {
+ replaceMovedMemberTypeParameters(aClass, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
+ //fixReferencesToStatic(aClass, movedMembers);
+ PsiMember movedElement = (PsiMember)myTargetSuperClass.addAfter(aClass, null);
+ //movedElement = (PsiMember)CodeStyleManager.getInstance(myProject).reformat(movedElement);
+ myMembersAfterMove.add(movedElement);
+ aClass.delete();
+ }
+ }
+
+ public static GrCodeReferenceElement findReferenceToClass(GrReferenceList refList, PsiClass aClass) {
+ GrCodeReferenceElement[] refs = refList.getReferenceElements();
+ for (GrCodeReferenceElement ref : refs) {
+ if (ref.isReferenceTo(aClass)) {
+ return ref;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * removes a reference to the specified class from the reference list given
+ *
+ * @return if removed - a reference to the class or null if there were no references to this class in the reference list
+ */
+ public static GrCodeReferenceElement removeFromReferenceList(GrReferenceList refList, PsiClass aClass)
+ throws IncorrectOperationException {
+ GrCodeReferenceElement[] refs = refList.getReferenceElements();
+ for (GrCodeReferenceElement ref : refs) {
+ if (ref.isReferenceTo(aClass)) {
+ GrCodeReferenceElement refCopy = (GrCodeReferenceElement)ref.copy();
+ ref.delete();
+ return refCopy;
+ }
+ }
+ return null;
+ }
+
+ private class QualifiedThisSuperSearcher extends GroovyRecursiveElementVisitor {
+ @Override
+ public void visitReferenceExpression(GrReferenceExpression expression) {
+ super.visitReferenceExpression(expression);
+ if (org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isSuperReference(expression)) {
+ final GrExpression qualifier = expression.getQualifier();
+ if (qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).isReferenceTo(mySourceClass)) {
+ try {
+ expression.putCopyableUserData(SUPER_REF, Boolean.TRUE);
+ }
+ catch (IncorrectOperationException e) {
+ LOG.error(e);
+ }
+ }
+ }
+ else if (org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isThisReference(expression)) {
+ final GrExpression qualifier = expression.getQualifier();
+ if (qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).isReferenceTo(mySourceClass)) {
+ try {
+ expression.putCopyableUserData(THIS_REF, Boolean.TRUE);
+ }
+ catch (IncorrectOperationException e) {
+ LOG.error(e);
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpTest.groovy
new file mode 100644
index 000000000000..e510154844f9
--- /dev/null
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/memberPullUp/GrPullUpTest.groovy
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2000-2013 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 org.jetbrains.plugins.groovy.refactoring.memberPullUp
+
+import com.intellij.psi.*
+import com.intellij.psi.util.PsiTreeUtil
+import com.intellij.refactoring.listeners.JavaRefactoringListenerManager
+import com.intellij.refactoring.listeners.MoveMemberListener
+import com.intellij.refactoring.util.DocCommentPolicy
+import com.intellij.util.ui.UIUtil
+import junit.framework.Assert
+import org.jetbrains.plugins.groovy.LightGroovyTestCase
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember
+import org.jetbrains.plugins.groovy.refactoring.classMembers.GrMemberInfo
+import org.jetbrains.plugins.groovy.util.TestUtils
+/**
+ * Created by Max Medvedev on 8/17/13
+ */
+class GrPullUpTest extends LightGroovyTestCase {
+ @Override
+ protected String getBasePath() {
+ TestUtils.testDataPath + 'refactoring/pullUp'
+ }
+
+ public void testQualifiedThis() {
+ doTest(new MemberDescriptor("Inner", PsiClass));
+ }
+
+ public void testQualifiedSuper() {
+ doTest(new MemberDescriptor("Inner", PsiClass));
+ }
+
+ public void testQualifiedReference() { // IDEADEV-25008
+ doTest(new MemberDescriptor("x", PsiField),
+ new MemberDescriptor("getX", PsiMethod),
+ new MemberDescriptor("setX", PsiMethod));
+ }
+
+ public void testPullUpInheritedStaticClasses() {
+ doTest(new MemberDescriptor("C", PsiClass),
+ new MemberDescriptor("D", PsiClass));
+ }
+
+ public void testPullUpPrivateInnerClassWithPrivateConstructor() {
+ doTest(new MemberDescriptor("C", PsiClass));
+ }
+
+ public void testPullUpAndMakeAbstract() {
+ doTest(new MemberDescriptor("a", PsiMethod),
+ new MemberDescriptor("b", PsiMethod, true));
+ }
+
+ public void _testTryCatchFieldInitializer() {
+ doTest(new MemberDescriptor("field", PsiField));
+ }
+
+ public void testIfFieldInitializationWithNonMovedField() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void _testIfFieldMovedInitialization() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void _testMultipleConstructorsFieldInitialization() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void _testMultipleConstructorsFieldInitializationNoGood() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void _testRemoveOverride() {
+ doTest(new MemberDescriptor("get", PsiMethod));
+ }
+
+ public void testTypeParamErasure() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void testTypeParamSubst() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void testTypeArgument() {
+ doTest(new MemberDescriptor("f", PsiField));
+ }
+
+ public void testGenericsInAbstractMethod() {
+ doTest(new MemberDescriptor("method", PsiMethod, true));
+ }
+
+ public void _testReplaceDuplicatesInInheritors() {
+ doTest(new MemberDescriptor("foo", PsiMethod, false));
+ }
+
+ public void testGenericsInImplements() {
+ doTest(false, new MemberDescriptor("I", PsiClass));
+ }
+
+ public void testUpdateStaticRefs() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ public void testRemoveOverrideFromPulledMethod() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ public void testPreserveOverrideInPulledMethod() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ public void testMergeInterfaces() {
+ doTest(false, new MemberDescriptor("I", PsiClass));
+ }
+
+ public void testTypeParamsConflictingNames() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ public void testEscalateVisibility() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ public void testExtensionMethod() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ public void testPreserveOverride() {
+ doTest(false, new MemberDescriptor("foo", PsiMethod));
+ }
+
+ private void doTest(MemberDescriptor... membersToFind) {
+ doTest(true, membersToFind);
+ }
+
+ private void doTest(final boolean checkMembersMovedCount, MemberDescriptor... membersToFind) {
+ myFixture.configureByFile(getTestName(false) + ".groovy");
+ PsiElement elementAt = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
+ final PsiClass sourceClass = PsiTreeUtil.getParentOfType(elementAt, PsiClass);
+ assertNotNull(sourceClass);
+
+ PsiClass targetClass = sourceClass.getSuperClass();
+ assertNotNull(targetClass);
+ if (!targetClass.isWritable()) {
+ final PsiClass[] interfaces = sourceClass.getInterfaces();
+ assertEquals(1, interfaces.length);
+ assertTrue(interfaces[0].isWritable());
+ targetClass = interfaces[0];
+ }
+ GrMemberInfo[] infos = findMembers(sourceClass, membersToFind);
+
+ final int[] countMoved = [0];
+ final MoveMemberListener listener = new MoveMemberListener() {
+ @Override
+ public void memberMoved(PsiClass aClass, PsiMember member) {
+ assertEquals(sourceClass, aClass);
+ countMoved[0]++;
+ }
+ };
+ JavaRefactoringListenerManager.getInstance(getProject()).addMoveMembersListener(listener);
+ final GrPullUpHelper helper = new GrPullUpHelper(sourceClass, targetClass, infos, new DocCommentPolicy(DocCommentPolicy.ASIS));
+ helper.run();
+ UIUtil.dispatchAllInvocationEvents();
+ JavaRefactoringListenerManager.getInstance(getProject()).removeMoveMembersListener(listener);
+ if (checkMembersMovedCount) {
+ assertEquals(countMoved[0], membersToFind.length);
+ }
+ myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
+ }
+
+ public static class MemberDescriptor {
+ private String myName;
+ private Class extends PsiMember> myClass;
+ private boolean myAbstract;
+
+ public MemberDescriptor(String name, Class extends PsiMember> aClass, boolean isAbstract) {
+ myName = name;
+ myClass = aClass;
+ myAbstract = isAbstract;
+ }
+
+
+ public MemberDescriptor(String name, Class extends PsiMember> aClass) {
+ this(name, aClass, false);
+ }
+ }
+
+ public static GrMemberInfo[] findMembers(final PsiClass sourceClass, final MemberDescriptor... membersToFind) {
+ GrMemberInfo[] infos = new GrMemberInfo[membersToFind.length]
+ for (int i = 0; i < membersToFind.length; i++) {
+ final Class extends PsiMember> clazz = membersToFind[i].myClass
+ final String name = membersToFind[i].myName
+ PsiMember member = null
+ boolean overrides = false
+ GrReferenceList refList = null
+ if (PsiClass.isAssignableFrom(clazz)) {
+ member = sourceClass.findInnerClassByName(name, false)
+ if (member == null) {
+ final PsiClass[] supers = sourceClass.getSupers()
+ for (PsiClass superTypeClass : supers) {
+ if (superTypeClass.getName().equals(name)) {
+ member = superTypeClass
+ overrides = true
+ refList = superTypeClass.isInterface() ?
+ (sourceClass as GrTypeDefinition).getImplementsClause() :
+ (sourceClass as GrTypeDefinition).getExtendsClause()
+ break
+ }
+ }
+ }
+
+ } else if (PsiMethod.class.isAssignableFrom(clazz)) {
+ final PsiMethod[] methods = sourceClass.findMethodsByName(name, false)
+ Assert.assertEquals(1, methods.length)
+ member = methods[0]
+ } else if (PsiField.class.isAssignableFrom(clazz)) {
+ member = sourceClass.findFieldByName(name, false)
+ }
+
+ assertNotNull(member)
+ assertInstanceOf(member, GrMember)
+ infos[i] = new GrMemberInfo(member as GrMember, overrides, refList)
+ infos[i].setToAbstract(membersToFind[i].myAbstract)
+ }
+ return infos
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/EscalateVisibility.groovy b/plugins/groovy/testdata/refactoring/pullUp/EscalateVisibility.groovy
new file mode 100644
index 000000000000..6f50634df5a2
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/EscalateVisibility.groovy
@@ -0,0 +1,10 @@
+class Foo {
+
+}
+
+class FooImpl extends Foo {
+ private void foo(){}
+ void bar() {
+ foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/EscalateVisibility_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/EscalateVisibility_after.groovy
new file mode 100644
index 000000000000..725e5c5a2b12
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/EscalateVisibility_after.groovy
@@ -0,0 +1,10 @@
+class Foo {
+
+ protected void foo(){}
+}
+
+class FooImpl extends Foo {
+ void bar() {
+ foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/ExtensionMethod.groovy b/plugins/groovy/testdata/refactoring/pullUp/ExtensionMethod.groovy
new file mode 100644
index 000000000000..4a59e1eef8c8
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/ExtensionMethod.groovy
@@ -0,0 +1,8 @@
+interface Base {
+}
+
+interface I2 extends Base {
+ default void foo() {
+ System.out.println("Hi there.");
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/ExtensionMethod_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/ExtensionMethod_after.groovy
new file mode 100644
index 000000000000..469ee86ef62a
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/ExtensionMethod_after.groovy
@@ -0,0 +1,8 @@
+interface Base {
+ default void foo() {
+ System.out.println("Hi there.");
+ }
+}
+
+interface I2 extends Base {
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/GenericsInAbstractMethod.groovy b/plugins/groovy/testdata/refactoring/pullUp/GenericsInAbstractMethod.groovy
new file mode 100644
index 000000000000..bd2f4991dff6
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/GenericsInAbstractMethod.groovy
@@ -0,0 +1,5 @@
+public abstract class Parent {}
+
+class Child extends Parent {
+ void method(T t){}
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/GenericsInAbstractMethod_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/GenericsInAbstractMethod_after.groovy
new file mode 100644
index 000000000000..353201fac27c
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/GenericsInAbstractMethod_after.groovy
@@ -0,0 +1,8 @@
+public abstract class Parent {
+ abstract void method(S t)
+}
+
+class Child extends Parent {
+ @Override
+ void method(T t){}
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/GenericsInImplements.groovy b/plugins/groovy/testdata/refactoring/pullUp/GenericsInImplements.groovy
new file mode 100644
index 000000000000..07e1f89a50c9
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/GenericsInImplements.groovy
@@ -0,0 +1,10 @@
+public class Parent {}
+
+interface I {
+ void method(IT t);
+}
+
+class Child extends Parent implements I{
+
+ public void method(T t){}
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/GenericsInImplements_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/GenericsInImplements_after.groovy
new file mode 100644
index 000000000000..3aca9f833a81
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/GenericsInImplements_after.groovy
@@ -0,0 +1,10 @@
+public class Parent implements I {}
+
+interface I {
+ void method(IT t);
+}
+
+class Child extends Parent {
+
+ public void method(T t){}
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/IfFieldInitializationWithNonMovedField.groovy b/plugins/groovy/testdata/refactoring/pullUp/IfFieldInitializationWithNonMovedField.groovy
new file mode 100644
index 000000000000..ba3609d7238c
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/IfFieldInitializationWithNonMovedField.groovy
@@ -0,0 +1,18 @@
+public class A {
+}
+
+class B extends A {
+ final String f;
+ final String foo;
+
+ B(String fi, String foo) {
+ this.foo = foo;
+ if (fi == this.foo) {
+ f = foo;
+ } else {
+ f = "";
+ }
+ }
+
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/IfFieldInitializationWithNonMovedField_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/IfFieldInitializationWithNonMovedField_after.groovy
new file mode 100644
index 000000000000..8d52600bc079
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/IfFieldInitializationWithNonMovedField_after.groovy
@@ -0,0 +1,18 @@
+public class A {
+ protected final String f
+}
+
+class B extends A {
+ final String foo;
+
+ B(String fi, String foo) {
+ this.foo = foo;
+ if (fi == this.foo) {
+ f = foo;
+ } else {
+ f = "";
+ }
+ }
+
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/IfFieldMovedInitialization.groovy b/plugins/groovy/testdata/refactoring/pullUp/IfFieldMovedInitialization.groovy
new file mode 100644
index 000000000000..f541f0ef1118
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/IfFieldMovedInitialization.groovy
@@ -0,0 +1,18 @@
+public class A {
+}
+
+class B extends A {
+ final String f;
+ final String foo;
+
+ B(String fi, String foo) {
+ this.foo = foo;
+ if (fi == foo) {
+ f = foo;
+ } else {
+ f = "";
+ }
+ }
+
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/IfFieldMovedInitialization_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/IfFieldMovedInitialization_after.groovy
new file mode 100644
index 000000000000..4000fdc4e154
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/IfFieldMovedInitialization_after.groovy
@@ -0,0 +1,22 @@
+public class A {
+ final String f;
+
+ public A(String fi, String foo) {
+ if (fi == foo) {
+ f = foo;
+ } else {
+ f = "";
+ }
+ }
+}
+
+class B extends A {
+ final String foo;
+
+ B(String fi, String foo) {
+ super(fi, foo);
+ this.foo = foo;
+ }
+
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/MergeInterfaces.groovy b/plugins/groovy/testdata/refactoring/pullUp/MergeInterfaces.groovy
new file mode 100644
index 000000000000..5376e86b6b42
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/MergeInterfaces.groovy
@@ -0,0 +1,3 @@
+class Base implements I {}
+class Test extends Base implements I {}
+interface I{}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/MergeInterfaces_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/MergeInterfaces_after.groovy
new file mode 100644
index 000000000000..ea7fffc75bf2
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/MergeInterfaces_after.groovy
@@ -0,0 +1,3 @@
+class Base implements I {}
+class Test extends Base {}
+interface I{}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitialization.groovy b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitialization.groovy
new file mode 100644
index 000000000000..f884f48399c2
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitialization.groovy
@@ -0,0 +1,17 @@
+public class A {
+}
+
+class B extends A {
+ final String f;
+ final String foo;
+
+ B(String fi, String foo) {
+ this.foo = foo;
+ f = "";
+ }
+
+ B(String foo) {
+ this.foo = foo;
+ f = "";
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitializationNoGood.groovy b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitializationNoGood.groovy
new file mode 100644
index 000000000000..25117fc692c8
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitializationNoGood.groovy
@@ -0,0 +1,21 @@
+public class A {
+}
+
+class B extends A {
+ final String f;
+ final String foo;
+
+ B(String fi, String foo) {
+ this.foo = foo;
+ if (fi == this.foo) {
+ f = foo;
+ } else {
+ f = "";
+ }
+ }
+
+ B(String f) {
+ this.f = f;
+ foo = "";
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitializationNoGood_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitializationNoGood_after.groovy
new file mode 100644
index 000000000000..b66ba0b55967
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitializationNoGood_after.groovy
@@ -0,0 +1,21 @@
+public class A {
+ final String f;
+}
+
+class B extends A {
+ final String foo;
+
+ B(String fi, String foo) {
+ this.foo = foo;
+ if (fi == this.foo) {
+ f = foo;
+ } else {
+ f = "";
+ }
+ }
+
+ B(String f) {
+ this.f = f;
+ foo = "";
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitialization_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitialization_after.groovy
new file mode 100644
index 000000000000..7c19de1ed075
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/MultipleConstructorsFieldInitialization_after.groovy
@@ -0,0 +1,21 @@
+public class A {
+ final String f;
+
+ public A() {
+ f = "";
+ }
+}
+
+class B extends A {
+ final String foo;
+
+ B(String fi, String foo) {
+ super();
+ this.foo = foo;
+ }
+
+ B(String foo) {
+ super();
+ this.foo = foo;
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PreserveOverride.groovy b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverride.groovy
new file mode 100644
index 000000000000..84f2f18bad76
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverride.groovy
@@ -0,0 +1,12 @@
+abstract class Bazz {
+ public abstract void foo();
+}
+
+abstract class Foo extends Bazz {}
+
+class Bar extends Foo {
+ @Override
+ public void foo() {
+ }
+}
+
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PreserveOverrideInPulledMethod.groovy b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverrideInPulledMethod.groovy
new file mode 100644
index 000000000000..c814a6825a69
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverrideInPulledMethod.groovy
@@ -0,0 +1,12 @@
+public class Test {
+ abstract class Base extends IntImpl {
+ @Override
+ public abstract String foo();
+ }
+
+ class IntImpl extends Int {}
+
+ class Int {
+ public abstract String foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PreserveOverrideInPulledMethod_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverrideInPulledMethod_after.groovy
new file mode 100644
index 000000000000..3c8eea40c9bb
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverrideInPulledMethod_after.groovy
@@ -0,0 +1,13 @@
+public class Test {
+ abstract class Base extends IntImpl {
+ }
+
+ abstract class IntImpl extends Int {
+ @Override
+ public abstract String foo();
+ }
+
+ class Int {
+ public abstract String foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PreserveOverride_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverride_after.groovy
new file mode 100644
index 000000000000..ea553c109132
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PreserveOverride_after.groovy
@@ -0,0 +1,13 @@
+abstract class Bazz {
+ public abstract void foo();
+}
+
+abstract class Foo extends Bazz {
+ @Override
+ public void foo() {
+ }
+}
+
+class Bar extends Foo {
+}
+
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PullUpAndMakeAbstract.groovy b/plugins/groovy/testdata/refactoring/pullUp/PullUpAndMakeAbstract.groovy
new file mode 100644
index 000000000000..111cfbe2f1c7
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PullUpAndMakeAbstract.groovy
@@ -0,0 +1,11 @@
+public class A2 {
+}
+
+class B2 extends A2 {
+ public void a() {
+ b();
+ }
+
+ private void b() {
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PullUpAndMakeAbstract_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/PullUpAndMakeAbstract_after.groovy
new file mode 100644
index 000000000000..312788c07d78
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PullUpAndMakeAbstract_after.groovy
@@ -0,0 +1,14 @@
+public abstract class A2 {
+ public void a() {
+ b();
+ }
+
+ protected abstract void b()
+}
+
+class B2 extends A2 {
+
+ @Override
+ protected void b() {
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PullUpInheritedStaticClasses.groovy b/plugins/groovy/testdata/refactoring/pullUp/PullUpInheritedStaticClasses.groovy
new file mode 100644
index 000000000000..e0faaba55617
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PullUpInheritedStaticClasses.groovy
@@ -0,0 +1,8 @@
+public class A extends AA {
+
+ static class C extends D {}
+ static class D extends B {}
+ static class B {}
+}
+
+class AA {}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PullUpInheritedStaticClasses_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/PullUpInheritedStaticClasses_after.groovy
new file mode 100644
index 000000000000..cc948e7632ea
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PullUpInheritedStaticClasses_after.groovy
@@ -0,0 +1,10 @@
+public class A extends AA {
+
+ static class B {}
+}
+
+class AA {
+ static class C extends D {}
+
+ static class D extends A.B {}
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PullUpPrivateInnerClassWithPrivateConstructor.groovy b/plugins/groovy/testdata/refactoring/pullUp/PullUpPrivateInnerClassWithPrivateConstructor.groovy
new file mode 100644
index 000000000000..a5fbc567cd6b
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PullUpPrivateInnerClassWithPrivateConstructor.groovy
@@ -0,0 +1,15 @@
+public class B extends A {
+ private void f(){
+ new C();
+ }
+
+ private static class C{
+ private C(){
+
+ }
+ }
+}
+
+//A.java
+class A {
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/PullUpPrivateInnerClassWithPrivateConstructor_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/PullUpPrivateInnerClassWithPrivateConstructor_after.groovy
new file mode 100644
index 000000000000..a1cc2b848007
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/PullUpPrivateInnerClassWithPrivateConstructor_after.groovy
@@ -0,0 +1,15 @@
+public class B extends A {
+ private void f(){
+ new C();
+ }
+
+}
+
+//A.java
+class A {
+ protected static class C{
+ protected C(){
+
+ }
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/QualifiedReference.groovy b/plugins/groovy/testdata/refactoring/pullUp/QualifiedReference.groovy
new file mode 100644
index 000000000000..cf557ddd7033
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/QualifiedReference.groovy
@@ -0,0 +1,13 @@
+class X {}
+
+class Y extends X {
+ private static int x = 0;
+
+ public static int getX() {
+ return x;
+ }
+
+ public static void setX(int x) {
+ Y.x = x;
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/QualifiedReference_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/QualifiedReference_after.groovy
new file mode 100644
index 000000000000..2ee952609dcd
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/QualifiedReference_after.groovy
@@ -0,0 +1,16 @@
+class X {
+ private static int x = 0
+
+ public static int getX() {
+ return x;
+ }
+
+ public static void setX(int x) {
+ X.x = x;
+ }
+}
+
+class Y extends X {
+
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/QualifiedSuper.groovy b/plugins/groovy/testdata/refactoring/pullUp/QualifiedSuper.groovy
new file mode 100644
index 000000000000..6c586617fb01
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/QualifiedSuper.groovy
@@ -0,0 +1,12 @@
+class QualifiedSuper extends Base {
+ class Inner {
+ void goo() {
+ QualifiedSuper.super.toString();
+ }
+ }
+}
+
+class Base {
+
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/QualifiedSuper_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/QualifiedSuper_after.groovy
new file mode 100644
index 000000000000..08e72509da9e
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/QualifiedSuper_after.groovy
@@ -0,0 +1,12 @@
+class QualifiedSuper extends Base {
+}
+
+class Base {
+
+
+ class Inner {
+ void goo() {
+ Base.this.toString();
+ }
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/QualifiedThis.groovy b/plugins/groovy/testdata/refactoring/pullUp/QualifiedThis.groovy
new file mode 100644
index 000000000000..ae042886bafb
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/QualifiedThis.groovy
@@ -0,0 +1,15 @@
+class Base {
+ void foo() {
+ }
+}
+
+public class QualifiedThis extends Base {
+ void foo() {
+ }
+
+ class Inner {
+ void bar() {
+ QualifiedThis.this.foo();
+ }
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/QualifiedThis_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/QualifiedThis_after.groovy
new file mode 100644
index 000000000000..c097c66b5f82
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/QualifiedThis_after.groovy
@@ -0,0 +1,16 @@
+class Base {
+ void foo() {
+ }
+
+ class Inner {
+ void bar() {
+ Base.this.foo();
+ }
+ }
+}
+
+public class QualifiedThis extends Base {
+ void foo() {
+ }
+
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/RemoveOverride.groovy b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverride.groovy
new file mode 100644
index 000000000000..8c3d05feb402
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverride.groovy
@@ -0,0 +1,16 @@
+public class Test {
+ class Impl extends Base {
+ @Override
+ public String get() {
+ return "239";
+ }
+ }
+
+ abstract class Base implements Int {
+ public abstract String get();
+
+ }
+
+ interface Int {
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/RemoveOverrideFromPulledMethod.groovy b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverrideFromPulledMethod.groovy
new file mode 100644
index 000000000000..2c14369982ae
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverrideFromPulledMethod.groovy
@@ -0,0 +1,9 @@
+public class Test {
+ abstract class Base extends Int {
+ @Override
+ public abstract String foo();
+ }
+
+ class Int {
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/RemoveOverrideFromPulledMethod_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverrideFromPulledMethod_after.groovy
new file mode 100644
index 000000000000..15c02bbec11c
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverrideFromPulledMethod_after.groovy
@@ -0,0 +1,8 @@
+public class Test {
+ abstract class Base extends Int {
+ }
+
+ abstract class Int {
+ public abstract String foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/RemoveOverride_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverride_after.groovy
new file mode 100644
index 000000000000..94aef6d3d359
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/RemoveOverride_after.groovy
@@ -0,0 +1,15 @@
+public class Test {
+ class Impl extends Base {
+ public String get() {
+ return "239";
+ }
+ }
+
+ abstract class Base implements Int {
+
+ }
+
+ interface Int {
+ String get();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/ReplaceDuplicatesInInheritors.groovy b/plugins/groovy/testdata/refactoring/pullUp/ReplaceDuplicatesInInheritors.groovy
new file mode 100644
index 000000000000..0f8c6a110fc8
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/ReplaceDuplicatesInInheritors.groovy
@@ -0,0 +1,18 @@
+class A {}
+class AImpl1 extends A{
+ void foo() {
+ System.out.println("hello");
+ System.out.println("hello");
+ System.out.println("hello");
+ System.out.println("hello");
+ }
+}
+
+class AImpl2 extends A {
+ void bar() {
+ System.out.println("hello");
+ System.out.println("hello");
+ System.out.println("hello");
+ System.out.println("hello");
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/ReplaceDuplicatesInInheritors_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/ReplaceDuplicatesInInheritors_after.groovy
new file mode 100644
index 000000000000..47b655ce3c89
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/ReplaceDuplicatesInInheritors_after.groovy
@@ -0,0 +1,16 @@
+class A {
+ void foo() {
+ System.out.println("hello");
+ System.out.println("hello");
+ System.out.println("hello");
+ System.out.println("hello");
+ }
+}
+class AImpl1 extends A{
+}
+
+class AImpl2 extends A {
+ void bar() {
+ foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TryCatchFieldInitializer.groovy b/plugins/groovy/testdata/refactoring/pullUp/TryCatchFieldInitializer.groovy
new file mode 100644
index 000000000000..64675e489afa
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TryCatchFieldInitializer.groovy
@@ -0,0 +1,19 @@
+public class Sup {
+
+}
+
+class ExtractSuperClass extends Sup {
+
+ private final String field;
+
+ public ExtractSuperClass() {
+
+
+ try {
+ field = (String)"text";
+ }
+ catch (RuntimeException e) {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TryCatchFieldInitializer_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/TryCatchFieldInitializer_after.groovy
new file mode 100644
index 000000000000..600247f2d6a1
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TryCatchFieldInitializer_after.groovy
@@ -0,0 +1,22 @@
+public class Sup {
+
+ protected final String field
+
+ public Sup() {
+ try {
+ field = (String)"text";
+ }
+ catch (RuntimeException e) {
+ throw new RuntimeException();
+ }
+ }
+}
+
+class ExtractSuperClass extends Sup {
+
+ public ExtractSuperClass() {
+ super();
+
+
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeArgument.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeArgument.groovy
new file mode 100644
index 000000000000..21140c87bb61
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeArgument.groovy
@@ -0,0 +1,5 @@
+public class Parent {}
+
+class Child extends Parent {
+ String f;
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeArgument_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeArgument_after.groovy
new file mode 100644
index 000000000000..3eb901010ca6
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeArgument_after.groovy
@@ -0,0 +1,6 @@
+public class Parent {
+ String f
+}
+
+class Child extends Parent {
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeParamErasure.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeParamErasure.groovy
new file mode 100644
index 000000000000..0dbc24fce32d
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeParamErasure.groovy
@@ -0,0 +1,5 @@
+public class Parent {}
+
+class Child extends Parent {
+ T f;
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeParamErasure_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeParamErasure_after.groovy
new file mode 100644
index 000000000000..ab94d54beee3
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeParamErasure_after.groovy
@@ -0,0 +1,6 @@
+public class Parent {
+ Object f
+}
+
+class Child extends Parent {
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeParamSubst.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeParamSubst.groovy
new file mode 100644
index 000000000000..f2ad0c7e8dae
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeParamSubst.groovy
@@ -0,0 +1,5 @@
+public class Parent {}
+
+class Child extends Parent {
+ T f;
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeParamSubst_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeParamSubst_after.groovy
new file mode 100644
index 000000000000..703445143419
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeParamSubst_after.groovy
@@ -0,0 +1,6 @@
+public class Parent {
+ S f
+}
+
+class Child extends Parent {
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeParamsConflictingNames.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeParamsConflictingNames.groovy
new file mode 100644
index 000000000000..b0d736631ae4
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeParamsConflictingNames.groovy
@@ -0,0 +1,7 @@
+interface Bar { }
+
+interface Base { }
+
+class Foo implements Base {
+ void foo(Bar bar) { }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/TypeParamsConflictingNames_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/TypeParamsConflictingNames_after.groovy
new file mode 100644
index 000000000000..8c29df338869
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/TypeParamsConflictingNames_after.groovy
@@ -0,0 +1,10 @@
+interface Bar { }
+
+interface Base {
+ void foo(Bar bar);
+}
+
+class Foo implements Base {
+ @Override
+ public void foo(Bar bar) { }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/UpdateStaticRefs.groovy b/plugins/groovy/testdata/refactoring/pullUp/UpdateStaticRefs.groovy
new file mode 100644
index 000000000000..7ad6fb62eaf6
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/UpdateStaticRefs.groovy
@@ -0,0 +1,10 @@
+class Foo {}
+class FooImpl extends Foo {
+ public static void foo(){}
+
+}
+class U {
+ public static void main(String[] args) {
+ FooImpl.foo();
+ }
+}
diff --git a/plugins/groovy/testdata/refactoring/pullUp/UpdateStaticRefs_after.groovy b/plugins/groovy/testdata/refactoring/pullUp/UpdateStaticRefs_after.groovy
new file mode 100644
index 000000000000..dc797f702d0d
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/pullUp/UpdateStaticRefs_after.groovy
@@ -0,0 +1,11 @@
+class Foo {
+ public static void foo(){}
+}
+class FooImpl extends Foo {
+
+}
+class U {
+ public static void main(String[] args) {
+ Foo.foo();
+ }
+}