reference to static method from interface: prefer static import context if provided (IDEA-130136)

This commit is contained in:
Anna Kozlova
2014-09-30 15:43:42 +02:00
parent 30b12e3e25
commit 3f940f370f
6 changed files with 59 additions and 22 deletions

View File

@@ -206,7 +206,7 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) {
refExpr.setQualifierExpression(null);
}
else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)){
else if (!ImportsUtil.hasStaticImportOn(refExpr, member, false)){
PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory();
refExpr.setQualifierExpression(factory.createReferenceExpression(aClass));
}

View File

@@ -210,26 +210,6 @@ public class RefactoringUtil {
return false;
}
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) {
final PsiClass containingClass = member.getContainingClass();
final String referenceName = stmt.getReferenceName();
if (!stmt.isOnDemand() && stmt.resolveTargetClass() == containingClass && Comparing.strEqual(referenceName, member.getName())) {
if (member instanceof PsiMethod) {
return containingClass.findMethodsByName(referenceName, false).length == 1;
}
return true;
}
}
}
}
return false;
}
public static PsiElement replaceElementsWithMap(PsiElement replaceIn, final Map<PsiElement, PsiElement> elementsToReplace) throws IncorrectOperationException {
for(Map.Entry<PsiElement, PsiElement> e: elementsToReplace.entrySet()) {
if (e.getKey() == replaceIn) {

View File

@@ -15,6 +15,7 @@
*/
package com.intellij.psi.util;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -79,4 +80,29 @@ public class ImportsUtil {
refExpr.replace(elementFactory.createReferenceFromText(referenceExpression.getText() + "." + refExpr.getText(), refExpr));
}
}
public static boolean hasStaticImportOn(final PsiElement expr, final PsiMember member, boolean acceptOnDemand) {
if (expr.getContainingFile() instanceof PsiJavaFile) {
final PsiImportList importList = ((PsiJavaFile)expr.getContainingFile()).getImportList();
if (importList != null) {
final PsiImportStaticStatement[] importStaticStatements = importList.getImportStaticStatements();
for (PsiImportStaticStatement stmt : importStaticStatements) {
final PsiClass containingClass = member.getContainingClass();
final String referenceName = stmt.getReferenceName();
if (containingClass != null && stmt.resolveTargetClass() == containingClass) {
if (!stmt.isOnDemand() && Comparing.strEqual(referenceName, member.getName())) {
if (member instanceof PsiMethod) {
return containingClass.findMethodsByName(referenceName, false).length == 1;
}
return true;
}
if (acceptOnDemand && stmt.isOnDemand()) {
return true;
}
}
}
}
}
return false;
}
}

View File

@@ -21,6 +21,7 @@ import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.PsiConflictResolver;
import com.intellij.psi.scope.conflictResolvers.DuplicateConflictResolver;
import com.intellij.psi.util.ImportsUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
@@ -54,7 +55,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
final boolean isAccessible = JavaResolveUtil.isAccessible(method, getContainingClass(method), method.getModifierList(),
myPlace, myAccessClass, myCurrentFileContext, myPlaceFile) &&
!isShadowed(method);
if (isAccepted(method)) {
if (isAccepted(method) && !(isInterfaceStaticMethodAccessibleThroughInheritance(method) && ImportsUtil.hasStaticImportOn(myPlace, method, true))) {
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible, false));
if (acceptVarargs() && method.isVarArgs() && PsiUtil.isLanguageLevel8OrHigher(myPlace)) {
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible, true));
@@ -63,6 +64,14 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
}
}
private boolean isInterfaceStaticMethodAccessibleThroughInheritance(PsiMethod method) {
if (method.hasModifierProperty(PsiModifier.STATIC) && !(myCurrentFileContext instanceof PsiImportStaticStatement)) {
final PsiClass containingClass = method.getContainingClass();
return containingClass != null && containingClass.isInterface();
}
return false;
}
protected PsiClass getContainingClass(PsiMethod method) {
return method.getContainingClass();
}

View File

@@ -0,0 +1,11 @@
import p.*;
import static p.Foo.bar;
import static p.Boo.*;
class FooImpl implements Foo, Boo {
public void baz() {
<error descr="Static method may be invoked on containing interface class only">foo();</error>
bar();
boo();
}
}

View File

@@ -47,6 +47,17 @@ public class Interface8MethodsHighlightingTest extends LightCodeInsightFixtureTe
doTest(false, false);
}
public void testStaticMethodAccessibleBothThroughStaticImportAndInheritance() throws Exception {
myFixture.addClass("package p; public interface Foo {" +
" static void foo() {}" +
" static void bar() {}" +
"}");
myFixture.addClass("package p; public interface Boo {" +
" static void boo() {}" +
"}");
doTest(false, false);
}
public void testSuperProtectedCalls() throws Exception {
myFixture.addClass("package p; public class Foo {" +
" protected void foo(){}" +