push down: static import preserve (IDEADEV-33557)

This commit is contained in:
anna
2009-10-19 21:31:57 +04:00
parent a9a8372082
commit 113efc1bd8
21 changed files with 199 additions and 14 deletions
@@ -282,11 +282,12 @@ public class JavaChangeUtilSupport implements TreeGenerator, TreeCopyHandler {
else {
final PsiMember refMember = element.getCopyableUserData(REFERENCED_MEMBER_KEY);
if (refMember != null) {
LOG.assertTrue(ref instanceof PsiReferenceExpression);
element.putCopyableUserData(REFERENCED_MEMBER_KEY, null);
PsiElement refElement1 = ref.resolve();
if (refMember != refElement1 && !refMember.getManager().areElementsEquivalent(refMember, refElement1)) {
try {
ref = (PsiJavaCodeReferenceElement) ref.bindToElement(refMember);
ref = (PsiJavaCodeReferenceElement) ((PsiReferenceExpression)ref).bindToElementViaStaticImport(refMember.getContainingClass());
}
catch (IncorrectOperationException e) {
// TODO[yole] ignore?
@@ -84,6 +84,10 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements
if (getQualifierExpression() != null) {
throw new IncorrectOperationException("Reference is qualified: "+getText());
}
if (!isPhysical()) {
// don't qualify reference: the isReferenceTo() check fails anyway, whether we have a static import for this member or not
return this;
}
String staticName = getReferenceName();
PsiFile containingFile = getContainingFile();
PsiImportList importList = null;
@@ -71,7 +71,7 @@ public class PushDownConflicts {
}
}
public void checkTargetClassConflicts(PsiClass targetClass) {
public void checkTargetClassConflicts(PsiClass targetClass, boolean checkStatic) {
for (final PsiMember movedMember : myMovedMembers) {
checkMemberPlacementInTargetClassConflict(targetClass, movedMember);
}
@@ -84,13 +84,24 @@ public class PushDownConflicts {
final PsiExpression qualifier = referenceExpression.getQualifierExpression();
if (qualifier != null) {
final PsiType qualifierType = qualifier.getType();
PsiClass aClass = null;
if (qualifierType instanceof PsiClassType) {
final PsiClass aClass = ((PsiClassType)qualifierType).resolve();
if (!InheritanceUtil.isInheritorOrSelf(aClass, targetClass, true)) {
myConflicts.putValue(aClass, RefactoringBundle.message("pushed.members.will.not.be.visible.from.certain.call.sites"));
break Members;
aClass = ((PsiClassType)qualifierType).resolve();
}
else {
if (!checkStatic) continue;
if (qualifier instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve();
if (resolved instanceof PsiClass) {
aClass = (PsiClass)resolved;
}
}
}
if (!InheritanceUtil.isInheritorOrSelf(aClass, targetClass, true)) {
myConflicts.putValue(aClass, RefactoringBundle.message("pushed.members.will.not.be.visible.from.certain.call.sites"));
break Members;
}
}
}
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
@@ -41,6 +42,8 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class PushDownProcessor extends BaseRefactoringProcessor {
@@ -93,7 +96,7 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
for (UsageInfo usage : usagesIn) {
final PsiElement element = usage.getElement();
if (element instanceof PsiClass) {
pushDownConflicts.checkTargetClassConflicts((PsiClass)element);
pushDownConflicts.checkTargetClassConflicts((PsiClass)element, usagesIn.length > 1);
}
}
@@ -318,6 +321,22 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
}
for (MemberInfo memberInfo : myMemberInfos) {
final PsiMember member = memberInfo.getMember();
final List<PsiReference> refsToRebind = new ArrayList<PsiReference>();
final PsiModifierList list = member.getModifierList();
LOG.assertTrue(list != null);
if (list.hasModifierProperty(PsiModifier.STATIC)) {
for (final PsiReference reference : ReferencesSearch.search(member)) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression) {
final PsiExpression qualifierExpression = ((PsiReferenceExpression)element).getQualifierExpression();
if (qualifierExpression instanceof PsiReferenceExpression && !(((PsiReferenceExpression)qualifierExpression).resolve() instanceof PsiClass)) {
continue;
}
}
refsToRebind.add(reference);
}
}
PsiMember newMember = null;
if (member instanceof PsiField) {
((PsiField)member).normalizeDeclaration();
@@ -357,6 +376,9 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
if (newMember != null) {
decodeRefs(newMember, targetClass);
for (PsiReference psiReference : refsToRebind) {
JavaCodeStyleManagerImpl.getInstance(myProject).shortenClassReferences(psiReference.bindToElement(newMember));
}
final JavaRefactoringListenerManager listenerManager = JavaRefactoringListenerManager.getInstance(newMember.getProject());
((JavaRefactoringListenerManagerImpl)listenerManager).fireMemberMoved(myClass, newMember);
}
@@ -140,7 +140,7 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) {
refExpr.setQualifierExpression(null);
}
else if (!RefactoringUtil.hasStaticImportOn(refExpr, member.getContainingClass(), member)){
else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)){
PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory();
refExpr.setQualifierExpression(factory.createReferenceExpression(aClass));
}
@@ -224,13 +224,13 @@ public class RefactoringUtil {
return false;
}
public static boolean hasStaticImportOn(final PsiReferenceExpression expr, final PsiClass aClass, final PsiMember member) {
public static boolean hasStaticImportOn(final PsiElement expr, final PsiMember member) {
if (expr.getContainingFile() instanceof PsiJavaFile) {
final PsiImportList importList = ((PsiJavaFile)expr.getContainingFile()).getImportList();
if (importList != null) {
final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements();
for(PsiImportStaticStatement stmt: importStaticStatements) {
if (!stmt.isOnDemand() && stmt.resolveTargetClass() == aClass && Comparing.strEqual(stmt.getReferenceName(), member.getName())) {
if (!stmt.isOnDemand() && stmt.resolveTargetClass() == member.getContainingClass() && Comparing.strEqual(stmt.getReferenceName(), member.getName())) {
return true;
}
}
@@ -1,11 +1,11 @@
class Test {
public void contextChild() {
Test.StInner inner1 = new Test.StInner();
StInner inner1 = new StInner();
Test.InstInner inner2 = this.new InstInner();
}
void foo() {
Test.StInner inner1 = new Test.StInner();
StInner inner1 = new StInner();
Test.InstInner inner2 = this.new InstInner();
}
@@ -1,11 +1,11 @@
package p1;
import p2.Statics;
import static p2.Statics.PUB_CONST;
public class Usage {
public void test() {
Object i = new Object() {
public int myInt = Statics.PUB_CONST;
public int myInt = PUB_CONST;
};
}
}
@@ -0,0 +1,3 @@
package a;
public class A {
}
@@ -0,0 +1,7 @@
package b;
import a.*;
public class B extends A {
public static void foo(){
}
}
@@ -0,0 +1,7 @@
package u;
import static b.B.foo;
public class U {
public static void main(String[] args) {
foo();
}
}
@@ -0,0 +1,5 @@
package a;
public class A {
public static void foo(){
}
}
@@ -0,0 +1,4 @@
package b;
import a.*;
public class B extends A {}
@@ -0,0 +1,7 @@
package u;
import static a.A.foo;
public class U {
public static void main(String[] args) {
foo();
}
}
@@ -0,0 +1,4 @@
package a;
import static u.U.C;
public class A {
}
@@ -0,0 +1,9 @@
package b;
import a.*;
import static u.U.C;
public class B extends A {
public static void foo(){
System.out.println(C);
}
}
@@ -0,0 +1,4 @@
package u;
public class U {
public static final String C = "CONSTANT";
}
@@ -0,0 +1,7 @@
package a;
import static u.U.C;
public class A {
public static void foo(){
System.out.println(C);
}
}
@@ -0,0 +1,4 @@
package b;
import a.*;
public class B extends A {}
@@ -0,0 +1,4 @@
package u;
public class U {
public static final String C = "CONSTANT";
}
@@ -0,0 +1,82 @@
/*
* User: anna
* Date: 20-Aug-2008
*/
package com.intellij.refactoring;
import com.intellij.JavaTestUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.memberPushDown.PushDownProcessor;
import com.intellij.refactoring.util.DocCommentPolicy;
import com.intellij.refactoring.util.classMembers.MemberInfo;
//push first method from class a.A to class b.B
public class PushDownImportsTest extends MultiFileTestCase {
protected String getTestRoot() {
return "/refactoring/pushDown/";
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath();
}
protected Sdk getTestProjectJdk() {
return JavaSdkImpl.getMockJdk15("java 1.5");
}
private void doTest() throws Exception {
doTest(false);
}
private void doTest(final boolean fail) throws Exception {
try {
doTest(new PerformAction() {
public void performAction(final VirtualFile rootDir, final VirtualFile rootAfter) throws Exception {
final PsiClass srcClass = myJavaFacade.findClass("a.A");
assertTrue("Source class not found", srcClass != null);
final PsiClass targetClass = myJavaFacade.findClass("b.B");
assertTrue("Target class not found", targetClass != null);
final PsiMethod[] methods = srcClass.getMethods();
assertTrue("No methods found", methods.length > 0);
final MemberInfo[] membersToMove = new MemberInfo[1];
final MemberInfo memberInfo = new MemberInfo(methods[0]);
memberInfo.setChecked(true);
membersToMove[0] = memberInfo;
new PushDownProcessor(getProject(), membersToMove, srcClass, new DocCommentPolicy(DocCommentPolicy.ASIS)).run();
//LocalFileSystem.getInstance().refresh(false);
//FileDocumentManager.getInstance().saveAllDocuments();
}
});
}
catch (RuntimeException e) {
if (fail) {
return;
}
else {
throw e;
}
}
if (fail) {
fail("Conflict was not detected");
}
}
public void testStaticImportsInsidePushedMethod() throws Exception {
doTest();
}
public void testStaticImportOfPushedMethod() throws Exception {
doTest();
}
}