package de.plushnikov.intellij.plugin.util;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.impl.source.PsiExtensibleClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* @author Plushnikov Michail
*/
public class PsiClassUtil {
/**
* Workaround to get all of original Methods of the psiClass, without calling PsiAugmentProvider infinitely
*
* @param psiClass psiClass to collect all of methods from
* @return all intern methods of the class
*/
@NotNull
public static Collection<PsiMethod> collectClassMethodsIntern(@NotNull PsiClass psiClass) {
if (psiClass instanceof PsiExtensibleClass) {
return new ArrayList<PsiMethod>(((PsiExtensibleClass) psiClass).getOwnMethods());
} else {
return filterPsiElements(psiClass, PsiMethod.class);
}
}
/**
* Workaround to get all of original Fields of the psiClass, without calling PsiAugmentProvider infinitely
*
* @param psiClass psiClass to collect all of fields from
* @return all intern fields of the class
*/
@NotNull
public static Collection<PsiField> collectClassFieldsIntern(@NotNull PsiClass psiClass) {
if (psiClass instanceof PsiExtensibleClass) {
return ((PsiExtensibleClass) psiClass).getOwnFields();
} else {
return filterPsiElements(psiClass, PsiField.class);
}
}
/**
* Workaround to get all of original inner classes of the psiClass, without calling PsiAugmentProvider infinitely
*
* @param psiClass psiClass to collect all inner classes from
* @return all inner classes of the class
*/
@NotNull
public static Collection<PsiClass> collectInnerClassesIntern(@NotNull PsiClass psiClass) {
if (psiClass instanceof PsiExtensibleClass) {
return ((PsiExtensibleClass) psiClass).getOwnInnerClasses();
} else {
return filterPsiElements(psiClass, PsiClass.class);
}
}
private static <T extends PsiElement> Collection<T> filterPsiElements(@NotNull PsiClass psiClass, @NotNull Class<T> disiredClass) {
Collection<T> result = new ArrayList<T>();
for (PsiElement psiElement : psiClass.getChildren()) {
if (disiredClass.isAssignableFrom(psiElement.getClass())) {
result.add((T) psiElement);
}
}
return result;
}
@NotNull
public static Collection<PsiMethod> collectClassConstructorIntern(@NotNull PsiClass psiClass) {
final Collection<PsiMethod> psiMethods = collectClassMethodsIntern(psiClass);
Collection<PsiMethod> classConstructors = new ArrayList<PsiMethod>(3);
for (PsiMethod psiMethod : psiMethods) {
if (psiMethod.isConstructor()) {
classConstructors.add(psiMethod);
}
}
return classConstructors;
}
@NotNull
public static Collection<PsiMethod> collectClassStaticMethodsIntern(@NotNull PsiClass psiClass) {
final Collection<PsiMethod> psiMethods = collectClassMethodsIntern(psiClass);
Collection<PsiMethod> staticMethods = new ArrayList<PsiMethod>(psiMethods.size());
for (PsiMethod psiMethod : psiMethods) {
if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
staticMethods.add(psiMethod);
}
}
return staticMethods;
}
public static boolean hasSuperClass(@NotNull final PsiClass psiClass) {
final PsiClass superClass = psiClass.getSuperClass();
return (null != superClass && !CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())
|| !superTypesIsEmptyOrObjectOnly(psiClass));
}
private static boolean superTypesIsEmptyOrObjectOnly(@NotNull final PsiClass psiClass) {
// It returns abstract classes, but also Object.
final PsiClassType[] superTypes = psiClass.getSuperTypes();
return superTypes.length == 0 || superTypes.length > 1 || CommonClassNames.JAVA_LANG_OBJECT.equals(superTypes[0].getCanonicalText());
}
/**
* Creates a PsiType for a PsiClass enriched with generic substitution information if available
*/
@NotNull
public static PsiType getTypeWithGenerics(@NotNull PsiClass psiClass) {
return getTypeWithGenerics(psiClass, psiClass.getTypeParameters());
}
/**
* Creates a PsiType for a PsiClass enriched with generic substitution information if available
*/
@NotNull
private static PsiType getTypeWithGenerics(@NotNull PsiClass psiClass, @NotNull PsiTypeParameter... classTypeParameters) {
PsiType result;
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject());
if (classTypeParameters.length > 0) {
Map<PsiTypeParameter, PsiType> substitutionMap = new HashMap<PsiTypeParameter, PsiType>();
for (PsiTypeParameter typeParameter : classTypeParameters) {
substitutionMap.put(typeParameter, factory.createType(typeParameter));
}
result = factory.createType(psiClass, factory.createSubstitutor(substitutionMap));
} else {
result = factory.createType(psiClass);
}
return result;
}
/**
* Workaround to get inner class of the psiClass, without calling PsiAugmentProvider infinitely
*
* @param psiClass psiClass to search for inner class
* @return inner class if found
*/
@Nullable
public static PsiClass getInnerClassInternByName(@NotNull PsiClass psiClass, @NotNull String className) {
Collection<PsiClass> innerClasses = collectInnerClassesIntern(psiClass);
for (PsiClass innerClass : innerClasses) {
if (className.equals(innerClass.getName())) {
return innerClass;
}
}
return null;
}
public static Collection<String> getNames(Collection<? extends PsiMember> psiMembers) {
Collection<String> result = new HashSet<String>();
for (PsiMember psiMember : psiMembers) {
result.add(psiMember.getName());
}
return result;
}
}