/* * Copyright 2013 Guidewire Software, Inc. */ package gw.plugin.ij.lang.psi.custom; import com.google.common.collect.Maps; import com.intellij.ide.util.PsiNavigationSupport; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.HierarchicalMethodSignature; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClassInitializer; import com.intellij.psi.PsiClassType; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiIdentifier; import com.intellij.psi.PsiInvalidElementAccessException; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiReference; import com.intellij.psi.PsiReferenceList; import com.intellij.psi.PsiSubstitutor; import com.intellij.psi.PsiTypeParameter; import com.intellij.psi.PsiTypeParameterList; import com.intellij.psi.ResolveState; import com.intellij.psi.impl.PsiClassImplUtil; import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; import gw.fs.IFile; import gw.lang.reflect.IFileBasedType; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.IParameterInfo; import gw.lang.reflect.IType; import gw.plugin.ij.filesystem.IDEAFile; import gw.plugin.ij.lang.GosuLanguage; import gw.plugin.ij.lang.psi.impl.CustomPsiClassCache; import gw.plugin.ij.util.FileUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; public class CustomGosuClass extends UserDataHolderBase implements PsiClass { @Nullable private final PsiFile file; private final Map<String, PsiField> fields = Maps.newHashMap(); private final Map<String, PsiMethod> methods = Maps.newHashMap(); private final String relativeName; private final String namespace; private final IType superType; private final IFile[] sourceFiles; private final boolean valid; public CustomGosuClass(@NotNull PsiFile file) { this(file, file.getVirtualFile().getNameWithoutExtension(), file.getVirtualFile().getParent().getName()); } public CustomGosuClass(@NotNull PsiFile file, String relativeName, String namespace) { this.file = file; this.relativeName = relativeName; this.namespace = namespace; this.superType = null; this.sourceFiles = null; this.valid = isClassValid(); } public CustomGosuClass(@NotNull IFileBasedType type) { final VirtualFile virtualFile = FileUtil.getTypeResourceFiles(type).get(0); final PsiManager manager = PsiManagerImpl.getInstance((Project) type.getTypeLoader().getModule().getExecutionEnvironment().getProject().getNativeProject()); this.file = manager.findFile(virtualFile); final Module module = virtualFile.getUserData(ModuleUtil.KEY_MODULE); if (module != null) { this.file.putUserData(ModuleUtil.KEY_MODULE, module); } this.relativeName = type.getRelativeName(); this.namespace = type.getNamespace(); this.superType = type.getSupertype(); this.sourceFiles = type.getSourceFiles(); this.valid = isClassValid(); } private boolean isClassValid() { if ("".equals(namespace) && "displaykey".equals(getName())) { return false; } return true; } @Override public String getQualifiedName() { if (namespace == null || namespace.isEmpty()) { return relativeName; } return namespace + "." + relativeName; } public String getNamespace() { return namespace; } @Override public String getName() { return relativeName; } @Override public boolean isInterface() { return false; } @Override public boolean isEnum() { return false; } @Override public boolean isAnnotationType() { return false; } @NotNull @Override public PsiMethod[] getConstructors() { return PsiMethod.EMPTY_ARRAY; } @NotNull @Override public PsiMethod[] getMethods() { return PsiMethod.EMPTY_ARRAY; } @NotNull @Override public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) { return PsiMethod.EMPTY_ARRAY; } @Override public boolean isValid() { return valid; } @NotNull @Override public Project getProject() throws PsiInvalidElementAccessException { return file.getProject(); } @Override public boolean isWritable() { return false; } @NotNull @Override public PsiManager getManager() { return PsiManager.getInstance(getProject()); } @Override public boolean isPhysical() { return true; } @Override public PsiClass getContainingClass() { return null; } @Nullable @Override public PsiFile getContainingFile() throws PsiInvalidElementAccessException { return file; } @Override public boolean hasModifierProperty(@PsiModifier.ModifierConstant @NonNls @NotNull String name) { return false; } @Override public PsiField findFieldByName(@NonNls String name, boolean checkBases) { return null; } ////// @Override public PsiReferenceList getExtendsList() { return null; } @Override public PsiReferenceList getImplementsList() { return null; } @NotNull @Override public PsiClassType[] getExtendsListTypes() { return PsiClassType.EMPTY_ARRAY; } @NotNull @Override public PsiClassType[] getImplementsListTypes() { return PsiClassType.EMPTY_ARRAY; } @Override public PsiClass getSuperClass() { return superType != null ? CustomPsiClassCache.instance().getPsiClass(superType) : null; } @NotNull @Override public PsiClass[] getInterfaces() { return PsiClass.EMPTY_ARRAY; } @NotNull @Override public PsiClass[] getSupers() { final PsiClass klass = getSuperClass(); return klass != null ? new PsiClass[]{klass} : PsiClass.EMPTY_ARRAY; } @NotNull @Override public PsiClassType[] getSuperTypes() { return PsiClassType.EMPTY_ARRAY; } @NotNull @Override public PsiField[] getFields() { return PsiField.EMPTY_ARRAY; } @NotNull @Override public PsiClass[] getInnerClasses() { return PsiClass.EMPTY_ARRAY; } @NotNull @Override public PsiClassInitializer[] getInitializers() { return PsiClassInitializer.EMPTY_ARRAY; } @NotNull @Override public PsiField[] getAllFields() { return PsiField.EMPTY_ARRAY; } @NotNull @Override public PsiMethod[] getAllMethods() { return PsiMethod.EMPTY_ARRAY; } @NotNull @Override public PsiClass[] getAllInnerClasses() { return PsiClass.EMPTY_ARRAY; } @Override public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) { return null; } @NotNull @Override public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) { return PsiMethod.EMPTY_ARRAY; } @NotNull @Override public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) { return Collections.emptyList(); } @NotNull @Override public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() { return Collections.emptyList(); } @Override public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) { return null; } @Override public PsiElement getLBrace() { return null; } @Override public PsiElement getRBrace() { return null; } @Override public PsiIdentifier getNameIdentifier() { return null; } @Nullable @Override public PsiElement getScope() { return null; } @Override public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) { return false; } @Override public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) { return false; } @NotNull @Override public Collection<HierarchicalMethodSignature> getVisibleSignatures() { return null; } @Nullable @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { return null; } @Override public PsiDocComment getDocComment() { return null; } @Override public boolean isDeprecated() { return false; } @Override public boolean hasTypeParameters() { return false; } @Override public PsiTypeParameterList getTypeParameterList() { return null; } @NotNull @Override public PsiTypeParameter[] getTypeParameters() { return PsiTypeParameter.EMPTY_ARRAY; } @Override public ItemPresentation getPresentation() { return new CustomGosuClassPresentation(this); } @Override public void navigate(boolean requestFocus) { final Navigatable navigatable = PsiNavigationSupport.getInstance().getDescriptor(this); if (navigatable != null) { navigatable.navigate(requestFocus); } } @Override public boolean canNavigate() { return true; } @Override public boolean canNavigateToSource() { return true; } @Override public PsiModifierList getModifierList() { return null; } @NotNull @Override public Language getLanguage() { return GosuLanguage.instance(); } @NotNull @Override public PsiElement[] getChildren() { return PsiElement.EMPTY_ARRAY; } @Nullable @Override public PsiElement getParent() { return null; } @Override public PsiElement getFirstChild() { return null; } @Override public PsiElement getLastChild() { return null; } @Override public PsiElement getNextSibling() { return null; } @Override public PsiElement getPrevSibling() { return null; } @Nullable @Override public TextRange getTextRange() { return null; } @Override public int getStartOffsetInParent() { return 0; } @Override public int getTextLength() { return 0; } @Override public PsiElement findElementAt(int offset) { return null; } @Override public PsiReference findReferenceAt(int offset) { return null; } @Override public int getTextOffset() { return 0; } @Nullable @Override public String getText() { return file.getText(); } @NotNull @Override public char[] textToCharArray() { return file.getText().toCharArray(); } @NotNull @Override public PsiElement getNavigationElement() { if (sourceFiles != null && sourceFiles.length > 1) { //TODO-dp this is a hack, add some extension point if (namespace.equals("entity") || namespace.equals("typekey")) { for (int i = sourceFiles.length - 1; i >= 0; i--) { final IFile file = sourceFiles[i]; final VirtualFile virtualFile = ((IDEAFile) file).getVirtualFile(); final PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(virtualFile); if (psiFile instanceof XmlFile) { //Avoid java and gosu files return psiFile.getNavigationElement(); } } } } return file.getNavigationElement(); } @Nullable @Override public PsiElement getOriginalElement() { return null; } @Override public boolean textMatches(@NotNull @NonNls CharSequence text) { return false; } @Override public boolean textMatches(@NotNull PsiElement element) { return false; } @Override public boolean textContains(char c) { return false; } @Override public void accept(@NotNull PsiElementVisitor visitor) { } @Override public void acceptChildren(@NotNull PsiElementVisitor visitor) { } @Nullable @Override public PsiElement copy() { return null; } @Nullable @Override public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException { return null; } @Nullable @Override public PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException { return null; } @Nullable @Override public PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException { return null; } @Override public void checkAdd(@NotNull PsiElement element) throws IncorrectOperationException { } @Nullable @Override public PsiElement addRange(PsiElement first, PsiElement last) throws IncorrectOperationException { return null; } @Nullable @Override public PsiElement addRangeBefore(@NotNull PsiElement first, @NotNull PsiElement last, PsiElement anchor) throws IncorrectOperationException { return null; } @Nullable @Override public PsiElement addRangeAfter(PsiElement first, PsiElement last, PsiElement anchor) throws IncorrectOperationException { return null; } @Override public void delete() throws IncorrectOperationException { } @Override public void checkDelete() throws IncorrectOperationException { } @Override public void deleteChildRange(PsiElement first, PsiElement last) throws IncorrectOperationException { } @Nullable @Override public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException { return null; } @Override public PsiReference getReference() { return null; } @NotNull @Override public PsiReference[] getReferences() { return PsiReference.EMPTY_ARRAY; } @Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { return false; } @Override public PsiElement getContext() { return null; } @NotNull @Override public GlobalSearchScope getResolveScope() { return GlobalSearchScope.allScope(getProject()); } @NotNull @Override public SearchScope getUseScope() { return PsiClassImplUtil.getClassUseScope(this); } @Nullable @Override public ASTNode getNode() { return null; } @Override public boolean isEquivalentTo(PsiElement another) { return false; } @Override public Icon getIcon(int flags) { return file.getIcon(flags); } public PsiElement getField(String name, PsiElement element) { PsiField psiField = fields.get(name); if (psiField == null) { psiField = new GosuXMLField(name, element, this); fields.put(name, psiField); } return psiField; } public PsiElement getMethod(@NotNull IMethodInfo mi, XmlTag element) { final String signature = getSignature(mi); PsiMethod psiMethod = methods.get(signature); if (psiMethod == null) { psiMethod = new GosuXMLMethod(mi, this); methods.put(signature, psiMethod); } return psiMethod; } @NotNull public static String getSignature(@NotNull IMethodInfo mi) { String s = mi.getDisplayName() + "("; for (IParameterInfo parameter : mi.getParameters()) { s += parameter.getFeatureType().getName() + ", "; } return s + ")"; } @Nullable @Override public String toString() { return getName(); } }