/* * Copyright 2013 Guidewire Software, Inc. */ package gw.plugin.ij.lang.psi.impl.statements; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiAnnotation; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiIdentifier; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiRecursiveElementWalkingVisitor; import com.intellij.psi.PsiType; import com.intellij.psi.PsiTypeElement; import com.intellij.psi.impl.ElementPresentationUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.RowIcon; import com.intellij.util.IncorrectOperationException; import gw.lang.parser.IHasType; import gw.lang.parser.IParsedElementWithAtLeastOneDeclaration; import gw.lang.reflect.IType; import gw.lang.reflect.gs.ICompilableType; import gw.lang.reflect.java.JavaTypes; import gw.plugin.ij.icons.GosuIcons; import gw.plugin.ij.lang.parser.GosuCompositeElement; import gw.plugin.ij.lang.parser.GosuElementTypes; import gw.plugin.ij.lang.psi.api.auxilary.IGosuModifierList; import gw.plugin.ij.lang.psi.api.expressions.IGosuExpression; import gw.plugin.ij.lang.psi.api.statements.IGosuVariable; import gw.plugin.ij.lang.psi.api.types.IGosuTypeElement; import gw.plugin.ij.lang.psi.impl.GosuDeclaredElementImpl; import gw.plugin.ij.lang.psi.impl.GosuPsiImplUtil; import gw.plugin.ij.util.ExecutionUtil; import gw.plugin.ij.util.SafeCallable; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; public abstract class GosuVariableBaseImpl<E extends IParsedElementWithAtLeastOneDeclaration, T extends StubElement> extends GosuDeclaredElementImpl<E, T> implements IGosuVariable { public static final Logger LOG = Logger.getInstance("gw.plugin.ij.lang.psi.impl.statements.GosuVariableImpl"); public GosuVariableBaseImpl(@NotNull GosuCompositeElement node) { super(node); } protected GosuVariableBaseImpl(@NotNull final T stub, @NotNull IStubElementType nodeType) { super(stub, nodeType); } @Nullable public PsiTypeElement getTypeElement() { return null; } @Nullable public PsiExpression getInitializer() { for( PsiElement elem = findChildByType( GosuElementTypes.TT_OP_assign ); elem != null; elem = elem.getNextSibling() ) { if( elem instanceof PsiExpression ) { return (PsiExpression)elem; } } return null; } public boolean hasInitializer() { return getInitializer() != null; } public void normalizeDeclaration() throws IncorrectOperationException { } @Nullable public Object computeConstantValue() { return null; } @NotNull public PsiType getType() { return ExecutionUtil.execute( new SafeCallable<PsiType>(this) { public PsiType execute() throws Exception { PsiType type = getDeclaredType(); if( type == null ) { type = PsiType.getJavaLangObject(getManager(), getResolveScope()); } return type; } @Override public PsiType handleNull( Throwable exception ) { // Can't return a null type :/ return ExecutionUtil.execute( new SafeCallable<PsiType>(GosuVariableBaseImpl.this) { public PsiType execute() throws Exception { return createType( JavaTypes.OBJECT() ); } }); } }); } @Nullable public IGosuTypeElement getTypeElementGosu() { return (IGosuTypeElement) findChildByType(GosuElementTypes.ELEM_TYPE_TypeLiteral); } @Nullable public PsiType getDeclaredType() { IGosuTypeElement typeElement = getTypeElementGosu(); if (typeElement != null) { return typeElement.getType(); } Object parsedElement = getParsedElement(); if (parsedElement instanceof IHasType) { IType type = ((IHasType) parsedElement).getType(); if (type instanceof ICompilableType && ((ICompilableType) type).isAnonymous()) { IType superType = type.getSupertype(); if (superType == null) { superType = type.getInterfaces()[0]; } type = superType; } return createType(type); } return null; } public void setType(@Nullable PsiType type) { throw new UnsupportedOperationException("Men at work"); } @Nullable public IGosuExpression getInitializerGosu() { PsiExpression psiInit = getInitializer(); if( psiInit instanceof IGosuExpression ) { return (IGosuExpression) psiInit; } return null; } public int getTextOffset() { final PsiIdentifier nameIdentifier = getNameIdentifier(); return nameIdentifier == null ? getTextRange().getStartOffset() : nameIdentifier.getTextRange().getStartOffset(); } @NotNull public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { GosuPsiImplUtil.setName(getNameIdentifier(), name); return this; } @NotNull public SearchScope getUseScope() { final AbstractStatementWithLocalDeclarationsImpl owner = PsiTreeUtil.getParentOfType(this, AbstractStatementWithLocalDeclarationsImpl.class); if (owner != null) { return new LocalSearchScope(owner); } return super.getUseScope(); } @NotNull public String getName() { return GosuPsiImplUtil.getName(this); } @Nullable public PsiIdentifier getNameIdentifier() { //return (PsiIdentifier)findElement( this, GosuElementTypes.ELEM_TYPE_NameInDeclaration ); class FindIdSkippingAnnotations extends PsiRecursiveElementWalkingVisitor { PsiIdentifier id; public void visitElement(PsiElement element) { if (element instanceof PsiAnnotation) { return; } else if (element instanceof PsiIdentifier) { id = (PsiIdentifier) element; stopWalking(); return; } super.visitElement(element); } } FindIdSkippingAnnotations finder = new FindIdSkippingAnnotations(); this.accept(finder); PsiIdentifier id = finder.id; if (id != null && id.getFirstChild() != null && id.getFirstChild() instanceof PsiIdentifier) { // Always return the leaf token node; we always want to patch in just the name and not mess with upper-level tree nodes id = (PsiIdentifier) id.getFirstChild(); } return id; } @Nullable public IGosuModifierList getModifierList() { return (IGosuModifierList)findChildByClass( PsiModifierList.class ); } @Override public boolean hasModifierProperty( @PsiModifier.ModifierConstant @NonNls @NotNull String name ) { IGosuModifierList modifierList = getModifierList(); return modifierList != null ? modifierList.hasModifierProperty(name) : false; } @NotNull public PsiType getTypeNoResolve() { return getType(); } @Override public Icon getElementIcon(final int flags) { final RowIcon baseIcon = ElementPresentationUtil.createLayeredIcon(GosuIcons.VARIABLE, this, false); return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon); } }