/* * 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.navigation.ItemPresentation; import com.intellij.openapi.util.Pair; import com.intellij.plugins.haxe.HaxeComponentType; import com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypes; import com.intellij.plugins.haxe.lang.psi.*; import com.intellij.plugins.haxe.model.HaxeMemberModel; import com.intellij.plugins.haxe.model.HaxeMethodModel; import com.intellij.plugins.haxe.model.type.HaxeTypeResolver; import com.intellij.plugins.haxe.model.type.ResultHolder; import com.intellij.plugins.haxe.model.type.SpecificTypeReference; import com.intellij.plugins.haxe.util.HaxePresentableUtil; import com.intellij.plugins.haxe.util.HaxeResolveUtil; import com.intellij.plugins.haxe.util.UsefulPsiTreeUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.PsiReference; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Set; /** * @author: Fedor.Korotkov */ abstract public class AbstractHaxeNamedComponent extends HaxePsiCompositeElementImpl implements HaxeNamedComponent, PsiNamedElement { public ResultHolder _cachedType; public long _cachedTypeStamp; public AbstractHaxeNamedComponent(@NotNull ASTNode node) { super(node); } @Override @Nullable @NonNls public String getName() { final HaxeComponentName name = getComponentName(); if (name != null) { return name.getText(); } return super.getName(); } @Override public String getText() { return super.getText(); } @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { final HaxeComponentName componentName = getComponentName(); if (componentName != null) { componentName.setName(name); } return this; } @Override public Icon getIcon(int flags) { final HaxeComponentType type = HaxeComponentType.typeOf(this); return type == null ? null : type.getIcon(); } @Override public ItemPresentation getPresentation() { return new ItemPresentation() { @Override public String getPresentableText() { final StringBuilder result = new StringBuilder(); HaxeMemberModel member = HaxeMemberModel.fromPsi(AbstractHaxeNamedComponent.this); if (member == null) { result.append(AbstractHaxeNamedComponent.this.getName()); } else { result.append(member.getName()); if (member instanceof HaxeMethodModel) { final String parameterList = HaxePresentableUtil.getPresentableParameterList(member.getNamedComponentPsi()); result.append("(").append(parameterList).append(")"); } final ResultHolder resultType = member.getResultType(); if (resultType != null) { result.append(":"); result.append(member.getResultType().toString()); } } return result.toString(); } @Override public String getLocationString() { HaxeClass haxeClass = AbstractHaxeNamedComponent.this instanceof HaxeClass ? (HaxeClass)AbstractHaxeNamedComponent.this : PsiTreeUtil.getParentOfType(AbstractHaxeNamedComponent.this, HaxeClass.class); if (haxeClass instanceof HaxeAnonymousType) { final HaxeTypedefDeclaration typedefDeclaration = PsiTreeUtil.getParentOfType(haxeClass, HaxeTypedefDeclaration.class); if (typedefDeclaration != null) { haxeClass = typedefDeclaration; } } if (haxeClass == null) { return ""; } final Pair<String, String> qName = HaxeResolveUtil.splitQName(haxeClass.getQualifiedName()); if (haxeClass == AbstractHaxeNamedComponent.this) { return qName.getFirst(); } return haxeClass.getQualifiedName(); } @Override public Icon getIcon(boolean open) { return AbstractHaxeNamedComponent.this.getIcon(0); } }; } @Override public HaxeNamedComponent getTypeComponent() { final HaxeTypeTag typeTag = PsiTreeUtil.getChildOfType(getParent(), HaxeTypeTag.class); final HaxeType type = typeTag != null ? typeTag.getTypeOrAnonymous().getType() : null; final PsiReference reference = type != null ? type.getReference() : null; if (reference != null) { final PsiElement result = reference.resolve(); if (result instanceof HaxeNamedComponent) { return (HaxeNamedComponent)result; } } return null; } @Override public boolean isPublic() { if (PsiTreeUtil.getParentOfType(this, HaxeExternClassDeclaration.class) != null) { return true; } if (PsiTreeUtil.getParentOfType(this, HaxeInterfaceDeclaration.class, HaxeEnumDeclaration.class) != null) { return true; } if (PsiTreeUtil.getParentOfType(this, HaxeAnonymousType.class) != null) { return true; } final PsiElement parent = getParent(); return hasPublicAccessor(this) || (parent instanceof HaxePsiCompositeElement && hasPublicAccessor((HaxePsiCompositeElement)parent)); } private static boolean hasPublicAccessor(HaxePsiCompositeElement element) { // do not change the order of these if-statements if (UsefulPsiTreeUtil.getChildOfType(element, HaxeTokenTypes.KPRIVATE) != null) { return false; // private } if (UsefulPsiTreeUtil.getChildOfType(element, HaxeTokenTypes.KPUBLIC) != null) { return true; // public } final HaxeDeclarationAttribute[] declarationAttributeList = PsiTreeUtil.getChildrenOfType(element, HaxeDeclarationAttribute.class); if (declarationAttributeList != null) { final Set<IElementType> declarationTypes = HaxeResolveUtil.getDeclarationTypes((declarationAttributeList)); // do not change the order of these if-statements if (declarationTypes.contains(HaxeTokenTypes.KPRIVATE)) { return false; // private } if (declarationTypes.contains(HaxeTokenTypes.KPUBLIC)) { return true; // public } } return false; // <default>: private } @Override public boolean isStatic() { AbstractHaxeNamedComponent element = this; if (this instanceof HaxeVarDeclarationPart) { element = (AbstractHaxeNamedComponent)element.getParent(); } final HaxeDeclarationAttribute[] declarationAttributeList = PsiTreeUtil.getChildrenOfType(element, HaxeDeclarationAttribute.class); return HaxeResolveUtil.getDeclarationTypes(declarationAttributeList).contains(HaxeTokenTypes.KSTATIC); } @Override public boolean isOverride() { final HaxeDeclarationAttribute[] declarationAttributeList = PsiTreeUtil.getChildrenOfType(this, HaxeDeclarationAttribute.class); return HaxeResolveUtil.getDeclarationTypes(declarationAttributeList).contains(HaxeTokenTypes.KOVERRIDE); } @Override public boolean isInline() { final HaxeDeclarationAttribute[] declarationAttributeList = PsiTreeUtil.getChildrenOfType(this, HaxeDeclarationAttribute.class); return HaxeResolveUtil.getDeclarationTypes(declarationAttributeList).contains(HaxeTokenTypes.KINLINE); } @Nullable public final PsiElement findChildByRoleAsPsiElement(int role) { ASTNode element = findChildByRole(role); if (element == null) return null; return SourceTreeToPsiMap.treeElementToPsi(element); } @Nullable public ASTNode findChildByRole(int role) { // assert ChildRole.isUnique(role); for (ASTNode child = getFirstChild().getNode(); child != null; child = child.getTreeNext()) { if (getChildRole(child) == role) return child; } return null; } public int getChildRole(ASTNode child) { if (child.getElementType() == HaxeTokenTypes.PLCURLY) { return ChildRole.LBRACE; } else if (child.getElementType() == HaxeTokenTypes.PRCURLY) { return ChildRole.RBRACE; } return 0; } protected final int getChildRole(ASTNode child, int roleCandidate) { if (findChildByRole(roleCandidate) == child) { return roleCandidate; } return 0; //ChildRole.NONE; } }