IDEA-52789: Groovy map literals should have LinkedHashMap type
authorMaxim Medvedev <maxim.medvedev@jetbrains.com>
Tue, 16 Mar 2010 13:14:46 +0000 (16:14 +0300)
committerMaxim Medvedev <maxim.medvedev@jetbrains.com>
Tue, 16 Mar 2010 13:35:03 +0000 (16:35 +0300)
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java
plugins/groovy/testdata/highlighting/IndexPropertyAccess.groovy [new file with mode: 0644]

index 93fb11d11c608fa6ad6ebfbc29a91f8e7146c217..969465c6aab1d47e4935b63d6d8088e978ca059d 100644 (file)
@@ -24,7 +24,6 @@ import com.intellij.util.Function;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
-import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCOMMA;
 import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
@@ -40,6 +39,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpre
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 
+import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCOMMA;
+
 /**
  * @author ilyas
  */
@@ -89,6 +90,7 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap {
   }
 
   private static class MyTypesCalculator implements Function<GrListOrMapImpl, PsiType> {
+    @Nullable
     public PsiType fun(GrListOrMapImpl listOrMap) {
       final GlobalSearchScope scope = listOrMap.getResolveScope();
       if (listOrMap.isMap()) {
@@ -109,7 +111,10 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap {
 
     @Nullable
     private static PsiClassType inferMapInitializerType(GrListOrMapImpl listOrMap, JavaPsiFacade facade, GlobalSearchScope scope) {
-      PsiClass mapClass = facade.findClass("java.util.Map", scope);
+      PsiClass mapClass = facade.findClass("java.util.LinkedHashMap", scope);
+      if (mapClass == null) {
+        mapClass = facade.findClass(CommonClassNames.JAVA_UTIL_MAP, scope);
+      }
       PsiElementFactory factory = facade.getElementFactory();
       if (mapClass != null) {
         PsiTypeParameter[] typeParameters = mapClass.getTypeParameters();
@@ -146,15 +151,20 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap {
       if (labels.length == 0) return null;
       PsiType result = null;
       PsiManager manager = labels[0].getManager();
+      final PsiElementFactory factory = JavaPsiFacade.getElementFactory(labels[0].getProject());
       for (GrArgumentLabel label : labels) {
         PsiElement el = label.getNameElement();
-        final PsiType other;
+        PsiType other;
         if (el instanceof GrParenthesizedExpression) {
           other = ((GrParenthesizedExpression)el).getType();
         }
         else {
-          if (el.getNode() != null) {
-            other = TypesUtil.getPsiType(el, el.getNode().getElementType());
+          final ASTNode node = el.getNode();
+          if (node != null) {
+            other = TypesUtil.getPsiType(el, node.getElementType());
+            if (other == null) {
+              other = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, el.getResolveScope());
+            }
           }
           else {
             other = null;
@@ -186,6 +196,7 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap {
       return result;
     }
 
+    @Nullable
     private static PsiType getLeastUpperBound(PsiType result, PsiType other, PsiManager manager) {
       if (other == null) return result;
       if (result == null) result = other;
index 36b6584c70ed4ec23f754424f54dd1f6cb553ae1..3010d46677e41e2201f5d850f3553ac3904d447f 100644 (file)
@@ -222,7 +222,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
       if (getParent() instanceof GrReferenceExpression) {
         result = facade.getElementFactory().createType((PsiClass) resolved);
       } else {
-        PsiClass javaLangClass = facade.findClass("java.lang.Class", getResolveScope());
+        PsiClass javaLangClass = facade.findClass(CommonClassNames.JAVA_LANG_CLASS, getResolveScope());
         if (javaLangClass != null) {
           PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
           final PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
@@ -239,14 +239,14 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
     } else
     if (resolved instanceof PsiMethod && !GroovyPsiManager.isTypeBeingInferred(resolved)) {
       if (dotType == GroovyTokenTypes.mMEMBER_POINTER) {
-        return facade.getElementFactory().createTypeByFQClassName("groovy.lang.Closure", getResolveScope());
+        return facade.getElementFactory().createTypeByFQClassName(GrClosableBlock.GROOVY_LANG_CLOSURE, getResolveScope());
       }
       PsiMethod method = (PsiMethod) resolved;
       if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) {
         result = method.getParameterList().getParameters()[0].getType();
       } else {
         PsiClass containingClass = method.getContainingClass();
-        if (containingClass != null && "java.lang.Object".equals(containingClass.getQualifiedName()) &&
+        if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
                 "getClass".equals(method.getName())) {
           result = getTypeForObjectGetClass(facade, method);
         } else {
@@ -283,7 +283,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
           PsiClassType.ClassResolveResult qResult = ((PsiClassType) qType).resolveGenerics();
           PsiClass clazz = qResult.getElement();
           if (clazz != null) {
-            PsiClass mapClass = facade.findClass("java.util.Map", getResolveScope());
+            PsiClass mapClass = facade.findClass(CommonClassNames.JAVA_UTIL_MAP, getResolveScope());
             if (mapClass != null && mapClass.getTypeParameters().length == 2) {
               PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
               if (substitutor != null) {
index 3e8f0cfc927240d190f49cb13cde521898fcb098..730d93d2071f5b49a2067d5d70f7cb61a1680ee9 100644 (file)
 package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path;
 
 import com.intellij.lang.ASTNode;
-import com.intellij.psi.CommonClassNames;
-import com.intellij.psi.PsiArrayType;
-import com.intellij.psi.PsiType;
+import com.intellij.psi.*;
 import com.intellij.psi.util.InheritanceUtil;
 import com.intellij.psi.util.PsiUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
+import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
 import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl;
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
@@ -74,9 +74,21 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp
           argTypes[i] = argType;
         }
 
-        final PsiType overloadedOperatorType = TypesUtil.getOverloadedOperatorType(thisType, "getAt", this, argTypes);
-        if (overloadedOperatorType!=null) {
-          return overloadedOperatorType;
+        if (thisType instanceof GrTupleType) {
+          PsiType[] types = ((GrTupleType)thisType).getParameters();
+          return types.length == 1 ? types[0] : null;
+        }
+
+        PsiType overloadedOperatorType = null;
+        final GroovyResolveResult[] candidates = TypesUtil.getOverloadedOperatorCandidates(thisType, "getAt", this, argTypes);
+        if (candidates.length == 1) {
+          final PsiElement element = candidates[0].getElement();
+          if (element instanceof PsiMethod) {
+            overloadedOperatorType = candidates[0].getSubstitutor().substitute(((PsiMethod)element).getReturnType());
+            if (overloadedOperatorType != null && !(element instanceof GrGdkMethod)) {   //gdk 'getAt' methods don't have information about type parameters
+              return overloadedOperatorType;
+            }
+          }
         }
 
         if (thisType instanceof PsiArrayType) {
@@ -84,11 +96,6 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp
           return TypesUtil.boxPrimitiveType(componentType, getManager(), getResolveScope());
         }
 
-        if (thisType instanceof GrTupleType) {
-          PsiType[] types = ((GrTupleType)thisType).getParameters();
-          return types.length == 1 ? types[0] : null;
-        }
-
         if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_LIST)) {
           PsiType iterType = PsiUtil.extractIterableTypeParameter(thisType, true);
           if (iterType != null) return iterType;
@@ -97,6 +104,8 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp
         if (InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP)) {
           return PsiUtil.substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true);
         }
+
+        return overloadedOperatorType;
       }
     }
     return null;
index f38280c2924c28efb2d50b579e0bbd1ed76978a2..2e18835f83809265ab15847b566a70f9d620bb15 100644 (file)
@@ -222,4 +222,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
   }
 
   public void testSuperConstructorInvocation() throws Exception {doTest();}
+
+  public void testIndexPropertyAccess() throws Exception {
+    doTest();
+  }
 }
\ No newline at end of file
diff --git a/plugins/groovy/testdata/highlighting/IndexPropertyAccess.groovy b/plugins/groovy/testdata/highlighting/IndexPropertyAccess.groovy
new file mode 100644 (file)
index 0000000..1c10619
--- /dev/null
@@ -0,0 +1,8 @@
+class X extends HashMap<Integer, Integer> {
+  def getAt(def k) {
+    return "string"
+  }
+}
+
+def x = new X();
+print x[2].concat("a")
\ No newline at end of file