blob: b7dd0ba08de3222d7c0e9cf438b0efeff094cda4 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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 org.jetbrains.plugins.groovy.lang.psi.impl.statements.arguments;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.extensions.GroovyNamedArgumentProvider;
import org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.Map;
/**
* @author ilyas
*/
public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgumentLabel {
public GrArgumentLabelImpl(@NotNull ASTNode node) {
super(node);
}
@Override
public void accept(GroovyElementVisitor visitor) {
visitor.visitArgumentLabel(this);
}
public String toString() {
return "Argument label";
}
@Nullable
private PsiPolyVariantReference getReferenceFromNamedArgumentProviders() {
PsiElement namedArgument = getParent();
if (!(namedArgument instanceof GrNamedArgument)) return null;
PsiElement nameElement = getNameElement();
if (!(nameElement instanceof LeafPsiElement)) return null;
IElementType elementType = ((LeafPsiElement)nameElement).getElementType();
if (elementType != GroovyTokenTypes.mIDENT && !CommonClassNames.JAVA_LANG_STRING.equals(TypesUtil.getBoxedTypeName(elementType))) {
return null;
}
GrCall call = PsiUtil.getCallByNamedParameter((GrNamedArgument)namedArgument);
if (call == null) return null;
String labelName = getName();
Map<String,NamedArgumentDescriptor> providers = GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, labelName, false);
if (providers != null) {
NamedArgumentDescriptor descr = providers.get(labelName);
if (descr != null) {
PsiPolyVariantReference res = descr.createReference(this);
if (res != null) {
return res;
}
}
}
return null;
}
@NotNull
private PsiPolyVariantReference getRealReference() {
PsiReference[] otherReferences = ReferenceProvidersRegistry.getReferencesFromProviders(this, PsiReferenceService.Hints.NO_HINTS);
PsiPolyVariantReference reference = getReferenceFromNamedArgumentProviders();
if (otherReferences.length == 0) {
if (reference != null) {
return reference;
}
else {
return new PsiPolyVariantReferenceBase<PsiElement>(this) {
@NotNull
@Override
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@NotNull
@Override
public ResolveResult[] multiResolve(boolean incompleteCode) {
return ResolveResult.EMPTY_ARRAY;
}
};
}
}
else {
if (reference != null) {
PsiReference[] refs = new PsiReference[otherReferences.length + 1];
refs[0] = reference;
//noinspection ManualArrayCopy
for (int i = 0; i < otherReferences.length; i++) {
refs[i + 1] = otherReferences[i];
}
otherReferences = refs;
}
return new PsiMultiReference(otherReferences, this);
}
}
@Override
public PsiReference getReference() {
final PsiElement name = getNameElement();
return name instanceof GrLiteral || name instanceof LeafPsiElement ? this : null;
}
@Override
@Nullable
public String getName() {
final PsiElement element = getNameElement();
if (element instanceof GrLiteral) {
return convertToString(((GrLiteral)element).getValue());
}
if (element instanceof GrExpression) {
final Object value = JavaPsiFacade.getInstance(getProject()).getConstantEvaluationHelper().computeConstantExpression(element);
if (value instanceof String) {
return (String)value;
}
}
final IElementType elemType = element.getNode().getElementType();
if (GroovyTokenTypes.mIDENT == elemType || TokenSets.KEYWORDS.contains(elemType)) {
return element.getText();
}
return convertToString(GrLiteralImpl.getLiteralValue(element));
}
private static String convertToString(Object value) {
if (value instanceof String) {
return (String)value;
}
if (value instanceof Number) {
return value.toString();
}
return null;
}
@Override
public PsiElement getElement() {
return this;
}
@Override
public TextRange getRangeInElement() {
return new TextRange(0, getTextLength());
}
@Override
@Nullable
public PsiElement resolve() {
return advancedResolve().getElement();
}
@NotNull
@Override
public GroovyResolveResult[] multiResolve(boolean incompleteCode) {
final ResolveResult[] results = getRealReference().multiResolve(incompleteCode);
if (results instanceof GroovyResolveResult[]) {
return (GroovyResolveResult[])results;
}
else {
final GroovyResolveResult[] results1 = new GroovyResolveResult[results.length];
for (int i = 0; i < results.length; i++) {
ResolveResult result = results[i];
final PsiElement element = result.getElement();
if (element == null) {
results1[i] = GroovyResolveResult.EMPTY_RESULT;
}
else {
results1[i] = new GroovyResolveResultImpl(element, true);
}
}
return results1;
}
}
@NotNull
@Override
public GroovyResolveResult advancedResolve() {
return PsiImplUtil.extractUniqueResult(multiResolve(false));
}
@Override
@NotNull
public String getCanonicalText() {
PsiElement resolved = resolve();
if (resolved instanceof PsiMember && resolved instanceof PsiNamedElement) {
PsiClass clazz = ((PsiMember) resolved).getContainingClass();
if (clazz != null) {
String qName = clazz.getQualifiedName();
if (qName != null) {
return qName + "." + ((PsiNamedElement) resolved).getName();
}
}
}
return getText();
}
@Override
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
return getRealReference().handleElementRename(newElementName);
}
@Override
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
return getRealReference().bindToElement(element);
}
@Override
public boolean isReferenceTo(PsiElement element) {
return getRealReference().isReferenceTo(element);
}
@Override
@NotNull
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Override
public boolean isSoft() {
return false;
}
@Override
@NotNull
public PsiElement getNameElement() {
final PsiElement element = getFirstChild();
assert element != null;
return element;
}
@Override
public GrExpression getExpression() {
final PsiElement nameElement = getNameElement();
if (nameElement instanceof GrParenthesizedExpression) return ((GrParenthesizedExpression)nameElement).getOperand();
return null;
}
@Override
@Nullable
public PsiType getExpectedArgumentType() { // TODO use GroovyNamedArgumentProvider to determinate expected argument type.
return null;
}
@Override
public PsiType getLabelType() {
PsiElement el = getNameElement();
if (el instanceof GrParenthesizedExpression) {
return ((GrParenthesizedExpression)el).getType();
}
final ASTNode node = el.getNode();
if (node == null) {
return null;
}
PsiType nodeType = TypesUtil.getPsiType(el, node.getElementType());
if (nodeType != null) {
return nodeType;
}
return TypesUtil.createType(CommonClassNames.JAVA_LANG_STRING, this);
}
@Override
public GrNamedArgument getNamedArgument() {
final PsiElement parent = getParent();
assert parent instanceof GrNamedArgument;
return (GrNamedArgument)parent;
}
@Override
public PsiElement setName(@NotNull String newName) {
PsiImplUtil.setName(newName, getNameElement());
return this;
}
}