/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.lang.psi.impl.statements;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.util.IncorrectOperationException;
import gw.lang.parser.expressions.IModifierListClause;
import gw.plugin.ij.lang.GosuTokenSets;
import gw.plugin.ij.lang.parser.GosuCompositeElement;
import gw.plugin.ij.lang.parser.GosuElementTypes;
import gw.plugin.ij.lang.psi.api.auxilary.IGosuModifier;
import gw.plugin.ij.lang.psi.api.auxilary.IGosuModifierList;
import gw.plugin.ij.lang.psi.api.auxilary.annotation.IGosuAnnotation;
import gw.plugin.ij.lang.psi.api.statements.IGosuVariable;
import gw.plugin.ij.lang.psi.api.statements.typedef.IGosuTypeDefinition;
import gw.plugin.ij.lang.psi.impl.GosuElementVisitor;
import gw.plugin.ij.lang.psi.impl.GosuPsiElementImpl;
import gw.plugin.ij.lang.psi.util.GosuPsiParseUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class GosuModifierListImpl extends GosuPsiElementImpl<IModifierListClause> implements IGosuModifierList {
private static final Logger LOG = Logger.getInstance("#gw.plugin.ij.lang.psi.impl.statements.params.GosuModifierListImpl");
public GosuModifierListImpl( @NotNull GosuCompositeElement node ) {
super(node);
}
public void accept(@NotNull GosuElementVisitor visitor) {
visitor.visitModifierList( this );
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if( visitor instanceof GosuElementVisitor) {
((GosuElementVisitor)visitor).visitModifierList(this);
}
else {
visitor.visitElement( this );
}
}
@NotNull
public PsiElement[] getModifiers() {
final PsiElement[] modifiersKeywords = findChildrenByType( GosuTokenSets.MODIFIERS, PsiElement.class);
final IGosuAnnotation[] modifiersAnnotations = findChildrenByClass(IGosuAnnotation.class);
if (modifiersAnnotations.length == 0) {
return modifiersKeywords;
} else {
final PsiElement[] result = new PsiElement[modifiersAnnotations.length + modifiersKeywords.length];
int i = 0;
for (PsiElement keyword : modifiersKeywords) {
result[i++] = keyword;
}
for (IGosuAnnotation annotation : modifiersAnnotations) {
result[i++] = annotation;
}
return result;
}
}
public boolean hasExplicitVisibilityModifiers() {
return findChildByType(GosuTokenSets.VISIBILITY_MODIFIERS) != null;
}
public boolean hasModifierProperty(@NotNull @NonNls String modifier) {
final PsiElement parent = getParent();
if (parent instanceof IGosuVariable &&
parent.getParent() instanceof IGosuTypeDefinition ) {
PsiElement pParent = parent.getParent().getParent();
if (!hasExplicitVisibilityModifiers()) { //properties are backed by private fields
if (pParent instanceof PsiClass && ((PsiClass) pParent).isInterface()) {
if (modifier.equals( IGosuModifier.STATIC)) {
return true;
}
if (modifier.equals(IGosuModifier.FINAL)) {
return true;
}
} else {
if (modifier.equals(IGosuModifier.PRIVATE)) {
return true;
}
if (modifier.equals(IGosuModifier.PROTECTED)) {
return false;
}
if (modifier.equals(IGosuModifier.PUBLIC)) {
return false;
}
}
}
}
if (hasExplicitModifier(modifier)) {
return true;
}
if (modifier.equals(IGosuModifier.PUBLIC)) {
// Gosu type definitions and methods are public by default
return !hasExplicitModifier(IGosuModifier.PRIVATE) &&
!hasExplicitModifier(IGosuModifier.PROTECTED) &&
!hasExplicitModifier(IGosuModifier.INTERNAL);
}
if (parent instanceof IGosuTypeDefinition) {
if (modifier.equals(IGosuModifier.STATIC)) {
final PsiClass containingClass = ((IGosuTypeDefinition) parent).getContainingClass();
return containingClass != null && containingClass.isInterface();
}
if (modifier.equals(IGosuModifier.ABSTRACT)) {
return ((IGosuTypeDefinition) parent).isInterface();
}
}
return false;
}
public boolean hasExplicitModifier(@NotNull @NonNls String name) {
if (name.equals(IGosuModifier.PUBLIC)) {
return findChildByType( GosuElementTypes.TT_public) != null;
}
if (name.equals(IGosuModifier.ABSTRACT)) {
return findChildByType(GosuElementTypes.TT_abstract) != null;
}
if (name.equals(IGosuModifier.PRIVATE)) {
return findChildByType(GosuElementTypes.TT_private) != null;
}
if (name.equals(IGosuModifier.PROTECTED)) {
return findChildByType(GosuElementTypes.TT_protected) != null;
}
if (name.equals(IGosuModifier.PACKAGE_LOCAL) || name.equals(IGosuModifier.INTERNAL)) {
return findChildByType(GosuElementTypes.TT_internal) != null;
}
if (name.equals(IGosuModifier.STATIC)) {
return findChildByType(GosuElementTypes.TT_static) != null;
}
if (name.equals(IGosuModifier.FINAL)) {
return findChildByType(GosuElementTypes.TT_final) != null;
}
if (name.equals(IGosuModifier.TRANSIENT)) {
return findChildByType(GosuElementTypes.TT_transient) != null;
}
return false;
}
public void setModifierProperty(@NotNull @NonNls String name, boolean doSet) throws IncorrectOperationException {
if (hasModifierProperty(name) == doSet) {
return;
}
if (doSet) {
if (IGosuModifier.PRIVATE.equals(name) ||
IGosuModifier.PROTECTED.equals(name) ||
IGosuModifier.PUBLIC.equals(name) ||
IGosuModifier.PACKAGE_LOCAL.equals(name)) {
setModifierPropertyInternal(IGosuModifier.PUBLIC, false);
setModifierPropertyInternal(IGosuModifier.PROTECTED, false);
setModifierPropertyInternal(IGosuModifier.INTERNAL, false);
setModifierPropertyInternal(IGosuModifier.PRIVATE, false);
}
}
setModifierPropertyInternal(name, doSet);
}
private void setModifierPropertyInternal(@NotNull String name, boolean doSet) {
if (doSet) {
final ASTNode modifierNode = GosuPsiParseUtil.createModifierFromText( name, getManager() ).getNode();
addInternal(modifierNode, modifierNode, null, false);
} else {
final PsiElement[] modifiers = findChildrenByType(GosuTokenSets.MODIFIERS, PsiElement.class);
for (PsiElement modifier : modifiers) {
if (name.equals(modifier.getText())) {
deleteChildRange(modifier, modifier);
break;
}
}
}
}
public void checkSetModifierProperty(@NotNull @NonNls String name, boolean value) throws IncorrectOperationException {
}
@NotNull
public IGosuAnnotation[] getAnnotations() {
return findChildrenByClass(IGosuAnnotation.class);
}
@NotNull
public PsiAnnotation[] getApplicableAnnotations() {
return getAnnotations();
}
@Nullable
public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
PsiElement child = getFirstChild();
while (child != null) {
if (child instanceof PsiAnnotation && qualifiedName.equals(((PsiAnnotation) child).getQualifiedName())) {
return (PsiAnnotation) child;
}
child = child.getNextSibling();
}
return null;
}
@NotNull
public IGosuAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
throw new UnsupportedOperationException("This operation does not make sense for Gosu");
}
}