[groovy] map access improvements

- Do not resolve reference if qualifier is inheritor of `java.util.Map`.
- Get inferred type from map access only when qualifier is not resolved to a class.
- Use qualifier's full type instead of nominal type when getting map values type.
This commit is contained in:
Daniil Ovchinnikov
2015-10-27 21:15:34 +03:00
parent 472fff60b8
commit 2656dddf65
2 changed files with 60 additions and 19 deletions
@@ -105,13 +105,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
if (!InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) return false;
final String qname = TypesUtil.getQualifiedName(type);
if (qname != null) {
if (qname.startsWith("java.")) return true; //so we have jdk map here
if (GroovyCommonClassNames.GROOVY_UTIL_CONFIG_OBJECT.equals(qname)) return false;
if (qname.startsWith("groovy.")) return true; //we have gdk map here
}
return false;
return qname == null || !GroovyCommonClassNames.GROOVY_UTIL_CONFIG_OBJECT.equals(qname);
}
@NotNull
@@ -713,8 +707,11 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
private static PsiType getTypeFromMapAccess(@NotNull GrReferenceExpressionImpl ref) {
//map access
GrExpression qualifier = ref.getQualifierExpression();
if (qualifier instanceof GrReferenceExpression) {
if (((GrReferenceExpression)qualifier).resolve() instanceof PsiClass) return null;
}
if (qualifier != null) {
PsiType qType = qualifier.getNominalType();
PsiType qType = qualifier.getType();
if (qType instanceof PsiClassType) {
PsiClassType.ClassResolveResult qResult = ((PsiClassType)qType).resolveGenerics();
PsiClass clazz = qResult.getElement();
@@ -814,16 +811,18 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
@Nullable
private static PsiType getInferredTypes(@NotNull GrReferenceExpressionImpl refExpr, @Nullable PsiElement resolved) {
final GrExpression qualifier = refExpr.getQualifier();
if (qualifier == null && !(resolved instanceof PsiClass || resolved instanceof PsiPackage)) {
return TypeInferenceHelper.getCurrentContext().getVariableType(refExpr);
}
else if (qualifier != null) {
//map access
PsiType qType = qualifier.getType();
if (qType instanceof PsiClassType && !(qType instanceof GrMapType)) {
final PsiType mapValueType = getTypeFromMapAccess(refExpr);
if (mapValueType != null) {
return mapValueType;
if (!(resolved instanceof PsiClass) && !(resolved instanceof PsiPackage)) {
if (qualifier == null) {
return TypeInferenceHelper.getCurrentContext().getVariableType(refExpr);
}
else {
//map access
PsiType qType = qualifier.getType();
if (qType instanceof PsiClassType && !(qType instanceof GrMapType)) {
final PsiType mapValueType = getTypeFromMapAccess(refExpr);
if (mapValueType != null) {
return mapValueType;
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.resolve
import com.intellij.psi.*
import com.intellij.psi.util.PropertyUtil
import org.jetbrains.plugins.groovy.GroovyFileType
@@ -23,6 +24,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrClassDefinition
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod
@@ -31,6 +33,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrTraitMethod
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil
import org.jetbrains.plugins.groovy.util.TestUtils
/**
* @author ven
*/
@@ -718,6 +721,45 @@ print map.cla<caret>ss''')
assert !ref.resolve()
}
void 'test custom map properties'() {
myFixture.addFileToProject 'classes.groovy', '''\
class Pojo {
def pojoProperty
def anotherPojoProperty
}
class SomeMapClass extends HashMap<String, Pojo> {
public static final CONSTANT = 1
static class Inner {
public static final INNER_CONSTANT = 4
}
}
'''
(configureByText('SomeMapClass.CONST<caret>ANT').element as GrReferenceExpression).with { ref ->
assert ref.resolve() instanceof GrField
assert ref.type.equalsToText('java.lang.Integer')
}
(configureByText('SomeMapClass.Inn<caret>er').element as GrReferenceExpression).with { ref ->
assert ref.resolve() instanceof GrClassDefinition
assert ref.type.equalsToText('java.lang.Class<SomeMapClass.Inner>')
}
assert configureByText('SomeMapClass.Inner.INNER_<caret>CONSTANT').resolve() instanceof GrField
assert !configureByText('def m = new SomeMapClass(); m.CONS<caret>TANT').resolve()
assert !configureByText('def m = new SomeMapClass(); m.In<caret>ner').resolve()
configureByText('def m = new SomeMapClass(); m.CONSTANT.pojo<caret>Property').resolve().with { resolved ->
assert resolved instanceof GrAccessorMethod
assert resolved.containingClass.name == 'Pojo'
}
configureByText('def m = new SomeMapClass(); m.Inner.anotherPojo<caret>Property').resolve().with { resolved ->
assert resolved instanceof GrAccessorMethod
assert resolved.containingClass.name == 'Pojo'
}
}
public void testResolveInsideWith0() {
def resolved = resolve('a.groovy', GrAccessorMethod)
assertEquals(resolved.containingClass.name, 'A')