add single static import: process nested references (IDEA-94951)

This commit is contained in:
anna
2013-04-24 16:27:01 +02:00
parent 7b6da75722
commit 3d9008c296
7 changed files with 128 additions and 46 deletions
@@ -61,8 +61,7 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
if (parent instanceof PsiMethodReferenceExpression) return null;
if (parent instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)parent).getQualifier() != null) {
PsiJavaCodeReferenceElement refExpr = (PsiJavaCodeReferenceElement)parent;
PsiReferenceParameterList parameterList = refExpr.getParameterList();
if (parameterList != null && parameterList.getFirstChild() != null) return null;
if (checkParameterizedReference(refExpr)) return null;
PsiElement resolved = refExpr.resolve();
if (resolved instanceof PsiMember && ((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) {
PsiClass aClass = getResolvedClass(element, (PsiMember)resolved);
@@ -99,6 +98,11 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
return null;
}
private static boolean checkParameterizedReference(PsiJavaCodeReferenceElement refExpr) {
PsiReferenceParameterList parameterList = refExpr instanceof PsiReferenceExpression ? refExpr.getParameterList() : null;
return parameterList != null && parameterList.getFirstChild() != null;
}
@Nullable
private static PsiClass getResolvedClass(PsiElement element, PsiMember resolved) {
PsiClass aClass = resolved.getContainingClass();
@@ -158,58 +162,61 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
@Override
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
if (reference.getParameterList() != null &&
reference.getParameterList().getFirstChild() != null) return;
try {
if (checkParameterizedReference(reference)) return;
if (referenceName.equals(reference.getReferenceName()) && !(reference instanceof PsiMethodReferenceExpression)) {
final PsiElement qualifierExpression = reference.getQualifier();
PsiElement referent = reference.getUserData(TEMP_REFERENT_USER_DATA);
if (!reference.isQualified()) {
if (referent instanceof PsiMember && referent != reference.resolve()) {
PsiElementFactory factory = JavaPsiFacade.getInstance(reference.getProject()).getElementFactory();
try {
final PsiClass containingClass = ((PsiMember)referent).getContainingClass();
if (containingClass != null) {
PsiReferenceExpression copy = (PsiReferenceExpression)factory.createExpressionFromText("A." + reference.getReferenceName(), null);
reference = (PsiReferenceExpression)reference.replace(copy);
((PsiReferenceExpression)reference.getQualifier()).bindToElement(containingClass);
if (referenceName.equals(reference.getReferenceName()) && !(reference instanceof PsiMethodReferenceExpression)) {
final PsiElement qualifierExpression = reference.getQualifier();
PsiElement referent = reference.getUserData(TEMP_REFERENT_USER_DATA);
if (!reference.isQualified()) {
if (referent instanceof PsiMember && referent != reference.resolve()) {
PsiElementFactory factory = JavaPsiFacade.getInstance(reference.getProject()).getElementFactory();
try {
final PsiClass containingClass = ((PsiMember)referent).getContainingClass();
if (containingClass != null) {
PsiReferenceExpression copy = (PsiReferenceExpression)factory.createExpressionFromText("A." + reference.getReferenceName(), null);
reference = (PsiReferenceExpression)reference.replace(copy);
((PsiReferenceExpression)reference.getQualifier()).bindToElement(containingClass);
}
}
catch (IncorrectOperationException e) {
LOG.error (e);
}
}
catch (IncorrectOperationException e) {
LOG.error (e);
reference.putUserData(TEMP_REFERENT_USER_DATA, null);
} else {
if (qualifierExpression instanceof PsiJavaCodeReferenceElement) {
PsiElement aClass = ((PsiJavaCodeReferenceElement)qualifierExpression).resolve();
if (aClass instanceof PsiVariable) {
aClass = PsiUtil.resolveClassInClassTypeOnly(((PsiVariable)aClass).getType());
}
if (aClass instanceof PsiClass && InheritanceUtil.isInheritorOrSelf((PsiClass)aClass, resolvedClass, true)) {
boolean foundMemberByName = false;
if (referent instanceof PsiMember) {
final String memberName = ((PsiMember)referent).getName();
final PsiClass containingClass = PsiTreeUtil.getParentOfType(reference, PsiClass.class);
if (containingClass != null) {
foundMemberByName |= containingClass.findFieldByName(memberName, true) != null;
foundMemberByName |= containingClass.findMethodsByName(memberName, true).length > 0;
}
}
if (!foundMemberByName) {
try {
qualifierExpression.delete();
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
}
}
reference.putUserData(TEMP_REFERENT_USER_DATA, null);
} else {
if (qualifierExpression instanceof PsiJavaCodeReferenceElement) {
PsiElement aClass = ((PsiJavaCodeReferenceElement)qualifierExpression).resolve();
if (aClass instanceof PsiVariable) {
aClass = PsiUtil.resolveClassInClassTypeOnly(((PsiVariable)aClass).getType());
}
if (aClass instanceof PsiClass && InheritanceUtil.isInheritorOrSelf((PsiClass)aClass, resolvedClass, true)) {
boolean foundMemberByName = false;
if (referent instanceof PsiMember) {
final String memberName = ((PsiMember)referent).getName();
final PsiClass containingClass = PsiTreeUtil.getParentOfType(reference, PsiClass.class);
if (containingClass != null) {
foundMemberByName |= containingClass.findFieldByName(memberName, true) != null;
foundMemberByName |= containingClass.findMethodsByName(memberName, true).length > 0;
}
}
if (!foundMemberByName) {
try {
qualifierExpression.delete();
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
}
}
reference.putUserData(TEMP_REFERENT_USER_DATA, null);
}
super.visitReferenceElement(reference);
finally {
super.visitReferenceElement(reference);
}
}
});
}
@@ -0,0 +1,6 @@
import foo.*;
class Class2 {
public static void main(String[] args) {
Class1.<String>f<caret>oo();
}
}
@@ -0,0 +1,6 @@
import foo.*;
class Class2 {
public static void main(String[] args) {
new Class1.Inn<caret>er2<Class1.Inner1>();
}
}
@@ -0,0 +1,6 @@
import foo.*;
class Class2 {
public static void main(String[] args) {
new Class1.Inner2<Class1.In<caret>ner1>();
}
}
@@ -0,0 +1,9 @@
import foo.*;
import static foo.Class1.Inner1;
class Class2 {
public static void main(String[] args) {
new Class1.Inner2<Inner1>();
}
}
@@ -0,0 +1,9 @@
import foo.*;
import static foo.Class1.Inner2;
class Class2 {
public static void main(String[] args) {
new Inner2<Class1.Inner1>();
}
}
@@ -30,6 +30,45 @@ public class AddSingleStaticImportActionTest extends JavaCodeInsightFixtureTestC
myFixture.checkResultByFile(getTestName(false) + "_after.java");
}
public void testInsideParameterizedReference() {
myFixture.addClass("package foo; " +
"public class Class1 {" +
" public static class Inner1 {}\n" +
" public static class Inner2<T> {}" +
"}");
myFixture.configureByFile(getTestName(false) + ".java");
final IntentionAction intentionAction = myFixture.findSingleIntention("Add static import for 'foo.Class1.Inner2'");
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(getTestName(false) + "_after.java");
}
public void testInsideParameterizedReferenceInsideParameterizedReference() {
myFixture.addClass("package foo; " +
"public class Class1 {" +
" public static class Inner1 {}\n" +
" public static class Inner2<T> {}" +
"}");
myFixture.configureByFile(getTestName(false) + ".java");
final IntentionAction intentionAction = myFixture.findSingleIntention("Add static import for 'foo.Class1.Inner1'");
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(getTestName(false) + "_after.java");
}
public void testDisabledInsideParameterizedReference() {
myFixture.addClass("package foo; " +
"public class Class1 {" +
" public static <T> T foo(){return null;}\n" +
"}");
myFixture.configureByFile(getTestName(false) + ".java");
final IntentionAction intentionAction = myFixture.getAvailableIntention("Add static import for 'foo.Class1.foo'");
assertNull(intentionAction);
}
@Override
protected String getTestDataPath() {