diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java b/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java index 076c8b39aa6c..9444bad89f21 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java @@ -15,6 +15,9 @@ */ package com.intellij.codeInsight; +import com.intellij.codeInspection.dataFlow.CommonDataflow; +import com.intellij.codeInspection.dataFlow.DfaFactType; +import com.intellij.codeInspection.dataFlow.TypeConstraint; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.Computable; @@ -38,18 +41,19 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem public static final int NEW_AS_CONSTRUCTOR = 0x04; public static final int THIS_ACCEPTED = 0x10; public static final int SUPER_ACCEPTED = 0x20; + public static final int USE_DFA = 0x40; @Override public int getAllAdditionalFlags() { - return NEW_AS_CONSTRUCTOR | THIS_ACCEPTED | SUPER_ACCEPTED; + return NEW_AS_CONSTRUCTOR | THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA; } /** - * Accepts THIS or SUPER but not NEW_AS_CONSTRUCTOR. + * Accepts THIS or SUPER or USE_DFA but not NEW_AS_CONSTRUCTOR. */ @Override public int getAdditionalDefinitionSearchFlags() { - return THIS_ACCEPTED | SUPER_ACCEPTED; + return THIS_ACCEPTED | SUPER_ACCEPTED | USE_DFA; } /** @@ -78,6 +82,32 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem return ((PsiClassType)type).resolve(); } } + if (targetElement instanceof PsiMethod && BitUtil.isSet(flags, USE_DFA)) { + PsiMethod method = (PsiMethod)targetElement; + PsiClass qualifierClass = method.getContainingClass(); + if (!method.hasModifierProperty(PsiModifier.PRIVATE) && + !method.hasModifierProperty(PsiModifier.FINAL) && + !method.hasModifierProperty(PsiModifier.STATIC) && + qualifierClass != null) { + PsiReference reference = TargetElementUtil.findReference(editor, offset); + if (reference instanceof PsiReferenceExpression && reference.isReferenceTo(targetElement)) { + PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression(); + if (qualifier != null) { + TypeConstraint constraint = CommonDataflow.getExpressionFact(qualifier, DfaFactType.TYPE_CONSTRAINT); + if (constraint != null) { + PsiClass specificQualifierClass = PsiUtil.resolveClassInClassTypeOnly(constraint.getPsiType()); + if (specificQualifierClass != null && !specificQualifierClass.equals(qualifierClass) && + InheritanceUtil.isInheritorOrSelf(specificQualifierClass, qualifierClass, true)) { + PsiMethod realMethod = specificQualifierClass.findMethodBySignature(method, true); + if (realMethod != null) { + return realMethod; + } + } + } + } + } + } + } return super.adjustTargetElement(editor, offset, flags, targetElement); } diff --git a/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java b/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java index e2736c6edc99..6a0962f503cf 100644 --- a/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java +++ b/java/java-tests/testSrc/com/intellij/java/navigation/GotoImplementationHandlerTest.java @@ -55,6 +55,29 @@ public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCas assertEquals(2, impls.length); } + public void testUnderInstanceOf() { + PsiFile file = myFixture.addFileToProject("Foo.java", "abstract class Hello {\n" + + " abstract void foo();\n" + + "\n" + + " void test(Hello h) {\n" + + " if(h instanceof Hello1) h.foo();\n" + + " }\n" + + " \n" + + " class Hello1 extends Hello {\n" + + " void foo() {}\n" + + " }\n" + + " class Hello2 extends Hello {\n" + + " void foo() {}\n" + + " }\n" + + "}"); + myFixture.configureFromExistingVirtualFile(file.getVirtualFile()); + + final PsiElement[] impls = getTargets(file); + assertEquals(1, impls.length); + assertTrue(impls[0] instanceof PsiMethod); + assertEquals("Hello.Hello1", ((PsiMethod)impls[0]).getContainingClass().getQualifiedName()); + } + public void testFromIncompleteCode() { PsiFile file = myFixture.addFileToProject("Foo.java", "public abstract class Hello {\n" + " abstract void foo();\n" +