package org.fandev.lang.fan.psi.impl.statements.typedefs; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.psi.impl.InheritanceImplUtil; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.tree.IElementType; import com.intellij.util.IncorrectOperationException; import org.fandev.icons.Icons; import org.fandev.lang.fan.FanElementTypes; import org.fandev.lang.fan.psi.api.statements.typeDefs.FanClassDefinition; import org.fandev.lang.fan.psi.api.statements.typeDefs.members.FanConstructor; import org.fandev.lang.fan.psi.api.statements.typeDefs.members.FanMethod; import org.fandev.lang.fan.psi.api.statements.typeDefs.members.FanField; import org.fandev.lang.fan.psi.stubs.FanTypeDefinitionStub; import org.fandev.lang.fan.psi.impl.PsiImplUtil; import org.fandev.lang.fan.resolve.CollectClassMembersUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; /** * @author Dror Bereznitsky * @date Jan 7, 2009 3:48:09 PM */ public class FanClassDefinitionImpl extends FanTypeDefinitionImpl implements FanClassDefinition { private final static Logger logger = Logger.getInstance("org.fandev.lang.fan.psi.impl.statements.typedefs.FanClassDefinitionImpl"); public FanClassDefinitionImpl(final FanTypeDefinitionStub stubElement) { super(stubElement, FanElementTypes.CLASS_DEFINITION); } public FanClassDefinitionImpl(final ASTNode astNode) { super(astNode); } protected Icon getIconInner() { if (hasModifierProperty(PsiModifier.ABSTRACT)) { return Icons.ABSTRACT_CLASS; } else { return Icons.CLASS; } } public String toString() { return "Class definition"; } public PsiElement setName(@NonNls final String name) throws IncorrectOperationException { // TODO rename return this; } public boolean isInterface() { return false; } public boolean isAnnotationType() { return false; } public boolean isEnum() { return false; } public PsiClass[] getInterfaces() { return PsiClass.EMPTY_ARRAY; } @Override public void subtreeChanged() { this.fanSlots = null; this.fanFields = null; this.fanMethods = null; super.subtreeChanged(); } @NotNull public PsiField[] getFields() { return getFanFields(); } @NotNull public PsiMethod[] getMethods() { return getFanMethods(); } @NotNull public PsiMethod[] getConstructors() { final Set<PsiMethod> constructors = new HashSet<PsiMethod>(); for (final FanMethod method : getFanMethods()) { if (method instanceof FanConstructor) { constructors.add(method); } } return constructors.toArray(new PsiMethod[0]); } @NotNull public PsiClass[] getInnerClasses() { return PsiClass.EMPTY_ARRAY; } @NotNull public PsiClassInitializer[] getInitializers() { return PsiClassInitializer.EMPTY_ARRAY; } @NotNull public PsiField[] getAllFields() { return PsiField.EMPTY_ARRAY; } @NotNull public PsiMethod[] getAllMethods() { final List<PsiMethod> allMethods = new ArrayList<PsiMethod>(); getAllMethodsInner(this, allMethods, new HashSet<PsiClass>()); return allMethods.toArray(new PsiMethod[0]); } private static void getAllMethodsInner(final PsiClass clazz, final List<PsiMethod> allMethods, final HashSet<PsiClass> visited) { if (visited.contains(clazz)) { return; } visited.add(clazz); allMethods.addAll(Arrays.asList(clazz.getMethods())); /*final PsiField[] fields = clazz.getFields(); for (final PsiField field : fields) { if (field instanceof FanField) { final FanField fanField = (FanField) field; if (fanField.isProperty()) { final PsiMethod[] getters = fanField.getGetters(); if (getters.length > 0) allMethods.addAll(Arrays.asList(getters)); final PsiMethod setter = fanField.getSetter(); if (setter != null) allMethods.add(setter); } } }*/ final PsiClass[] supers = clazz.getSupers(); for (final PsiClass aSuper : supers) { getAllMethodsInner(aSuper, allMethods, visited); } } @NotNull public PsiClass[] getAllInnerClasses() { return PsiClass.EMPTY_ARRAY; } @Nullable public PsiField findFieldByName(final String name, final boolean checkBases) { if (!checkBases) { for (final FanField field : getFanFields()) { if (name.equals(field.getName())) { return field; } } return null; } final Map<String, CandidateInfo> fieldsMap = CollectClassMembersUtil.getAllFields(this); final CandidateInfo info = fieldsMap.get(name); return info == null ? null : (PsiField) info.getElement(); } @Nullable public PsiMethod findMethodBySignature(final PsiMethod patternMethod, final boolean checkBases) { final MethodSignature patternSignature = patternMethod.getSignature(PsiSubstitutor.EMPTY); for (final PsiMethod method : findMethodsByName(patternMethod.getName(), checkBases, false)) { final PsiClass clazz = method.getContainingClass(); final PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(clazz, this, PsiSubstitutor.EMPTY); assert superSubstitutor != null; final MethodSignature signature = method.getSignature(superSubstitutor); if (signature.equals(patternSignature)) { return method; } } return null; } @NotNull public PsiMethod[] findMethodsBySignature(final PsiMethod patternMethod, final boolean checkBases) { return findMethodsBySignature(patternMethod, checkBases, true); } private PsiMethod[] findMethodsBySignature(final PsiMethod patternMethod, final boolean checkBases, final boolean includeSynthetic) { final ArrayList<PsiMethod> result = new ArrayList<PsiMethod>(); final MethodSignature patternSignature = patternMethod.getSignature(PsiSubstitutor.EMPTY); for (final PsiMethod method : findMethodsByName(patternMethod.getName(), checkBases, includeSynthetic)) { final PsiClass clazz = method.getContainingClass(); if (clazz == null) { continue; } final PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(clazz, this, PsiSubstitutor.EMPTY); assert superSubstitutor != null; final MethodSignature signature = method.getSignature(superSubstitutor); if (signature.equals(patternSignature)) //noinspection unchecked { result.add(method); } } return result.toArray(new PsiMethod[0]); } @NotNull public PsiMethod[] findMethodsByName(@NonNls final String name, final boolean checkBases) { return findMethodsByName(name, checkBases, true); } private PsiMethod[] findMethodsByName(final String name, final boolean checkBases, final boolean includeSyntheticAccessors) { if (!checkBases) { final List<PsiMethod> result = new ArrayList<PsiMethod>(); for (final PsiMethod method : includeSyntheticAccessors ? getMethods() : getFanMethods()) { if (name.equals(method.getName())) { result.add(method); } } return result.toArray(new PsiMethod[0]); } final Map<String, List<CandidateInfo>> methodsMap = CollectClassMembersUtil.getAllMethods(this, includeSyntheticAccessors); return PsiImplUtil.mapToMethods(methodsMap.get(name)); } @NotNull public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(final String name, final boolean checkBases) { final ArrayList<Pair<PsiMethod, PsiSubstitutor>> result = new ArrayList<Pair<PsiMethod, PsiSubstitutor>>(); if (!checkBases) { final PsiMethod[] methods = findMethodsByName(name, false); for (final PsiMethod method : methods) { result.add(new Pair<PsiMethod, PsiSubstitutor>(method, PsiSubstitutor.EMPTY)); } } else { final Map<String, List<CandidateInfo>> map = CollectClassMembersUtil.getAllMethods(this, true); final List<CandidateInfo> candidateInfos = map.get(name); if (candidateInfos != null) { for (final CandidateInfo info : candidateInfos) { final PsiElement element = info.getElement(); result.add(new Pair<PsiMethod, PsiSubstitutor>((PsiMethod) element, info.getSubstitutor())); } } } return result; } @NotNull public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() { final Map<String, List<CandidateInfo>> allMethodsMap = CollectClassMembersUtil.getAllMethods(this, true); final List<Pair<PsiMethod, PsiSubstitutor>> result = new ArrayList<Pair<PsiMethod, PsiSubstitutor>>(); for (final List<CandidateInfo> infos : allMethodsMap.values()) { for (final CandidateInfo info : infos) { result.add(new Pair<PsiMethod, PsiSubstitutor>((PsiMethod) info.getElement(), info.getSubstitutor())); } } return result; } public PsiClass findInnerClassByName(@NonNls final String name, final boolean checkBases) { return null; } public PsiJavaToken getLBrace() { return null; } public PsiJavaToken getRBrace() { return null; } public PsiElement getScope() { return getParent(); } public boolean isInheritor(@NotNull final PsiClass baseClass, final boolean checkDeep) { return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep); } public boolean isInheritorDeep(final PsiClass baseClass, @Nullable final PsiClass classToByPass) { return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass); } public PsiClass getContainingClass() { return null; } @NotNull public Collection<HierarchicalMethodSignature> getVisibleSignatures() { return Collections.emptyList(); } public PsiDocComment getDocComment() { return null; } public boolean isDeprecated() { return false; } public boolean hasTypeParameters() { return getTypeParameters().length > 0; } public PsiTypeParameterList getTypeParameterList() { return findChildByClass(PsiTypeParameterList.class); } @NotNull public PsiTypeParameter[] getTypeParameters() { final PsiTypeParameterList list = getTypeParameterList(); if (list != null) { return list.getTypeParameters(); } return PsiTypeParameter.EMPTY_ARRAY; } protected IElementType getBodyElementType() { return FanElementTypes.CLASS_BODY; } }