add single static import: allow second single static import if it doesn't produce ambiguity or hiding of on-demand import (IDEA-155031)

This commit is contained in:
Anna Kozlova
2016-06-07 10:57:34 +03:00
parent c83341f731
commit 9132043620
9 changed files with 114 additions and 11 deletions
@@ -2752,11 +2752,9 @@ public class HighlightUtil extends HighlightUtilBase {
highlightInfo = HighlightControlFlowUtil.checkVariableMustBeFinal((PsiVariable)resolved, ref, languageLevel);
}
else if (resolved instanceof PsiClass) {
final PsiFile fileWithImportedClass = resolved.getContainingFile();
if (((PsiClass)resolved).getContainingClass() == null &&
fileWithImportedClass instanceof PsiClassOwner &&
PsiTreeUtil.getParentOfType(ref, PsiImportStatementBase.class) != null &&
StringUtil.isEmptyOrSpaces(((PsiClassOwner)fileWithImportedClass).getPackageName())) {
PsiUtil.isFromDefaultPackage((PsiClass)resolved)) {
String description = JavaErrorMessages.message("cannot.resolve.symbol", refName.getText());
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(refName).descriptionAndTooltip(description).create();
}
@@ -72,6 +72,10 @@ public class AddOnDemandStaticImportAction extends BaseElementAtCaretIntentionAc
return null;
}
PsiClass psiClass = (PsiClass)resolved;
if (PsiUtil.isFromDefaultPackage(psiClass) ||
psiClass.hasModifierProperty(PsiModifier.PRIVATE) ||
psiClass.getQualifiedName() == null) return null;
final PsiElement ggParent = gParent.getParent();
if (ggParent instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression call = (PsiMethodCallExpression)ggParent.copy();
@@ -90,7 +94,6 @@ public class AddOnDemandStaticImportAction extends BaseElementAtCaretIntentionAc
if (target != null && PsiTreeUtil.getParentOfType(target, PsiClass.class) != psiClass) return null;
}
if (Comparing.strEqual(psiClass.getName(), psiClass.getQualifiedName()) || psiClass.hasModifierProperty(PsiModifier.PRIVATE)) return null;
PsiFile file = refExpr.getContainingFile();
if (!(file instanceof PsiJavaFile)) return null;
PsiImportList importList = ((PsiJavaFile)file).getImportList();
@@ -30,12 +30,16 @@ import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public class AddSingleMemberStaticImportAction extends BaseElementAtCaretIntentionAction {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.AddSingleMemberStaticImportAction");
private static final Key<PsiElement> TEMP_REFERENT_USER_DATA = new Key<PsiElement>("TEMP_REFERENT_USER_DATA");
@@ -77,15 +81,33 @@ public class AddSingleMemberStaticImportAction extends BaseElementAtCaretIntenti
final PsiElement resolved = result.getElement();
if (resolved instanceof PsiMember && ((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) {
PsiClass aClass = getResolvedClass(element, (PsiMember)resolved);
if (aClass != null && !PsiTreeUtil.isAncestor(aClass, element, true) && !aClass.hasModifierProperty(PsiModifier.PRIVATE)) {
String qName = aClass != null ? aClass.getQualifiedName() : null;
if (aClass != null &&
qName != null &&
!PsiTreeUtil.isAncestor(aClass, element, true) &&
!aClass.hasModifierProperty(PsiModifier.PRIVATE) &&
!PsiUtil.isFromDefaultPackage(aClass)) {
final PsiElement gParent = refExpr.getParent();
if (gParent instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression call = (PsiMethodCallExpression)gParent.copy();
final PsiElement qualifier = call.getMethodExpression().getQualifier();
if (qualifier == null) return null;
qualifier.delete();
final PsiMethod method = call.resolveMethod();
if (method != null && method.getContainingClass() != aClass) return null;
final JavaResolveResult resolveResult = call.resolveMethodGenerics();
final PsiElement method = resolveResult.getElement();
if (method instanceof PsiMethod) {
if (((PsiMethod)method).getContainingClass() != aClass) {
final PsiElement currentFileResolveScope = resolveResult.getCurrentFileResolveScope();
if (currentFileResolveScope instanceof PsiImportStaticStatement) {
//don't hide another on-demand import and don't create ambiguity
if (((PsiImportStaticStatement)currentFileResolveScope).isOnDemand() ||
MethodSignatureUtil.areSignaturesEqual((PsiMethod)method, (PsiMethod)resolved)) {
return null;
}
}
else return null;
}
}
}
else {
final PsiJavaCodeReferenceElement copy = (PsiJavaCodeReferenceElement)refExpr.copy();
@@ -95,10 +117,7 @@ public class AddSingleMemberStaticImportAction extends BaseElementAtCaretIntenti
final PsiElement target = copy.resolve();
if (target != null && PsiTreeUtil.getParentOfType(target, PsiClass.class) != aClass) return null;
}
String qName = aClass.getQualifiedName();
if (qName != null && !Comparing.strEqual(qName, aClass.getName())) {
return new ImportAvailability(qName + "." +refExpr.getReferenceName(), (PsiMember) resolved);
}
return new ImportAvailability(qName + "." +refExpr.getReferenceName(), (PsiMember) resolved);
}
}
}
@@ -1235,6 +1235,11 @@ public final class PsiUtil extends PsiUtilCore {
return className + "." + member.getName();
}
public static boolean isFromDefaultPackage(PsiClass aClass) {
final PsiFile containingFile = aClass.getContainingFile();
return containingFile instanceof PsiClassOwner && StringUtil.isEmpty(((PsiClassOwner)containingFile).getPackageName());
}
static boolean checkSameExpression(PsiElement templateExpr, final PsiExpression expression) {
return templateExpr.equals(skipParenthesizedExprDown(expression));
}
@@ -0,0 +1,13 @@
// "Add static import for 'test.Bar.f'" "true"
package test;
import static test.Bar.*;
class Bar {
public static final void f() {}
}
public class Foo {
{
f();
}
}
@@ -0,0 +1,18 @@
// "Add static import for 'test.Bar.f'" "true"
package test;
import static test.Bar.f;
import static test.Bar1.f;
class Bar {
public static final void f() {}
}
class Bar1 {
public static final void f(int i) {}
}
public class Foo {
{
f();
}
}
@@ -0,0 +1,13 @@
// "Add static import for 'test.Bar.f'" "true"
package test;
import static test.Bar.*;
class Bar {
public static final void f() {}
}
public class Foo {
{
Bar.<caret>f();
}
}
@@ -0,0 +1,17 @@
// "Add static import for 'test.Bar.f'" "false"
package test;
import static test.Bar1.f;
class Bar {
public static final void f() {}
}
class Bar1 {
public static final void f() {}
}
public class Foo {
{
Bar.<caret>f();
}
}
@@ -0,0 +1,17 @@
// "Add static import for 'test.Bar.f'" "true"
package test;
import static test.Bar1.f;
class Bar {
public static final void f() {}
}
class Bar1 {
public static final void f(int i) {}
}
public class Foo {
{
Bar.<caret>f();
}
}