mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
check for static correctness in resolve
This commit is contained in:
@@ -390,99 +390,110 @@ public class PsiUtil {
|
||||
return isStaticsOK(owner, place, null);
|
||||
}
|
||||
|
||||
public static boolean isStaticsOK(PsiModifierListOwner owner, PsiElement place, @Nullable PsiElement resolveContext) {
|
||||
if (owner instanceof PsiMember) {
|
||||
if (place instanceof GrReferenceExpression) {
|
||||
GrExpression qualifier = ((GrReferenceExpression)place).getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
PsiClass containingClass = ((PsiMember)owner).getContainingClass();
|
||||
final boolean isStatic = owner.hasModifierProperty(PsiModifier.STATIC) && !(ResolveUtil.isInUseScope(resolveContext, owner));
|
||||
if (qualifier instanceof GrReferenceExpression) {
|
||||
if ("class".equals(((GrReferenceExpression)qualifier).getReferenceName())) {
|
||||
//invoke static members of class from A.class.foo()
|
||||
final PsiType type = qualifier.getType();
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClass psiClass = ((PsiClassType)type).resolve();
|
||||
if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) {
|
||||
final PsiType[] params = ((PsiClassType)type).getParameters();
|
||||
if (params.length == 1 && params[0] instanceof PsiClassType) {
|
||||
if (place.getManager().areElementsEquivalent(containingClass, ((PsiClassType)params[0]).resolve())) {
|
||||
return owner.hasModifierProperty(GrModifier.STATIC);
|
||||
}
|
||||
}
|
||||
public static boolean isStaticsOK(PsiModifierListOwner member, PsiElement place, @Nullable PsiElement resolveContext) {
|
||||
if (!(member instanceof PsiMember)) return true;
|
||||
|
||||
if (!(place instanceof GrReferenceExpression)) return true;
|
||||
|
||||
GrExpression qualifier = ((GrReferenceExpression)place).getQualifierExpression();
|
||||
final PsiClass containingClass = ((PsiMember)member).getContainingClass();
|
||||
if (qualifier != null) {
|
||||
final boolean isStatic = member.hasModifierProperty(PsiModifier.STATIC) && !(ResolveUtil.isInUseScope(resolveContext, member));
|
||||
if (qualifier instanceof GrReferenceExpression) {
|
||||
if ("class".equals(((GrReferenceExpression)qualifier).getReferenceName())) {
|
||||
//invoke static members of class from A.class.foo()
|
||||
final PsiType type = qualifier.getType();
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClass psiClass = ((PsiClassType)type).resolve();
|
||||
if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) {
|
||||
final PsiType[] params = ((PsiClassType)type).getParameters();
|
||||
if (params.length == 1 && params[0] instanceof PsiClassType) {
|
||||
if (place.getManager().areElementsEquivalent(containingClass, ((PsiClassType)params[0]).resolve())) {
|
||||
return member.hasModifierProperty(GrModifier.STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
PsiElement qualifierResolved = ((GrReferenceExpression)qualifier).resolve();
|
||||
if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) { //static context
|
||||
if (owner instanceof PsiClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//non-physical method, e.g. gdk
|
||||
if (containingClass == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isStatic) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//members from java.lang.Class can be invoked without ".class"
|
||||
final String qname = containingClass.getQualifiedName();
|
||||
if (qname != null && qname.startsWith("java.")) {
|
||||
if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname) || CommonClassNames.JAVA_LANG_CLASS.equals(qname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (containingClass.isInterface()) {
|
||||
PsiClass javaLangClass =
|
||||
JavaPsiFacade.getInstance(place.getProject()).findClass(CommonClassNames.JAVA_LANG_CLASS, place.getResolveScope());
|
||||
if (javaLangClass != null && javaLangClass.isInheritor(containingClass, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (qualifier instanceof GrThisReferenceExpression && ((GrThisReferenceExpression)qualifier).getQualifier() == null) {
|
||||
//static members may be invoked from this.<...>
|
||||
final boolean isInStatic = isInStaticContext((GrThisReferenceExpression)qualifier);
|
||||
if (containingClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(containingClass.getQualifiedName())) {
|
||||
return !(owner.hasModifierProperty(GrModifier.STATIC) && !CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE);
|
||||
}
|
||||
else if (isInStatic) return owner.hasModifierProperty(GrModifier.STATIC);
|
||||
}
|
||||
|
||||
//instance context
|
||||
if (owner instanceof PsiClass) {
|
||||
return false;
|
||||
}
|
||||
return !(isStatic && !CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE);
|
||||
}
|
||||
else {
|
||||
if (((PsiMember)owner).getContainingClass() == null) return true;
|
||||
if (owner instanceof GrVariable && !(owner instanceof GrField)) return true;
|
||||
if (owner.hasModifierProperty(GrModifier.STATIC)) return true;
|
||||
PsiElement qualifierResolved = ((GrReferenceExpression)qualifier).resolve();
|
||||
if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) { //static context
|
||||
if (member instanceof PsiClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiElement stopAt = resolveContext != null ? PsiTreeUtil.findCommonParent(place, resolveContext) : null;
|
||||
while (place != null && place != stopAt && !(place instanceof GrMember)) {
|
||||
if (place instanceof PsiFile) break;
|
||||
place = place.getParent();
|
||||
//non-physical method, e.g. gdk
|
||||
if (containingClass == null) {
|
||||
return true;
|
||||
}
|
||||
if (place == null || place instanceof PsiFile || place == stopAt) return true;
|
||||
if (place instanceof GrTypeDefinition) {
|
||||
return !(((GrTypeDefinition)place).hasModifierProperty(GrModifier.STATIC) ||
|
||||
((GrTypeDefinition)place).getContainingClass() == null);
|
||||
|
||||
if (isStatic) {
|
||||
return true;
|
||||
}
|
||||
return !((GrMember)place).hasModifierProperty(GrModifier.STATIC);
|
||||
|
||||
//members from java.lang.Class can be invoked without ".class"
|
||||
final String qname = containingClass.getQualifiedName();
|
||||
if (qname != null && qname.startsWith("java.")) {
|
||||
if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname) || CommonClassNames.JAVA_LANG_CLASS.equals(qname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (containingClass.isInterface()) {
|
||||
PsiClass javaLangClass =
|
||||
JavaPsiFacade.getInstance(place.getProject()).findClass(CommonClassNames.JAVA_LANG_CLASS, place.getResolveScope());
|
||||
if (javaLangClass != null && javaLangClass.isInheritor(containingClass, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (qualifier instanceof GrThisReferenceExpression && ((GrThisReferenceExpression)qualifier).getQualifier() == null) {
|
||||
//static members may be invoked from this.<...>
|
||||
final boolean isInStatic = isInStaticContext((GrThisReferenceExpression)qualifier);
|
||||
if (containingClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(containingClass.getQualifiedName())) {
|
||||
return !(member.hasModifierProperty(GrModifier.STATIC) && !CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE);
|
||||
}
|
||||
else if (isInStatic) return member.hasModifierProperty(GrModifier.STATIC);
|
||||
}
|
||||
|
||||
//instance context
|
||||
if (member instanceof PsiClass) {
|
||||
return false;
|
||||
}
|
||||
return !(isStatic && !CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE);
|
||||
}
|
||||
else {
|
||||
if (containingClass == null) return true;
|
||||
if (member instanceof GrVariable && !(member instanceof GrField)) return true;
|
||||
if (member.hasModifierProperty(GrModifier.STATIC)) return true;
|
||||
|
||||
if (resolveContext != null) {
|
||||
PsiElement stopAt = PsiTreeUtil.findCommonParent(place, resolveContext);
|
||||
while (place != null && place != stopAt && !(place instanceof GrMember)) {
|
||||
if (place instanceof PsiFile) break;
|
||||
place = place.getParent();
|
||||
}
|
||||
if (place == null || place instanceof PsiFile || place == stopAt) return true;
|
||||
if (place instanceof GrTypeDefinition) {
|
||||
return !(((GrTypeDefinition)place).hasModifierProperty(GrModifier.STATIC) ||
|
||||
((GrTypeDefinition)place).getContainingClass() == null);
|
||||
}
|
||||
return !((GrMember)place).hasModifierProperty(GrModifier.STATIC);
|
||||
}
|
||||
else {
|
||||
while (place != null) {
|
||||
place = place.getParent();
|
||||
if (place instanceof PsiClass && InheritanceUtil.isInheritorOrSelf((PsiClass)place, containingClass, true)) return true;
|
||||
if (place instanceof PsiMember && ((PsiMember)place).hasModifierProperty(PsiModifier.STATIC)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAccessible(PsiElement place, PsiMember member) {
|
||||
@@ -532,6 +543,7 @@ public class PsiUtil {
|
||||
else {
|
||||
PsiElement run = refExpression;
|
||||
while (run != null && run != targetClass) {
|
||||
if (targetClass == null && run instanceof PsiClass) return false;
|
||||
if (run instanceof PsiModifierListOwner && ((PsiModifierListOwner)run).hasModifierProperty(PsiModifier.STATIC)) return true;
|
||||
run = run.getParent();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.jetbrains.plugins.groovy.lang.resolve;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.util.TestUtils;
|
||||
|
||||
/**
|
||||
* @author Medvedev Max
|
||||
*/
|
||||
public class StaticCheckTest extends GroovyResolveTestCase {
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return TestUtils.getTestDataPath() + "resolve/static/";
|
||||
}
|
||||
|
||||
protected void doTest(boolean staticOk) {
|
||||
final GroovyResolveResult resolveResult = advancedResolve("a.groovy");
|
||||
assertNotNull(resolveResult);
|
||||
final PsiElement element = resolveResult.getElement();
|
||||
assertNotNull(element);
|
||||
assertEquals(staticOk, resolveResult.isStaticsOK());
|
||||
}
|
||||
|
||||
public void testPropInStaticInnerClass() {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
public void testThisInStaticInnerClass() {
|
||||
doTest(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
def someService
|
||||
|
||||
static private class B {
|
||||
void method() { someServi<ref>ce }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
def someService
|
||||
|
||||
static private class B {
|
||||
int ii
|
||||
B () { this.i<ref>i = 42 }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user