blob: ade3ec5ecdb059faa46bb2bb94f4c3b9ad277bad [file] [log] [blame]
/*
* Copyright 2007 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.plugins.relaxNG.references;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.patterns.PatternCondition;
import com.intellij.patterns.XmlAttributeValuePattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.AttributeValueSelfReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ProcessingContext;
import com.intellij.xml.XmlAttributeDescriptor;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
import static com.intellij.patterns.XmlPatterns.xmlAttribute;
import static com.intellij.patterns.XmlPatterns.xmlAttributeValue;
public class IdRefProvider extends PsiReferenceProvider {
public static final HasIdRefTypeCondition HAS_ID_REF_TYPE = new HasIdRefTypeCondition();
public static final HasIdTypeCondition HAS_ID_TYPE = new HasIdTypeCondition();
@Override
@NotNull
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
final XmlAttributeValue value = (XmlAttributeValue)element;
if (hasIdRefType(value)) {
return new PsiReference[]{
new IdReference(value)
};
} else if (hasIdType(value)) {
return new PsiReference[]{
new AttributeValueSelfReference(element)
};
}
return PsiReference.EMPTY_ARRAY;
}
private static class IdReference extends PsiReferenceBase<XmlAttributeValue> {
private static final Key<XmlAttributeValue> TARGET = Key.create("target");
private static final Key<Set<XmlAttributeValue>> VARIANTS = Key.create("variants");
private static final XmlAttributeValuePattern PATTERN = xmlAttributeValue().withParent(xmlAttribute()).with(HAS_ID_TYPE);
private final AttributeValueCondition myCondition;
public IdReference(XmlAttributeValue element) {
super(element, TextRange.from(1, element.getTextLength() - 2), true);
myCondition = new AttributeValueCondition(element.getValue());
}
@Override
public PsiElement resolve() {
final ProcessingContext context = new ProcessingContext();
final ResolvingVisitor visitor = new ResolvingVisitor(PATTERN.with(myCondition).save(TARGET), context) {
@Override
public void visitXmlTag(XmlTag tag) {
super.visitXmlTag(tag);
if (shouldContinue()) {
visitSubTags(tag);
}
}
@Override
protected boolean shouldContinue() {
return context.get(TARGET) == null;
}
};
process(visitor);
return context.get(TARGET);
}
private void process(ResolvingVisitor visitor) {
final XmlDocument document = PsiTreeUtil.getParentOfType(getElement(), XmlDocument.class);
if (document != null) {
visitor.execute(document);
}
}
@Override
@NotNull
public Object[] getVariants() {
final ProcessingContext context = new ProcessingContext();
context.put(VARIANTS, new HashSet<XmlAttributeValue>());
final ResolvingVisitor visitor = new ResolvingVisitor(PATTERN.with(AddValueCondition.create(VARIANTS)), context) {
@Override
public void visitXmlTag(XmlTag tag) {
super.visitXmlTag(tag);
visitSubTags(tag);
}
};
process(visitor);
return AttributeValueFunction.toStrings(context.get(VARIANTS));
}
}
private static boolean hasIdType(XmlAttributeValue xmlAttributeValue) {
final XmlAttributeDescriptor descriptor = ((XmlAttribute)xmlAttributeValue.getParent()).getDescriptor();
return descriptor != null && descriptor.hasIdType();
}
private static boolean hasIdRefType(XmlAttributeValue xmlAttributeValue) {
final XmlAttributeDescriptor descriptor = ((XmlAttribute)xmlAttributeValue.getParent()).getDescriptor();
return descriptor != null && descriptor.hasIdRefType();
}
static class HasIdTypeCondition extends PatternCondition<XmlAttributeValue> {
public HasIdTypeCondition() {
super("IdType");
}
@Override
public boolean accepts(@NotNull XmlAttributeValue xmlAttributeValue, ProcessingContext context) {
return hasIdType(xmlAttributeValue);
}
}
static class HasIdRefTypeCondition extends PatternCondition<XmlAttributeValue> {
public HasIdRefTypeCondition() {
super("IdRef");
}
@Override
public boolean accepts(@NotNull XmlAttributeValue xmlAttributeValue, ProcessingContext context) {
return hasIdRefType(xmlAttributeValue);
}
}
}