blob: 9e0c0c5ecb034aa0907903b11e974a702e576e97 [file] [log] [blame]
/*
* Copyright 2005 Sascha Weinreuter
*
* 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.intellij.lang.xpath.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.intellij.lang.xpath.XPathFileType;
import org.intellij.lang.xpath.XPathTokenTypes;
import org.intellij.lang.xpath.context.VariableContext;
import org.intellij.lang.xpath.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class XPathVariableReferenceImpl extends XPathElementImpl implements XPathVariableReference {
private static final TokenSet QNAME_FILTER = TokenSet.create(XPathTokenTypes.VARIABLE_PREFIX, XPathTokenTypes.VARIABLE_NAME);
public XPathVariableReferenceImpl(ASTNode node) {
super(node);
}
@NotNull
public String getReferencedName() {
return getText().substring(1);
}
@NotNull
public XPathType getType() {
final XPathVariable xPathVariable = resolve();
if (xPathVariable != null) {
return xPathVariable.getType();
}
return XPathType.UNKNOWN;
}
public PsiReference getReference() {
return this;
}
public PsiElement getElement() {
return this;
}
public int getTextOffset() {
return getTextRange().getStartOffset() + 1;
}
public TextRange getRangeInElement() {
return TextRange.from(1, getTextLength() - 1);
}
@Nullable
public XPathVariable resolve() {
if (getContainingFile().getLanguage() == XPathFileType.XPATH2.getLanguage()) {
XPathVariableHolder f = PsiTreeUtil.getParentOfType(this, XPathVariableHolder.class, true);
while (f != null) {
final XPathVariable variable = findVariable(f.getVariables(), getReferencedName());
if (variable != null) {
return variable;
}
f = PsiTreeUtil.getParentOfType(f, XPathVariableHolder.class, true);
}
}
final VariableContext context = getXPathContext().getVariableContext();
if (context == null) {
return null;
}
return context.resolve(this);
}
@Nullable
private static XPathVariable findVariable(XPathVariableDeclaration[] declarations, String referencedName) {
for (XPathVariableDeclaration decl : declarations) {
final XPathVariable v = decl.getVariable();
if (v != null) {
if (referencedName.equals(v.getName())) {
return v;
}
}
}
return null;
}
@NotNull
public String getCanonicalText() {
return getText();
}
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
renameTo(newElementName);
return this;
}
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
renameTo(((PsiNamedElement)element).getName());
return this;
}
private void renameTo(String newElementName) {
final XPathVariableReference child = XPathChangeUtil.createVariableReference(this, newElementName);
final PrefixedNameImpl newName = ((PrefixedNameImpl)child.getQName());
final PrefixedNameImpl oldName = ((PrefixedNameImpl)getQName());
assert newName != null;
assert oldName != null;
final ASTNode localNode = newName.getLocalNode();
getNode().replaceChild(oldName.getLocalNode(), localNode);
}
public boolean isReferenceTo(PsiElement element) {
if (element instanceof XPathVariable) {
final XPathVariable resolved = resolve();
if (getReferencedName().equals(((XPathVariable)element).getName())) {
if (element.equals(resolved)) {
return true;
}
}
}
final VariableContext context = getXPathContext().getVariableContext();
if (context != null) {
return context.isReferenceTo(element, this);
}
return false;
}
@NotNull
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
public boolean isSoft() {
return true;
}
@Nullable
public PrefixedName getQName() {
final ASTNode[] nodes = getNode().getChildren(QNAME_FILTER);
if (nodes.length == 1) {
return new PrefixedNameImpl(nodes[0]);
} else if (nodes.length == 2) {
return new PrefixedNameImpl(nodes[0], nodes[1]);
}
return null;
}
public int hashCode() {
return getReferencedName().hashCode();
}
@Override
@SuppressWarnings({ "EqualsWhichDoesntCheckParameterClass" })
public boolean equals(Object obj) {
return obj == this;
}
public void accept(XPathElementVisitor visitor) {
visitor.visitXPathVariableReference(this);
}
}