From 21c1cbff0529f8670f50537d06781abbd8c394f9 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Tue, 8 Apr 2014 12:34:02 +0400 Subject: [PATCH] IDEA-123337 lazy type inference for map literals --- .../lang/psi/impl/GrLiteralClassType.java | 17 +- .../groovy/lang/psi/impl/GrMapType.java | 179 +++++++----------- .../lang/psi/impl/GrMapTypeFromNamedArgs.java | 169 +++++++++++++++++ .../groovy/lang/psi/impl/GrMapTypeImpl.java | 118 ++++++++++++ .../psi/impl/auxiliary/GrListOrMapImpl.java | 30 +-- .../signatures/GrClosureSignatureUtil.java | 2 +- .../expressions/GrNewExpressionImpl.java | 2 +- .../statements/expressions/TypesUtil.java | 3 +- .../plugins/groovy/lang/psi/util/PsiUtil.java | 3 +- 9 files changed, 378 insertions(+), 145 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeImpl.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java index 8559f53e9f7e..a7b6a6f41077 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -46,10 +47,16 @@ public abstract class GrLiteralClassType extends PsiClassType { @Override @NotNull public ClassResolveResult resolveGenerics() { - final PsiClass myBaseClass = resolve(); - final PsiSubstitutor substitutor = inferSubstitutor(myBaseClass); - return new ClassResolveResult() { + private final PsiClass myBaseClass = resolve(); + + private final NotNullLazyValue mySubstitutor = new NotNullLazyValue() { + @NotNull + @Override + protected PsiSubstitutor compute() { + return inferSubstitutor(myBaseClass); + } + }; @Override public PsiClass getElement() { @@ -59,7 +66,7 @@ public abstract class GrLiteralClassType extends PsiClassType { @Override @NotNull public PsiSubstitutor getSubstitutor() { - return substitutor; + return mySubstitutor.getValue(); } @Override @@ -167,7 +174,7 @@ public abstract class GrLiteralClassType extends PsiClassType { @Override public boolean equalsToText(@NotNull @NonNls String text) { - return text != null && text.equals(getJavaClassName()); + return text.equals(getJavaClassName()); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java index 1142db27a5f4..f4a43045041b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java @@ -16,17 +16,19 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.*; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClassType; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import java.util.*; @@ -36,49 +38,33 @@ import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames. /** * @author peter */ -public class GrMapType extends GrLiteralClassType { - private final Map myStringEntries; - private final List> myOtherEntries; +public abstract class GrMapType extends GrLiteralClassType { private final String myJavaClassName; - private GrMapType(JavaPsiFacade facade, - GlobalSearchScope scope, - Map stringEntries, - List> otherEntries, - LanguageLevel languageLevel) { - super(languageLevel, scope, facade); - myStringEntries = stringEntries; - myOtherEntries = otherEntries; + private final AtomicNotNullLazyValue myParameters = new AtomicNotNullLazyValue() { + @NotNull + @Override + protected PsiType[] compute() { + final PsiType[] keyTypes = getAllKeyTypes(); + final PsiType[] valueTypes = getAllValueTypes(); + if (keyTypes.length == 0 && valueTypes.length == 0) { + return EMPTY_ARRAY; + } - myJavaClassName = facade.findClass(JAVA_UTIL_LINKED_HASH_MAP, scope) != null ? JAVA_UTIL_LINKED_HASH_MAP : JAVA_UTIL_MAP; + return new PsiType[]{getLeastUpperBound(keyTypes), getLeastUpperBound(valueTypes)}; + } + }; + + protected GrMapType(JavaPsiFacade facade, GlobalSearchScope scope) { + this(facade, scope, LanguageLevel.JDK_1_5); } - public GrMapType(@NotNull PsiElement context, GrNamedArgument[] args) { - super(LanguageLevel.JDK_1_5, context.getResolveScope(), JavaPsiFacade.getInstance(context.getProject())); + protected GrMapType(JavaPsiFacade facade, + GlobalSearchScope scope, + LanguageLevel languageLevel) { + super(languageLevel, scope, facade); - myJavaClassName = myFacade.findClass(JAVA_UTIL_LINKED_HASH_MAP, myScope) != null ? JAVA_UTIL_LINKED_HASH_MAP : JAVA_UTIL_MAP; - - myStringEntries = new HashMap(); - myOtherEntries = new ArrayList>(); - - for (GrNamedArgument arg : args) { - GrArgumentLabel label = arg.getLabel(); - if (label == null) continue; - - GrExpression expression = arg.getExpression(); - if (expression == null || expression.getType() == null) continue; - - String labelName = label.getName(); - GrExpression labelExpression = label.getExpression(); - - if (labelName != null) { - myStringEntries.put(labelName, expression.getType()); - } - else if (labelExpression != null) { - PsiType type = labelExpression.getType(); - myOtherEntries.add(new Pair(type, expression.getType())); - } - } + myJavaClassName = facade.findClass(JAVA_UTIL_LINKED_HASH_MAP, scope) != null ? JAVA_UTIL_LINKED_HASH_MAP : JAVA_UTIL_MAP; } @NotNull @@ -94,63 +80,49 @@ public class GrMapType extends GrLiteralClassType { } @Nullable - public PsiType getTypeByStringKey(String key) { - return myStringEntries.get(key); - } + public abstract PsiType getTypeByStringKey(String key); - public Set getStringKeys() { - return myStringEntries.keySet(); - } + @NotNull + public abstract Set getStringKeys(); - public PsiType[] getAllKeyTypes() { - Set result = new HashSet(); - if (!myStringEntries.isEmpty()) { - result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope())); - } - for (Pair entry : myOtherEntries) { - result.add(entry.first); - } - result.remove(null); - return result.toArray(createArray(result.size())); - } + public abstract boolean isEmpty(); - public PsiType[] getAllValueTypes() { - Set result = new HashSet(); - result.addAll(myStringEntries.values()); - for (Pair entry : myOtherEntries) { - result.add(entry.second); - } - result.remove(null); - return result.toArray(createArray(result.size())); - } + @NotNull + protected abstract PsiType[] getAllKeyTypes(); + + @NotNull + protected abstract PsiType[] getAllValueTypes(); + + @NotNull + protected abstract List> getOtherEntries(); + + @NotNull + protected abstract Map getStringEntries(); @Override @NotNull public PsiType[] getParameters() { - final PsiType[] keyTypes = getAllKeyTypes(); - final PsiType[] valueTypes = getAllValueTypes(); - if (keyTypes.length == 0 && valueTypes.length == 0) { - return EMPTY_ARRAY; - } - - return new PsiType[]{getLeastUpperBound(keyTypes), getLeastUpperBound(valueTypes)}; + return myParameters.getValue(); } @Override @NotNull public String getInternalCanonicalText() { - if (myStringEntries.isEmpty()) { - if (myOtherEntries.isEmpty()) return "[:]"; + Set stringKeys = getStringKeys(); + List> otherEntries = getOtherEntries(); + + if (stringKeys.isEmpty()) { + if (otherEntries.isEmpty()) return "[:]"; String name = getJavaClassName(); final PsiType[] params = getParameters(); return name + "<" + getInternalText(params[0]) + ", " + getInternalText(params[1]) + ">"; } List components = new ArrayList(); - for (String s : myStringEntries.keySet()) { - components.add("'" + s + "':" + getInternalCanonicalText(myStringEntries.get(s))); + for (String s : stringKeys) { + components.add("'" + s + "':" + getInternalCanonicalText(getTypeByStringKey(s))); } - for (Pair entry : myOtherEntries) { + for (Pair entry : otherEntries) { components.add(getInternalCanonicalText(entry.first) + ":" + getInternalCanonicalText(entry.second)); } boolean tooMany = components.size() > 2; @@ -163,34 +135,11 @@ public class GrMapType extends GrLiteralClassType { return param == null ? "null" : param.getInternalCanonicalText(); } - @Override - public boolean isValid() { - for (PsiType type : myStringEntries.values()) { - if (type != null && !type.isValid()) { - return false; - } - } - for (Pair entry : myOtherEntries) { - if (entry.first != null && !entry.first.isValid()) { - return false; - } - if (entry.second != null && !entry.second.isValid()) { - return false; - } - } - - return true; - } - - @Override - @NotNull - public PsiClassType setLanguageLevel(@NotNull final LanguageLevel languageLevel) { - return new GrMapType(myFacade, getResolveScope(), myStringEntries, myOtherEntries, languageLevel); - } - public boolean equals(Object obj) { if (obj instanceof GrMapType) { - return myStringEntries.equals(((GrMapType)obj).myStringEntries) && myOtherEntries.equals(((GrMapType)obj).myOtherEntries); + GrMapType other = (GrMapType)obj; + return getStringEntries().equals(other.getStringEntries()) && + getOtherEntries().equals(other.getOtherEntries()); } return super.equals(obj); } @@ -204,12 +153,12 @@ public class GrMapType extends GrLiteralClassType { final GlobalSearchScope scope = l.getScope().intersectWith(r.getResolveScope()); final Map strings = new HashMap(); - strings.putAll(l.myStringEntries); - strings.putAll(r.myStringEntries); + strings.putAll(l.getStringEntries()); + strings.putAll(r.getStringEntries()); List> other = new ArrayList>(); - other.addAll(l.myOtherEntries); - other.addAll(r.myOtherEntries); + other.addAll(l.getOtherEntries()); + other.addAll(r.getOtherEntries()); return create(l.myFacade, scope, strings, other); } @@ -218,13 +167,23 @@ public class GrMapType extends GrLiteralClassType { GlobalSearchScope scope, Map stringEntries, List> otherEntries) { - return new GrMapType(facade, scope, stringEntries, otherEntries, LanguageLevel.JDK_1_5); + return new GrMapTypeImpl(facade, scope, stringEntries, otherEntries, LanguageLevel.JDK_1_5); } public static GrMapType create(GlobalSearchScope scope) { JavaPsiFacade facade = JavaPsiFacade.getInstance(scope.getProject()); List> otherEntries = Collections.emptyList(); Map stringEntries = Collections.emptyMap(); - return new GrMapType(facade, scope, stringEntries, otherEntries, LanguageLevel.JDK_1_5); + return new GrMapTypeImpl(facade, scope, stringEntries, otherEntries, LanguageLevel.JDK_1_5); + } + + @NotNull + @Override + public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) { + return new GrMapTypeImpl(myFacade, getResolveScope(), getStringEntries(), getOtherEntries(), languageLevel); + } + + public static GrMapType createFromNamedArgs(PsiElement context, GrNamedArgument[] args) { + return new GrMapTypeFromNamedArgs(context, args); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java new file mode 100644 index 000000000000..16e94872a70d --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java @@ -0,0 +1,169 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl; + +import com.intellij.openapi.util.AtomicNotNullLazyValue; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Created by Max Medvedev on 07/04/14 + */ +public class GrMapTypeFromNamedArgs extends GrMapType { + + private final Map myStringEntries; + private final List> myOtherEntries; + + private final AtomicNotNullLazyValue>> myTypesOfOtherEntries = new AtomicNotNullLazyValue>>() { + @NotNull + @Override + protected List> compute() { + return ContainerUtil.map(myOtherEntries, new Function, Pair>() { + @Override + public Pair fun(Pair pair) { + return Pair.create(pair.first.getType(), pair.second.getType()); + } + }); + } + }; + + private final AtomicNotNullLazyValue> myTypesOfStringEntries = new AtomicNotNullLazyValue>() { + @NotNull + @Override + protected Map compute() { + HashMap result = ContainerUtil.newHashMap(); + for (Map.Entry entry : myStringEntries.entrySet()) { + result.put(entry.getKey(), entry.getValue().getType()); + } + return result; + } + + }; + + public GrMapTypeFromNamedArgs(@NotNull PsiElement context, @NotNull GrNamedArgument[] namedArgs) { + this(JavaPsiFacade.getInstance(context.getProject()), context.getResolveScope(), namedArgs); + } + + public GrMapTypeFromNamedArgs(@NotNull JavaPsiFacade facade, @NotNull GlobalSearchScope scope, @NotNull GrNamedArgument[] namedArgs) { + super(facade, scope); + + myStringEntries = ContainerUtil.newHashMap(); + myOtherEntries = ContainerUtil.newArrayList(); + for (GrNamedArgument namedArg : namedArgs) { + final GrArgumentLabel label = namedArg.getLabel(); + final GrExpression expression = namedArg.getExpression(); + if (label == null || expression == null) { + continue; + } + + final String name = label.getName(); + if (name != null) { + myStringEntries.put(name, expression); + } + else if (label.getExpression() != null) { + myOtherEntries.add(Pair.create(label.getExpression(), expression)); + } + } + } + + @Nullable + @Override + public PsiType getTypeByStringKey(String key) { + GrExpression expression = myStringEntries.get(key); + return expression != null ? expression.getType() : null; + } + + @NotNull + @Override + public Set getStringKeys() { + return myStringEntries.keySet(); + } + + @Override + public boolean isEmpty() { + return myStringEntries.isEmpty() && myOtherEntries.isEmpty(); + } + + @NotNull + @Override + protected PsiType[] getAllKeyTypes() { + Set result = ContainerUtil.newHashSet(); + if (!myStringEntries.isEmpty()) { + result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope())); + } + for (Pair entry : myOtherEntries) { + result.add(entry.first.getType()); + } + result.remove(null); + return result.toArray(createArray(result.size())); + } + + @NotNull + @Override + protected PsiType[] getAllValueTypes() { + Set result = ContainerUtil.newHashSet(); + for (GrExpression expression : myStringEntries.values()) { + result.add(expression.getType()); + } + for (Pair entry : myOtherEntries) { + result.add(entry.second.getType()); + } + result.remove(null); + return result.toArray(createArray(result.size())); + } + + @NotNull + @Override + protected List> getOtherEntries() { + return myTypesOfOtherEntries.getValue(); + } + + @NotNull + @Override + protected Map getStringEntries() { + return myTypesOfStringEntries.getValue(); + } + + @Override + public boolean isValid() { + for (GrExpression expression : myStringEntries.values()) { + if (!expression.isValid()) return false; + } + + for (Pair entry : myOtherEntries) { + if (!entry.first.isValid()) return false; + if (!entry.second.isValid()) return false; + } + + return true; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeImpl.java new file mode 100644 index 000000000000..4c9e1cf5228e --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeImpl.java @@ -0,0 +1,118 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl; + +import com.intellij.openapi.util.Pair; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Created by Max Medvedev on 07/04/14 + */ +public class GrMapTypeImpl extends GrMapType { + private final Map myStringEntries; + private final List> myOtherEntries; + + GrMapTypeImpl(JavaPsiFacade facade, + GlobalSearchScope scope, + Map stringEntries, + List> otherEntries, + LanguageLevel languageLevel) { + super(facade, scope, languageLevel); + myStringEntries = stringEntries; + myOtherEntries = otherEntries; + } + + @Nullable + public PsiType getTypeByStringKey(String key) { + return myStringEntries.get(key); + } + + @NotNull + public Set getStringKeys() { + return myStringEntries.keySet(); + } + + @NotNull + protected PsiType[] getAllKeyTypes() { + Set result = new HashSet(); + if (!myStringEntries.isEmpty()) { + result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope())); + } + for (Pair entry : myOtherEntries) { + result.add(entry.first); + } + result.remove(null); + return result.toArray(createArray(result.size())); + } + + @NotNull + protected PsiType[] getAllValueTypes() { + Set result = new HashSet(); + result.addAll(myStringEntries.values()); + for (Pair entry : myOtherEntries) { + result.add(entry.second); + } + result.remove(null); + return result.toArray(createArray(result.size())); + } + + @NotNull + @Override + protected List> getOtherEntries() { + return myOtherEntries; + } + + @NotNull + @Override + protected Map getStringEntries() { + return myStringEntries; + } + + @Override + public boolean isValid() { + for (PsiType type : myStringEntries.values()) { + if (type != null && !type.isValid()) { + return false; + } + } + for (Pair entry : myOtherEntries) { + if (entry.first != null && !entry.first.isValid()) { + return false; + } + if (entry.second != null && !entry.second.isValid()) { + return false; + } + } + + return true; + } + + @Override + public boolean isEmpty() { + return myStringEntries.isEmpty() && myOtherEntries.isEmpty(); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java index 469f2f48a8fb..efda27133e61 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java @@ -17,7 +17,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.search.GlobalSearchScope; @@ -36,7 +35,6 @@ 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; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; @@ -50,7 +48,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCOMMA; @@ -191,10 +188,8 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { @Override @Nullable public PsiType fun(GrListOrMapImpl listOrMap) { - final GlobalSearchScope scope = listOrMap.getResolveScope(); if (listOrMap.isMap()) { - JavaPsiFacade facade = JavaPsiFacade.getInstance(listOrMap.getProject()); - return inferMapInitializerType(listOrMap, facade, scope); + return inferMapInitializerType(listOrMap); } PsiElement parent = listOrMap.getParent(); @@ -210,15 +205,15 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { } @Nullable - private static PsiClassType inferMapInitializerType(GrListOrMapImpl listOrMap, JavaPsiFacade facade, GlobalSearchScope scope) { - final HashMap stringEntries = new HashMap(); - final ArrayList> otherEntries = new ArrayList>(); + private static PsiClassType inferMapInitializerType(GrListOrMapImpl listOrMap) { GrNamedArgument[] namedArgs = listOrMap.getNamedArguments(); if (namedArgs.length == 0) { PsiType lType = PsiImplUtil.inferExpectedTypeForDiamond(listOrMap); if (lType instanceof PsiClassType && InheritanceUtil.isInheritor(lType, CommonClassNames.JAVA_UTIL_MAP)) { + GlobalSearchScope scope = listOrMap.getResolveScope(); + JavaPsiFacade facade = JavaPsiFacade.getInstance(listOrMap.getProject()); PsiClass hashMap = facade.findClass(GroovyCommonClassNames.JAVA_UTIL_LINKED_HASH_MAP, scope); if (hashMap == null) hashMap = facade.findClass(CommonClassNames.JAVA_UTIL_MAP, scope); if (hashMap != null) { @@ -230,22 +225,7 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { } } - for (GrNamedArgument namedArg : namedArgs) { - final GrArgumentLabel label = namedArg.getLabel(); - final GrExpression expression = namedArg.getExpression(); - if (label == null || expression == null) { - continue; - } - - final String name = label.getName(); - if (name != null) { - stringEntries.put(name, expression.getType()); - } else { - otherEntries.add(Pair.create(label.getLabelType(), expression.getType())); - } - } - - return GrMapType.create(facade, scope, stringEntries, otherEntries); + return GrMapType.createFromNamedArgs(listOrMap, namedArgs); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java index 8bfea94c3bd3..41ecb523cdc7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java @@ -873,7 +873,7 @@ public class GrClosureSignatureUtil { for (int i = 0, size = arg.args.size(); i < size; i++) { args[i] = (GrNamedArgument)arg.args.get(i); } - return new GrMapType(first, args); + return GrMapType.createFromNamedArgs(first, args); } else { for (PsiElement elem : arg.args) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index c6c3b0a12d8b..144846ea99da 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -244,7 +244,7 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx if (argumentList == null) return GroovyResolveResult.EMPTY_ARRAY; if (argumentList.getNamedArguments().length > 0 && argumentList.getExpressionArguments().length == 0) { - PsiType mapType = new GrMapType(argumentList, getNamedArguments()); + PsiType mapType = GrMapType.createFromNamedArgs(argumentList, getNamedArguments()); GroovyResolveResult[] constructorResults = PsiUtil.getConstructorCandidates(ref, classCandidate, new PsiType[]{mapType}); //one Map parameter, actually for (GroovyResolveResult result : constructorResults) { final PsiElement resolved = result.getElement(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index c4e6c8d67e4d..d3c78c896e07 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -583,8 +583,7 @@ public class TypesUtil { private static boolean checkEmptyMapAndMap(PsiType type1, PsiType type2) { if (type1 instanceof GrMapType) { - PsiType[] types = ((GrMapType)type1).getAllKeyTypes(); - if (types.length == 0 && InheritanceUtil.isInheritor(type2, JAVA_UTIL_MAP)) return true; + if (((GrMapType)type1).isEmpty() && InheritanceUtil.isInheritor(type2, JAVA_UTIL_MAP)) return true; } return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 04fb94297a63..b12eff96a746 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -308,7 +308,8 @@ public class PsiUtil { List result = new ArrayList(); if (namedArgs.length > 0) { - result.add(new GrMapType(namedArgs[0], byShape ? new GrNamedArgument[0] : namedArgs)); + GrNamedArgument context = namedArgs[0]; + result.add(GrMapType.createFromNamedArgs(context, byShape ? new GrNamedArgument[0] : namedArgs)); } for (GrExpression expression : expressions) {