/* * Copyright 2013 Guidewire Software, Inc. */ package gw.plugin.ij.lang.psi.impl.expressions; import com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.JavaResolveResult; import com.intellij.psi.PsiCallExpression; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiExpressionList; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReferenceParameterList; import com.intellij.psi.PsiType; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.util.PsiMatcherImpl; import com.intellij.psi.util.PsiMatchers; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import gw.lang.parser.expressions.IBeanMethodCallExpression; import gw.lang.reflect.IMethodInfo; import gw.plugin.ij.lang.GosuTokenTypes; import gw.plugin.ij.lang.parser.GosuCompositeElement; import gw.plugin.ij.lang.parser.GosuElementTypes; import gw.plugin.ij.lang.psi.api.types.IGosuCodeReferenceElement; import gw.plugin.ij.lang.psi.api.types.IGosuTypeElement; import gw.plugin.ij.lang.psi.api.types.IGosuTypeParameterList; import gw.plugin.ij.lang.psi.impl.GosuElementVisitor; import gw.plugin.ij.lang.psi.impl.resolvers.PsiFeatureResolver; import gw.plugin.ij.lang.psi.impl.statements.typedef.GosuSyntheticClassDefinitionImpl; import gw.plugin.ij.lang.psi.util.ElementTypeMatcher; import gw.plugin.ij.lang.psi.util.GosuPsiParseUtil; import gw.plugin.ij.util.ExecutionUtil; import gw.plugin.ij.util.SafeCallable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class GosuBeanMethodCallExpressionImpl extends GosuReferenceExpressionImpl<IBeanMethodCallExpression> implements IGosuCodeReferenceElement, IGosuTypeElement, PsiCallExpression { public GosuBeanMethodCallExpressionImpl(GosuCompositeElement node) { super(node); } @Nullable public PsiElement getReferenceNameElement() { PsiElement child = getLastChild(); while (child != null) { final ASTNode node = child.getNode(); if (node != null && (node.getElementType() == GosuTokenTypes.TT_IDENTIFIER || GosuTokenTypes.isKeyword(node.getElementType()))) return child; child = child.getPrevSibling(); } return null; } @Override public IGosuCodeReferenceElement getQualifier() { final PsiElement firstChild = getFirstChild(); return firstChild instanceof IGosuCodeReferenceElement ? (IGosuCodeReferenceElement) firstChild : null; } @Override public void setQualifier(IGosuCodeReferenceElement newQualifier) { throw new UnsupportedOperationException("Men at work"); } @Nullable public IGosuTypeParameterList getTypeParameterList() { return null; } @Override public PsiType[] getTypeArguments() { return PsiType.EMPTY_ARRAY; } @Override public PsiElement resolve() { return ExecutionUtil.execute(new SafeCallable<PsiElement>(this) { @Nullable public PsiElement execute() throws Exception { final IBeanMethodCallExpression pe = getParsedElement(); if (pe != null) { final IMethodInfo mi = pe.getGenericMethodDescriptor(); if (mi != null) { return PsiFeatureResolver.resolveMethodOrConstructor(mi, GosuBeanMethodCallExpressionImpl.this); } } return null; } }); } //TODO-dp consider adding an extension point for these kinds of special cases public TextRange getRangeInElement() { if (isDisplayKey()) { int startOffset = getTextRange().getStartOffset(); PsiElement referenceNameElement = getReferenceNameElement(); if (referenceNameElement != null) { int endOffset = referenceNameElement.getTextRange().getEndOffset(); return new TextRange(0, endOffset - startOffset); } } return super.getRangeInElement(); } private boolean isDisplayKey() { return GosuPropertyMemberAccessExpressionImpl.isDisplayKey(getParsedElement()); } protected PsiElement handleElementRenameInner(String newElementName) throws IncorrectOperationException { if (isDisplayKey()) { GosuIdentifierImpl childOfType = PsiTreeUtil.findChildOfType(this, GosuIdentifierImpl.class); GosuPropertyMemberAccessExpressionImpl parent = (GosuPropertyMemberAccessExpressionImpl) childOfType.getParent().getParent(); PsiElement referenceNameElement = parent.getReferenceNameElement(); int textOffset = getTextOffset(); int startOffset = referenceNameElement.getTextRange().getStartOffset() - textOffset; int endOffset = getReferenceNameElement().getTextRange().getEndOffset() - textOffset; String oldText = getText(); String newText = oldText.substring(0, startOffset) + newElementName + oldText.substring(endOffset); PsiElement element = GosuPsiParseUtil.createReferenceNameFromText(this, newText); ASTNode newNode = new PsiMatcherImpl(element.getContainingFile()) .descendant(PsiMatchers.hasClass(GosuSyntheticClassDefinitionImpl.class)) .descendant(new ElementTypeMatcher(GosuElementTypes.ELEM_TYPE_ReturnStatement)) .descendant(PsiMatchers.hasClass(GosuBeanMethodCallExpressionImpl.class)) .getElement().getNode(); CodeEditUtil.setOldIndentation((TreeElement) newNode, 0); // this is to avoid a stupid exception GosuCompositeElement oldNode = this.getNode(); oldNode.getTreeParent().replaceChild(oldNode, newNode); return this; } else { return super.handleElementRenameInner(newElementName); } } @Override public void accept( @NotNull PsiElementVisitor visitor ) { if( visitor instanceof JavaElementVisitor && !(visitor instanceof HighlightVisitorImpl) ) { ((JavaElementVisitor)visitor).visitCallExpression( this ); } else if( visitor instanceof GosuElementVisitor) { ((GosuElementVisitor)visitor).visitBeanMethodCallExpression(this); } else { visitor.visitElement( this ); } } @NotNull @Override public PsiExpressionList getArgumentList() { return (GosuExpressionListImpl)findChildByType( GosuElementTypes.ELEM_TYPE_ArgumentListClause ); } @Override public PsiMethod resolveMethod() { PsiElement ref = resolve(); return ref instanceof PsiMethod ? (PsiMethod)ref : null; } @NotNull @Override public JavaResolveResult resolveMethodGenerics() { throw new UnsupportedOperationException( "Not implemented yet" ); } @NotNull @Override public PsiReferenceParameterList getTypeArgumentList() { return null; } }