check for static correctness in resolve

This commit is contained in:
Maxim Medvedev
2011-06-06 12:17:57 +04:00
parent ccf00f94e6
commit 238eea0d66
4 changed files with 139 additions and 81 deletions
@@ -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 }
}
}