mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-123337 lazy type inference for map literals
This commit is contained in:
+12
-5
@@ -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<PsiSubstitutor> mySubstitutor = new NotNullLazyValue<PsiSubstitutor>() {
|
||||
@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
|
||||
|
||||
@@ -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<String, PsiType> myStringEntries;
|
||||
private final List<Pair<PsiType, PsiType>> myOtherEntries;
|
||||
public abstract class GrMapType extends GrLiteralClassType {
|
||||
private final String myJavaClassName;
|
||||
|
||||
private GrMapType(JavaPsiFacade facade,
|
||||
GlobalSearchScope scope,
|
||||
Map<String, PsiType> stringEntries,
|
||||
List<Pair<PsiType, PsiType>> otherEntries,
|
||||
LanguageLevel languageLevel) {
|
||||
super(languageLevel, scope, facade);
|
||||
myStringEntries = stringEntries;
|
||||
myOtherEntries = otherEntries;
|
||||
private final AtomicNotNullLazyValue<PsiType[]> myParameters = new AtomicNotNullLazyValue<PsiType[]>() {
|
||||
@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<String, PsiType>();
|
||||
myOtherEntries = new ArrayList<Pair<PsiType, PsiType>>();
|
||||
|
||||
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<PsiType, PsiType>(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<String> getStringKeys() {
|
||||
return myStringEntries.keySet();
|
||||
}
|
||||
@NotNull
|
||||
public abstract Set<String> getStringKeys();
|
||||
|
||||
public PsiType[] getAllKeyTypes() {
|
||||
Set<PsiType> result = new HashSet<PsiType>();
|
||||
if (!myStringEntries.isEmpty()) {
|
||||
result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope()));
|
||||
}
|
||||
for (Pair<PsiType, PsiType> entry : myOtherEntries) {
|
||||
result.add(entry.first);
|
||||
}
|
||||
result.remove(null);
|
||||
return result.toArray(createArray(result.size()));
|
||||
}
|
||||
public abstract boolean isEmpty();
|
||||
|
||||
public PsiType[] getAllValueTypes() {
|
||||
Set<PsiType> result = new HashSet<PsiType>();
|
||||
result.addAll(myStringEntries.values());
|
||||
for (Pair<PsiType, PsiType> 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<Pair<PsiType, PsiType>> getOtherEntries();
|
||||
|
||||
@NotNull
|
||||
protected abstract Map<String, PsiType> 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<String> stringKeys = getStringKeys();
|
||||
List<Pair<PsiType, PsiType>> 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<String> components = new ArrayList<String>();
|
||||
for (String s : myStringEntries.keySet()) {
|
||||
components.add("'" + s + "':" + getInternalCanonicalText(myStringEntries.get(s)));
|
||||
for (String s : stringKeys) {
|
||||
components.add("'" + s + "':" + getInternalCanonicalText(getTypeByStringKey(s)));
|
||||
}
|
||||
for (Pair<PsiType, PsiType> entry : myOtherEntries) {
|
||||
for (Pair<PsiType, PsiType> 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<PsiType, PsiType> 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<String, PsiType> strings = new HashMap<String, PsiType>();
|
||||
strings.putAll(l.myStringEntries);
|
||||
strings.putAll(r.myStringEntries);
|
||||
strings.putAll(l.getStringEntries());
|
||||
strings.putAll(r.getStringEntries());
|
||||
|
||||
List<Pair<PsiType, PsiType>> other = new ArrayList<Pair<PsiType, PsiType>>();
|
||||
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<String, PsiType> stringEntries,
|
||||
List<Pair<PsiType, PsiType>> 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<Pair<PsiType, PsiType>> otherEntries = Collections.emptyList();
|
||||
Map<String, PsiType> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+169
@@ -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<String, GrExpression> myStringEntries;
|
||||
private final List<Pair<GrExpression, GrExpression>> myOtherEntries;
|
||||
|
||||
private final AtomicNotNullLazyValue<List<Pair<PsiType, PsiType>>> myTypesOfOtherEntries = new AtomicNotNullLazyValue<List<Pair<PsiType, PsiType>>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<Pair<PsiType, PsiType>> compute() {
|
||||
return ContainerUtil.map(myOtherEntries, new Function<Pair<GrExpression, GrExpression>, Pair<PsiType, PsiType>>() {
|
||||
@Override
|
||||
public Pair<PsiType, PsiType> fun(Pair<GrExpression, GrExpression> pair) {
|
||||
return Pair.create(pair.first.getType(), pair.second.getType());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private final AtomicNotNullLazyValue<Map<String, PsiType>> myTypesOfStringEntries = new AtomicNotNullLazyValue<Map<String, PsiType>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, PsiType> compute() {
|
||||
HashMap<String, PsiType> result = ContainerUtil.newHashMap();
|
||||
for (Map.Entry<String, GrExpression> 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<String> getStringKeys() {
|
||||
return myStringEntries.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return myStringEntries.isEmpty() && myOtherEntries.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiType[] getAllKeyTypes() {
|
||||
Set<PsiType> result = ContainerUtil.newHashSet();
|
||||
if (!myStringEntries.isEmpty()) {
|
||||
result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope()));
|
||||
}
|
||||
for (Pair<GrExpression, GrExpression> entry : myOtherEntries) {
|
||||
result.add(entry.first.getType());
|
||||
}
|
||||
result.remove(null);
|
||||
return result.toArray(createArray(result.size()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiType[] getAllValueTypes() {
|
||||
Set<PsiType> result = ContainerUtil.newHashSet();
|
||||
for (GrExpression expression : myStringEntries.values()) {
|
||||
result.add(expression.getType());
|
||||
}
|
||||
for (Pair<GrExpression, GrExpression> entry : myOtherEntries) {
|
||||
result.add(entry.second.getType());
|
||||
}
|
||||
result.remove(null);
|
||||
return result.toArray(createArray(result.size()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<Pair<PsiType, PsiType>> getOtherEntries() {
|
||||
return myTypesOfOtherEntries.getValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, PsiType> getStringEntries() {
|
||||
return myTypesOfStringEntries.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
for (GrExpression expression : myStringEntries.values()) {
|
||||
if (!expression.isValid()) return false;
|
||||
}
|
||||
|
||||
for (Pair<GrExpression, GrExpression> entry : myOtherEntries) {
|
||||
if (!entry.first.isValid()) return false;
|
||||
if (!entry.second.isValid()) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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<String, PsiType> myStringEntries;
|
||||
private final List<Pair<PsiType, PsiType>> myOtherEntries;
|
||||
|
||||
GrMapTypeImpl(JavaPsiFacade facade,
|
||||
GlobalSearchScope scope,
|
||||
Map<String, PsiType> stringEntries,
|
||||
List<Pair<PsiType, PsiType>> otherEntries,
|
||||
LanguageLevel languageLevel) {
|
||||
super(facade, scope, languageLevel);
|
||||
myStringEntries = stringEntries;
|
||||
myOtherEntries = otherEntries;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiType getTypeByStringKey(String key) {
|
||||
return myStringEntries.get(key);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<String> getStringKeys() {
|
||||
return myStringEntries.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected PsiType[] getAllKeyTypes() {
|
||||
Set<PsiType> result = new HashSet<PsiType>();
|
||||
if (!myStringEntries.isEmpty()) {
|
||||
result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope()));
|
||||
}
|
||||
for (Pair<PsiType, PsiType> entry : myOtherEntries) {
|
||||
result.add(entry.first);
|
||||
}
|
||||
result.remove(null);
|
||||
return result.toArray(createArray(result.size()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected PsiType[] getAllValueTypes() {
|
||||
Set<PsiType> result = new HashSet<PsiType>();
|
||||
result.addAll(myStringEntries.values());
|
||||
for (Pair<PsiType, PsiType> entry : myOtherEntries) {
|
||||
result.add(entry.second);
|
||||
}
|
||||
result.remove(null);
|
||||
return result.toArray(createArray(result.size()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<Pair<PsiType, PsiType>> getOtherEntries() {
|
||||
return myOtherEntries;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, PsiType> getStringEntries() {
|
||||
return myStringEntries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
for (PsiType type : myStringEntries.values()) {
|
||||
if (type != null && !type.isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (Pair<PsiType, PsiType> 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();
|
||||
}
|
||||
}
|
||||
+5
-25
@@ -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<String, PsiType> stringEntries = new HashMap<String, PsiType>();
|
||||
final ArrayList<Pair<PsiType, PsiType>> otherEntries = new ArrayList<Pair<PsiType, PsiType>>();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+1
-2
@@ -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;
|
||||
|
||||
@@ -308,7 +308,8 @@ public class PsiUtil {
|
||||
List<PsiType> result = new ArrayList<PsiType>();
|
||||
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user