/* * Copyright 2000-2013 JetBrains s.r.o. * Copyright 2014-2014 AS3Boyan * Copyright 2014-2014 Elias Ku * * 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.intellij.plugins.haxe.lang.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.plugins.haxe.lang.psi.HaxeReferenceExpression; import com.intellij.plugins.haxe.lang.psi.HaxeType; import com.intellij.plugins.haxe.lang.psi.HaxeTypeParam; import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.util.ArrayFactory; import com.intellij.util.IncorrectOperationException; import org.apache.log4j.Level; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; /** * A class to encapsulate/override PsiType so that its interface can be used with Haxe. * * This class is used to get around the fact that PsiType isn't an interface. * Instead, we re-implement everything and introduce a has-a relationship * to the erstwhile child class. * * Created by ebishton on 10/18/14. */ public class HaxePsiTypeAdapter extends PsiType implements HaxeType { static final Logger LOG = Logger.getInstance("#com.intellij.plugins.haxe.lang.psi.impl.HaxePsiTypeAdapter"); static { LOG.setLevel(Level.DEBUG); } public static final PsiPrimitiveType DYNAMIC = new PsiPrimitiveType("Dynamic", PsiAnnotation.EMPTY_ARRAY); HaxeType myType = null; public HaxePsiTypeAdapter(@NotNull HaxeType haxeType) { // Haxe doesn't use annotations in the same way that Java does. Instead, they're all // modifiers, including macros (which are more like annotations). super(PsiAnnotation.EMPTY_ARRAY); myType = haxeType; } // // ParameterListOwner methods. // @Override public boolean hasTypeParameters() { return myType.hasTypeParameters(); } @Nullable @Override public PsiTypeParameterList getTypeParameterList() { return myType.getTypeParameterList(); } @NotNull @Override public PsiTypeParameter[] getTypeParameters() { return myType.getTypeParameters(); } // // PsiMember methods. // @Nullable @Override public PsiClass getContainingClass() { return myType.getContainingClass(); } // // PsiModifierListOwner methods. // @Nullable @Override public PsiModifierList getModifierList() { return myType.getModifierList(); } @Override public boolean hasModifierProperty(@PsiModifier.ModifierConstant @NonNls @NotNull String name) { return myType.hasModifierProperty(name); } // // PsiType methods. // public static final HaxePsiTypeAdapter[] EMPTY_ARRAY = new HaxePsiTypeAdapter[0]; public static final ArrayFactory<HaxePsiTypeAdapter> ARRAY_FACTORY = new ArrayFactory<HaxePsiTypeAdapter>() { @NotNull @Override public HaxePsiTypeAdapter[] create(int count) { return count == 0 ? EMPTY_ARRAY : new HaxePsiTypeAdapter[count]; } }; @NotNull public static HaxePsiTypeAdapter[] createArray(int count) { return ARRAY_FACTORY.create(count); } @NotNull @Override public PsiArrayType createArrayType() { // Wrong answer, but until we need it, we can punt. // TODO: Implement HaxePsiAdapter.createArrayType LOG.debug("Implement HaxePsiAdapter.createArrayType"); return new PsiArrayType(this); } @NotNull @Override public PsiArrayType createArrayType(@NotNull PsiAnnotation... annotations) { // Wrong answer, but until we need it, we can punt. // TODO: Implement HaxePsiAdapter.createArrayType LOG.debug("Implement HaxePsiAdapter.createArrayType"); return new PsiArrayType(this); } @NotNull @Override public String getPresentableText() { return myType.getText(); } @NotNull @Override public String getCanonicalText(boolean annotated) { return getCanonicalText(); } @NotNull @Override public String getCanonicalText() { return myType.getText(); } @NotNull @Override public String getInternalCanonicalText() { return myType.getText(); } @Override public boolean isValid() { return myType.isValid(); } @Override public boolean isAssignableFrom(@NotNull PsiType type) { // Java uses the TypeConversionUtil.canAssignToFrom, which will most likely fail. // TODO: Implement HaxePsiAdapter.isAssignableFrom LOG.debug("Implement HaxePsiAdapter.isAssignableFrom()"); return super.isAssignableFrom(type); } @Override public boolean isConvertibleFrom(@NotNull PsiType type) { // Java uses the TypeConversionUtil.isConvertable, which will most likely fail. // TODO: Implement HaxePsiAdapter.isConvertibleFrom LOG.debug("Implement HaxePsiAdapter.isConvertibleFrom()"); return super.isConvertibleFrom(type); } @Override public boolean equalsToText(@NotNull @NonNls String text) { return text.equals(myType.getText()); } @Override public void accept(@NotNull PsiElementVisitor visitor) { myType.accept(visitor); } @Nullable @Override public GlobalSearchScope getResolveScope() { return myType.getResolveScope(); } @NotNull @Override public PsiType[] getSuperTypes() { // TODO: Verify that we don't need to find supertypes through HaxePsiTypeAdapter.getSuperTypes(). // XXX: This seems like a likely code path for call hierarchies. return EMPTY_ARRAY; } @NotNull @Override public PsiAnnotation[] getAnnotations() { // TODO: ?? Find and convert modifiers to annotations for HaxePsiTypeAdapter.getAnnotations() ?? return PsiAnnotation.EMPTY_ARRAY; } @Override public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) { // TODO: ?? Find and convert modifiers to annotations for HaxePsiTypeAdapter.findAnnotation() ?? return super.findAnnotation(qualifiedName); } @NotNull @Override public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) { // Duplicate the super's behavior. throw new UnsupportedOperationException(); } @NotNull @Override public PsiAnnotation[] getApplicableAnnotations() { return PsiAnnotation.EMPTY_ARRAY; } @Override public String toString() { return "HaxePsiTypeAdapter:" + getPresentableText(); } @Override public <A> A accept(@NotNull PsiTypeVisitor<A> visitor) { // TODO: Figure out what accept is supposed to do for HaxePsiTypeAdapter. LOG.debug("Unimplemented HaxePsiTypeAdapter.accept(PsiTypeVisitor<A>) was called."); return null; // visitor.visitPsiType(this); // Hmm, ain't no such thing. } // // HaxeType methods. // @NotNull @Override public HaxeReferenceExpression getReferenceExpression() { return myType.getReferenceExpression(); } @Nullable @Override public HaxeTypeParam getTypeParam() { return myType.getTypeParam(); } @Nullable @Override public PsiType getPsiType() { return this; } @Override public IElementType getTokenType() { return myType.getTokenType(); } @Nullable @Override public String getName() { return myType.getName(); } @Nullable @Override public ItemPresentation getPresentation() { return myType.getPresentation(); } @Override public void navigate(boolean requestFocus) { myType.navigate(requestFocus); } @Override public boolean canNavigate() { return myType.canNavigate(); } @Override public boolean canNavigateToSource() { return myType.canNavigateToSource(); } @NotNull @Override public Project getProject() throws PsiInvalidElementAccessException { return myType.getProject(); } @NotNull @Override public Language getLanguage() { return myType.getLanguage(); } @Override public PsiManager getManager() { return myType.getManager(); } @NotNull @Override public PsiElement[] getChildren() { return myType.getChildren(); } @Override public PsiElement getParent() { return myType.getParent(); } @Override public PsiElement getFirstChild() { return myType.getFirstChild(); } @Override public PsiElement getLastChild() { return myType.getLastChild(); } @Override public PsiElement getNextSibling() { return myType.getNextSibling(); } @Override public PsiElement getPrevSibling() { return myType.getPrevSibling(); } @Override public PsiFile getContainingFile() throws PsiInvalidElementAccessException { return myType.getContainingFile(); } @Override public TextRange getTextRange() { return myType.getTextRange(); } @Override public int getStartOffsetInParent() { return myType.getStartOffsetInParent(); } @Override public int getTextLength() { return myType.getTextLength(); } @Nullable @Override public PsiElement findElementAt(int offset) { return myType.findElementAt(offset); } @Nullable @Override public PsiReference findReferenceAt(int offset) { return myType.findReferenceAt(offset); } @Override public int getTextOffset() { return myType.getTextOffset(); } @Override public String getText() { return myType.getText(); } @NotNull @Override public char[] textToCharArray() { return myType.textToCharArray(); } @Override public PsiElement getNavigationElement() { return myType.getNavigationElement(); } @Override public PsiElement getOriginalElement() { return myType.getOriginalElement(); } @Override public boolean textMatches(@NotNull @NonNls CharSequence text) { return myType.textMatches(text); } @Override public boolean textMatches(@NotNull PsiElement element) { return myType.textMatches(element); } @Override public boolean textContains(char c) { return myType.textContains(c); } @Override public void acceptChildren(@NotNull PsiElementVisitor visitor) { myType.acceptChildren(visitor); } @Override public PsiElement copy() { return (HaxePsiTypeAdapter)((HaxeType)myType.copy()).getPsiType(); } @Override public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException { return myType.add(element); } @Override public PsiElement addBefore(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException { return myType.addBefore(element, anchor); } @Override public PsiElement addAfter(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException { return myType.addAfter(element, anchor); } @Override @Deprecated public void checkAdd(@NotNull PsiElement element) throws IncorrectOperationException { myType.checkAdd(element); } @Override public PsiElement addRange(PsiElement first, PsiElement last) throws IncorrectOperationException { return myType.addRange(first, last); } @Override public PsiElement addRangeBefore(@NotNull PsiElement first, @NotNull PsiElement last, PsiElement anchor) throws IncorrectOperationException { return myType.addRangeBefore(first, last, anchor); } @Override public PsiElement addRangeAfter(PsiElement first, PsiElement last, PsiElement anchor) throws IncorrectOperationException { return myType.addRangeAfter(first, last, anchor); } @Override public void delete() throws IncorrectOperationException { myType.delete(); } @Override @Deprecated public void checkDelete() throws IncorrectOperationException { myType.checkDelete(); } @Override public void deleteChildRange(PsiElement first, PsiElement last) throws IncorrectOperationException { myType.deleteChildRange(first, last); } @Override public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException { // XXX: Might need to return a PsiType for it, if it's a HaxeType. return myType.replace(newElement); } @Override public boolean isWritable() { return myType.isWritable(); } @Nullable @Override public PsiReference getReference() { return myType.getReference(); } @NotNull @Override public PsiReference[] getReferences() { return myType.getReferences(); } @Nullable @Override public <T> T getCopyableUserData(Key<T> key) { return myType.getCopyableUserData(key); } @Override public <T> void putCopyableUserData(Key<T> key, @Nullable T value) { myType.putCopyableUserData(key, value); } @Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { return myType.processDeclarations(processor, state, lastParent, place); } @Nullable @Override public PsiElement getContext() { return myType.getContext(); } @Override public boolean isPhysical() { return myType.isPhysical(); } @NotNull @Override public SearchScope getUseScope() { return myType.getUseScope(); } @Override public ASTNode getNode() { return myType.getNode(); } @Override public boolean isEquivalentTo(PsiElement another) { return myType.isEquivalentTo(another); } @Override public Icon getIcon(@IconFlags int flags) { return myType.getIcon(flags); } @Nullable @Override public <T> T getUserData(@NotNull Key<T> key) { return myType.getUserData(key); } @Override public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) { myType.putUserData(key, value); } }