mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-179038 When navigating to method definition specific type information known from DFA could be used to find actual implementation
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -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.fo<caret>o();\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" +
|
||||
|
||||
Reference in New Issue
Block a user