package org.jetbrains.plugins.clojure.psi.impl.synthetic; import org.jetbrains.plugins.clojure.psi.api.synthetic.ClSyntheticClass; import org.jetbrains.plugins.clojure.psi.api.ClojureFile; import org.jetbrains.plugins.clojure.psi.api.ClList; import org.jetbrains.plugins.clojure.psi.api.ClVector; import org.jetbrains.plugins.clojure.psi.api.symbols.ClSymbol; import org.jetbrains.plugins.clojure.psi.util.ClojureKeywords; import org.jetbrains.plugins.clojure.psi.util.ClojurePsiUtil; import org.jetbrains.plugins.clojure.psi.impl.ClKeywordImpl; import org.jetbrains.plugins.clojure.file.ClojureFileType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import com.intellij.psi.impl.light.LightElement; import com.intellij.psi.impl.InheritanceImplUtil; import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.util.IncorrectOperationException; import com.intellij.openapi.util.Pair; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.navigation.ItemPresentation; import javax.swing.*; import java.util.List; import java.util.Collection; import java.util.ArrayList; import java.util.Arrays; /** * @author ilyas * <p/> * Class to represent bytecode-compiled clojure files */ public class ClSyntheticClassImpl extends LightElement implements ClSyntheticClass { @Override public PsiElement getNavigationElement() { return myFile.getNamespaceElement(); } @NotNull private final ClojureFile myFile; private String myQualifiedName; private String myName; @Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { for (PsiMethod method : getAllMethods()) { if (!processor.execute(method, state)) return false; } for (PsiField field : getAllFields()) { if (!processor.execute(field, state)) return false; } return super.processDeclarations(processor, state, lastParent, place); } public ClSyntheticClassImpl(@NotNull ClojureFile file) { super(file.getManager(), ClojureFileType.CLOJURE_LANGUAGE); myFile = file; assert myFile.isClassDefiningFile(); assert myFile.getNamespaceElement() != null; cachesNames(); } private void cachesNames() { String name = myFile.getName(); int i = name.indexOf('.'); myName = i > 0 ? name.substring(0, i) : name; String packageName = myFile.getPackageName(); myQualifiedName = packageName.length() > 0 ? packageName + "." + myName : myName; } public String getText() { return "class " + myName + " {}"; } @Override public String toString() { return "ClojureSyntheticClass[" + getQualifiedName() + "]"; } public void accept(@NotNull PsiElementVisitor psiElementVisitor) { } @Override public ItemPresentation getPresentation() { return new ItemPresentation() { public String getPresentableText() { return getName(); } public String getLocationString() { String pn = myFile.getPackageName(); return "(" + (pn.equals("") ? "<default package>" : pn) + ") in " + myFile.getName(); } public TextAttributesKey getTextAttributesKey() { return null; } public Icon getIcon(boolean open) { return myFile.getIcon(0); } }; } public PsiElement copy() { return new ClSyntheticClassImpl(myFile); } public String getQualifiedName() { return myQualifiedName; } public boolean isInterface() { return false; } public boolean isAnnotationType() { return false; } public boolean isEnum() { return false; } public PsiReferenceList getExtendsList() { //todo implement me! return null; } public PsiReferenceList getImplementsList() { return null; } @NotNull public PsiClassType[] getExtendsListTypes() { final PsiClass superClass = getSuperClass(); final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); if (superClass != null && superClass.getQualifiedName() != null) { return new PsiClassType[]{factory.createTypeByFQClassName(superClass.getQualifiedName(), scope)}; } return PsiClassType.EMPTY_ARRAY; } @Override public void delete() throws IncorrectOperationException { myFile.delete(); } @NotNull public PsiClassType[] getImplementsListTypes() { return new PsiClassType[0]; } public PsiClass getSuperClass() { final ClList ns = getNsElement(); final ClKeywordImpl key = ClojurePsiUtil.findNamespaceKeyByName(ns, ClojureKeywords.EXTENDS); if (key != null) { final PsiElement next = ClojurePsiUtil.getNextNonWhiteSpace(key); if (next instanceof ClSymbol) { ClSymbol symbol = (ClSymbol) next; final PsiClass psiClass = JavaPsiFacade.getInstance(getProject()).findClass(symbol.getText(), GlobalSearchScope.allScope(getProject())); return psiClass; } } return null; } @NotNull private ClList getNsElement() { return myFile.getNamespaceElement(); } public PsiClass[] getInterfaces() { final ClList ns = getNsElement(); final ClKeywordImpl key = ClojurePsiUtil.findNamespaceKeyByName(ns, ClojureKeywords.IMPLEMENTS); final ArrayList<PsiClass> classes = new ArrayList<PsiClass>(); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); if (key != null) { final PsiElement next = ClojurePsiUtil.getNextNonWhiteSpace(key); if (next instanceof ClVector) { ClVector vector = (ClVector) next; for (PsiElement element : vector.getChildren()) { if (element instanceof ClSymbol) { ClSymbol symbol = (ClSymbol) element; final PsiClass clazz = facade.findClass(symbol.getText(), scope); if (clazz != null) classes.add(clazz); } } return classes.toArray(PsiClass.EMPTY_ARRAY); } } return new PsiClass[0]; } @NotNull public PsiClass[] getSupers() { final ArrayList<PsiClass> list = new ArrayList<PsiClass>(); final PsiClass psiClass = getSuperClass(); if (psiClass != null) { list.add(psiClass); } list.addAll(Arrays.asList(getInterfaces())); return list.toArray(PsiClass.EMPTY_ARRAY); } @NotNull public PsiClassType[] getSuperTypes() { final ArrayList<PsiClassType> types = new ArrayList<PsiClassType>(); final PsiClass superClass = getSuperClass(); final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); if (superClass != null && superClass.getQualifiedName() != null) { types.add(factory.createTypeByFQClassName(superClass.getQualifiedName(), scope)); } for (PsiClass clazz : getInterfaces()) { final String qName = clazz.getQualifiedName(); if (qName != null) { types.add(factory.createTypeByFQClassName(qName, scope)); } } return types.toArray(PsiClassType.EMPTY_ARRAY); } @NotNull public PsiField[] getFields() { final ArrayList<PsiField> list = new ArrayList<PsiField>(); final PsiClass psiClass = getSuperClass(); if (psiClass != null) { list.addAll(Arrays.asList(psiClass.getAllFields())); } for (PsiClass aClass : getInterfaces()) { list.addAll(Arrays.asList(aClass.getFields())); } return list.toArray(new PsiField[list.size()]); } @NotNull public PsiMethod[] getMethods() { final ArrayList<PsiMethod> methods = new ArrayList<PsiMethod>(); final PsiClass psiClass = getSuperClass(); if (psiClass != null) { methods.addAll(Arrays.asList(psiClass.getAllMethods())); } for (PsiClass iface : getInterfaces()) { methods.addAll(Arrays.asList(iface.getMethods())); } return methods.toArray(new PsiMethod[methods.size()]); } @NotNull public PsiMethod[] getConstructors() { return new PsiMethod[0]; } @NotNull public PsiClass[] getInnerClasses() { return new PsiClass[0]; } @NotNull public PsiClassInitializer[] getInitializers() { return new PsiClassInitializer[0]; } @NotNull public PsiField[] getAllFields() { return getFields(); } @NotNull public PsiMethod[] getAllMethods() { return getMethods(); } @NotNull public PsiClass[] getAllInnerClasses() { return new PsiClass[0]; } public PsiField findFieldByName(@NonNls String s, boolean b) { return null; } public PsiMethod findMethodBySignature(PsiMethod psiMethod, boolean b) { return null; } @NotNull public PsiMethod[] findMethodsBySignature(PsiMethod psiMethod, boolean b) { return new PsiMethod[0]; } @NotNull public PsiMethod[] findMethodsByName(@NonNls String s, boolean b) { return new PsiMethod[0]; } @NotNull public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(@NonNls String s, boolean b) { return new ArrayList<Pair<PsiMethod, PsiSubstitutor>>(); } @NotNull public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() { return new ArrayList<Pair<PsiMethod, PsiSubstitutor>>(); } public PsiClass findInnerClassByName(@NonNls String s, boolean b) { return null; } @Override public PsiFile getContainingFile() { return myFile; } public PsiJavaToken getLBrace() { return null; } public PsiJavaToken getRBrace() { return null; } public PsiIdentifier getNameIdentifier() { return null; } public PsiElement getScope() { return null; } public boolean isInheritor(@NotNull PsiClass psiClass, boolean b) { return InheritanceImplUtil.isInheritor(this, psiClass, b); } public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) { return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass); } public PsiClass getContainingClass() { return null; } @NotNull public Collection<HierarchicalMethodSignature> getVisibleSignatures() { return new ArrayList<HierarchicalMethodSignature>(); } public String getName() { return myName; } public PsiElement setName(@NonNls String s) throws IncorrectOperationException { return myFile.setClassName(s); } public PsiModifierList getModifierList() { //todo implement me! return null; } public boolean hasModifierProperty(String s) { //todo implement me! return false; } public PsiDocComment getDocComment() { return null; } public boolean isDeprecated() { return false; } public boolean hasTypeParameters() { return false; } public PsiTypeParameterList getTypeParameterList() { return null; } @NotNull public PsiTypeParameter[] getTypeParameters() { return new PsiTypeParameter[0]; } @Nullable public Icon getIcon(int flags) { return myFile.getIcon(flags); } }