blob: d4dd164e57efabb6fdb621ae058a9d8d8aff85ef [file] [log] [blame]
/*
* Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* 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 com.siyeh.ig.psiutils;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class CollectionUtils {
/**
* @noinspection StaticCollection
*/
@NonNls private static final Set<String> s_allCollectionClassesAndInterfaces;
/**
* @noinspection StaticCollection
*/
@NonNls private static final Map<String, String> s_interfaceForCollection =
new HashMap<String, String>();
static {
final Set<String> allCollectionClassesAndInterfaces = new HashSet<String>();
allCollectionClassesAndInterfaces.add("java.util.AbstractCollection");
allCollectionClassesAndInterfaces.add("java.util.AbstractList");
allCollectionClassesAndInterfaces.add("java.util.AbstractMap");
allCollectionClassesAndInterfaces.add("java.util.AbstractQueue");
allCollectionClassesAndInterfaces.add("java.util.AbstractSequentialList");
allCollectionClassesAndInterfaces.add("java.util.AbstractSet");
allCollectionClassesAndInterfaces.add("java.util.ArrayList");
allCollectionClassesAndInterfaces.add("java.util.ArrayDeque");
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_COLLECTION);
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_DICTIONARY);
allCollectionClassesAndInterfaces.add("java.util.EnumMap");
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_HASH_MAP);
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_HASH_SET);
allCollectionClassesAndInterfaces.add("java.util.Hashtable");
allCollectionClassesAndInterfaces.add("java.util.IdentityHashMap");
allCollectionClassesAndInterfaces.add("java.util.LinkedHashMap");
allCollectionClassesAndInterfaces.add("java.util.LinkedHashSet");
allCollectionClassesAndInterfaces.add("java.util.LinkedList");
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_LIST);
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_MAP);
allCollectionClassesAndInterfaces.add("java.util.PriorityQueue");
allCollectionClassesAndInterfaces.add("java.util.Queue");
allCollectionClassesAndInterfaces.add(CommonClassNames.JAVA_UTIL_SET);
allCollectionClassesAndInterfaces.add("java.util.SortedMap");
allCollectionClassesAndInterfaces.add("java.util.SortedSet");
allCollectionClassesAndInterfaces.add("java.util.Stack");
allCollectionClassesAndInterfaces.add("java.util.TreeMap");
allCollectionClassesAndInterfaces.add("java.util.TreeSet");
allCollectionClassesAndInterfaces.add("java.util.Vector");
allCollectionClassesAndInterfaces.add("java.util.WeakHashMap");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ArrayBlockingQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.BlockingDeque");
allCollectionClassesAndInterfaces.add("java.util.concurrent.BlockingQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentHashMap");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentLinkedDeque");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentLinkedQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentMap");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentNavigableMap");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentSkipListMap");
allCollectionClassesAndInterfaces.add("java.util.concurrent.ConcurrentSkipListSet");
allCollectionClassesAndInterfaces.add("java.util.concurrent.CopyOnWriteArrayList");
allCollectionClassesAndInterfaces.add("java.util.concurrent.CopyOnWriteArraySet");
allCollectionClassesAndInterfaces.add("java.util.concurrent.DelayQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.LinkedBlockingDeque");
allCollectionClassesAndInterfaces.add("java.util.concurrent.LinkedBlockingQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.LinkedTransferQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.PriorityBlockingQueue");
allCollectionClassesAndInterfaces.add("java.util.concurrent.SynchronousQueue");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.ArrayList");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Collection");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.HashMap");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.HashSet");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Hashtable");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.LinkedList");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.List");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Map");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Set");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.SortedMap");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.SortedSet");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.TreeMap");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.TreeSet");
allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Vector");
s_allCollectionClassesAndInterfaces = Collections.unmodifiableSet(allCollectionClassesAndInterfaces);
s_interfaceForCollection.put("ArrayList", "List");
s_interfaceForCollection.put("EnumMap", "Map");
s_interfaceForCollection.put("EnumSet", "Set");
s_interfaceForCollection.put("HashMap", "Map");
s_interfaceForCollection.put("HashSet", "Set");
s_interfaceForCollection.put("Hashtable", "Map");
s_interfaceForCollection.put("IdentityHashMap", "Map");
s_interfaceForCollection.put("LinkedHashMap", "Map");
s_interfaceForCollection.put("LinkedHashSet", "Set");
s_interfaceForCollection.put("LinkedList", "List");
s_interfaceForCollection.put("PriorityQueue", "Queue");
s_interfaceForCollection.put("TreeMap", "Map");
s_interfaceForCollection.put("TreeSet", "SortedSet");
s_interfaceForCollection.put("Vector", "List");
s_interfaceForCollection.put("WeakHashMap", "Map");
s_interfaceForCollection.put("java.util.ArrayList", CommonClassNames.JAVA_UTIL_LIST);
s_interfaceForCollection.put("java.util.EnumMap", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("java.util.EnumSet", CommonClassNames.JAVA_UTIL_SET);
s_interfaceForCollection.put("java.util.HashMap", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("java.util.HashSet", CommonClassNames.JAVA_UTIL_SET);
s_interfaceForCollection.put("java.util.Hashtable", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("java.util.IdentityHashMap", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("java.util.LinkedHashMap", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("java.util.LinkedHashSet", CommonClassNames.JAVA_UTIL_SET);
s_interfaceForCollection.put("java.util.LinkedList", CommonClassNames.JAVA_UTIL_LIST);
s_interfaceForCollection.put("java.util.PriorityQueue", "java.util.Queue");
s_interfaceForCollection.put("java.util.TreeMap", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("java.util.TreeSet", CommonClassNames.JAVA_UTIL_SET);
s_interfaceForCollection.put("java.util.Vector", CommonClassNames.JAVA_UTIL_LIST);
s_interfaceForCollection.put("java.util.WeakHashMap", CommonClassNames.JAVA_UTIL_MAP);
s_interfaceForCollection.put("com.sun.java.util.collections.HashSet", "com.sun.java.util.collections.Set");
s_interfaceForCollection.put("com.sun.java.util.collections.TreeSet", "com.sun.java.util.collections.Set");
s_interfaceForCollection.put("com.sun.java.util.collections.Vector", "com.sun.java.util.collections.List");
s_interfaceForCollection.put("com.sun.java.util.collections.ArrayList", "com.sun.java.util.collections.List");
s_interfaceForCollection.put("com.sun.java.util.collections.LinkedList", "com.sun.java.util.collections.List");
s_interfaceForCollection.put("com.sun.java.util.collections.TreeMap", "com.sun.java.util.collections.Map");
s_interfaceForCollection.put("com.sun.java.util.collections.HashMap", "com.sun.java.util.collections.Map");
s_interfaceForCollection.put("com.sun.java.util.collections.Hashtable", "com.sun.java.util.collections.Map");
}
private CollectionUtils() {
super();
}
public static Set<String> getAllCollectionNames() {
return s_allCollectionClassesAndInterfaces;
}
@Contract("null -> false")
public static boolean isConcreteCollectionClass(@Nullable PsiType type) {
if (!(type instanceof PsiClassType)) {
return false;
}
final PsiClassType classType = (PsiClassType)type;
final PsiClass resolved = classType.resolve();
if (resolved == null) {
return false;
}
return isConcreteCollectionClass(resolved);
}
@Contract("null -> false")
public static boolean isConcreteCollectionClass(PsiClass aClass) {
if (aClass == null || aClass.isEnum() || aClass.isInterface() || aClass.isAnnotationType() ||
aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
return false;
}
if (!InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_COLLECTION) &&
!InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_MAP)) {
return false;
}
@NonNls final String name = aClass.getQualifiedName();
return name != null && name.startsWith("java.util.");
}
public static boolean isCollectionClassOrInterface(@Nullable PsiType type) {
if (!(type instanceof PsiClassType)) {
return false;
}
final PsiClassType classType = (PsiClassType)type;
final PsiClass resolved = classType.resolve();
if (resolved == null) {
return false;
}
return isCollectionClassOrInterface(resolved);
}
public static boolean isCollectionClassOrInterface(PsiClass aClass) {
return isCollectionClassOrInterface(aClass, new HashSet<PsiClass>());
}
/**
* alreadyChecked set to avoid infinite loop in constructs like:
* class C extends C {}
*/
private static boolean isCollectionClassOrInterface(
PsiClass aClass, Set<PsiClass> visitedClasses) {
if (!visitedClasses.add(aClass)) {
return false;
}
final String className = aClass.getQualifiedName();
if (s_allCollectionClassesAndInterfaces.contains(className)) {
return true;
}
final PsiClass[] supers = aClass.getSupers();
for (PsiClass aSuper : supers) {
if (isCollectionClassOrInterface(aSuper, visitedClasses)) {
return true;
}
}
return false;
}
public static boolean isWeakCollectionClass(@Nullable PsiType type) {
if (!(type instanceof PsiClassType)) {
return false;
}
final String typeText = type.getCanonicalText();
return "java.util.WeakHashMap".equals(typeText);
}
public static boolean isConstantEmptyArray(@NotNull PsiField field) {
if (!field.hasModifierProperty(PsiModifier.STATIC) ||
!field.hasModifierProperty(PsiModifier.FINAL)) {
return false;
}
return isEmptyArray(field);
}
public static boolean isEmptyArray(PsiField field) {
final PsiExpression initializer = field.getInitializer();
if (initializer instanceof PsiArrayInitializerExpression) {
final PsiArrayInitializerExpression arrayInitializerExpression =
(PsiArrayInitializerExpression)initializer;
final PsiExpression[] initializers =
arrayInitializerExpression.getInitializers();
return initializers.length == 0;
}
return ExpressionUtils.isZeroLengthArrayConstruction(initializer);
}
public static boolean isArrayOrCollectionField(@NotNull PsiField field) {
final PsiType type = field.getType();
if (isCollectionClassOrInterface(type)) {
return true;
}
if (!(type instanceof PsiArrayType)) {
return false;
}
// constant empty arrays are ignored.
return !isConstantEmptyArray(field);
}
public static String getInterfaceForClass(String name) {
final int parameterStart = name.indexOf((int)'<');
final String baseName;
if (parameterStart >= 0) {
baseName = name.substring(0, parameterStart).trim();
}
else {
baseName = name;
}
return s_interfaceForCollection.get(baseName);
}
}