blob: d2e1e210534b44119f1819c9036c2152f9427f38 [file] [log] [blame]
package com.intellij.structuralsearch.impl.matcher;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.psi.xml.*;
import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler;
import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler;
import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator;
import java.util.ArrayList;
import java.util.List;
/**
* @author Eugene.Kudelevsky
*/
public class XmlMatchingVisitor extends XmlElementVisitor {
private final GlobalMatchingVisitor myMatchingVisitor;
private final boolean myCaseSensitive;
public XmlMatchingVisitor(GlobalMatchingVisitor matchingVisitor) {
myMatchingVisitor = matchingVisitor;
myCaseSensitive = myMatchingVisitor.getMatchContext().getOptions().isCaseSensitiveMatch();
}
@Override
public void visitElement(final PsiElement element) {
myMatchingVisitor.setResult(element.textMatches(element));
}
@Override public void visitXmlAttribute(XmlAttribute attribute) {
final XmlAttribute another = (XmlAttribute)myMatchingVisitor.getElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(attribute.getName());
myMatchingVisitor.setResult(matches(attribute.getName(), another.getName()) || isTypedVar);
if (myMatchingVisitor.getResult()) {
myMatchingVisitor.setResult(myMatchingVisitor.match(attribute.getValueElement(), another.getValueElement()));
}
if (myMatchingVisitor.getResult() && isTypedVar) {
MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(attribute.getName());
myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(another, myMatchingVisitor.getMatchContext()));
}
}
@Override public void visitXmlAttributeValue(XmlAttributeValue value) {
final XmlAttributeValue another = (XmlAttributeValue)myMatchingVisitor.getElement();
final String text = value.getValue();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(text);
MatchingHandler handler;
if (isTypedVar && (handler = myMatchingVisitor.getMatchContext().getPattern().getHandler( text )) instanceof SubstitutionHandler) {
String text2 = another.getText();
int offset = text2.length() > 0 && ( text2.charAt(0) == '"' || text2.charAt(0) == '\'') ? 1:0;
myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(another, offset, text2.length() - offset,
myMatchingVisitor.getMatchContext()));
} else {
myMatchingVisitor.setResult(matches(text, another.getValue()));
}
}
@Override public void visitXmlTag(XmlTag tag) {
final XmlTag another = (XmlTag)myMatchingVisitor.getElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(tag.getName());
myMatchingVisitor.setResult((matches(tag.getName(), another.getName()) || isTypedVar) &&
myMatchingVisitor.matchInAnyOrder(tag.getAttributes(), another.getAttributes()));
if(myMatchingVisitor.getResult()) {
final XmlTagChild[] contentChildren = tag.getValue().getChildren();
if (contentChildren.length > 0) {
PsiElement[] patternNodes = contentChildren;
PsiElement[] matchedNodes = another.getValue().getChildren();
if (contentChildren.length != 1) {
patternNodes = expandXmlTexts(patternNodes);
matchedNodes = expandXmlTexts(matchedNodes);
}
myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(
new ArrayBackedNodeIterator(patternNodes),
new ArrayBackedNodeIterator(matchedNodes)
));
}
}
if (myMatchingVisitor.getResult() && isTypedVar) {
MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler( tag.getName() );
myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(another, myMatchingVisitor.getMatchContext()));
}
}
private static PsiElement[] expandXmlTexts(PsiElement[] children) {
List<PsiElement> result = new ArrayList<PsiElement>(children.length);
for(PsiElement c:children) {
if (c instanceof XmlText) {
for(PsiElement p:c.getChildren()) {
if (!(p instanceof PsiWhiteSpace)) result.add(p);
}
} else if (!(c instanceof PsiWhiteSpace)) {
result.add(c);
}
}
return PsiUtilCore.toPsiElementArray(result);
}
@Override public void visitXmlText(XmlText text) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(text.getFirstChild(), myMatchingVisitor.getElement().getFirstChild()));
}
@Override public void visitXmlToken(XmlToken token) {
if (token.getTokenType() == XmlTokenType.XML_DATA_CHARACTERS) {
String text = token.getText();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(text);
if (isTypedVar) {
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(token, myMatchingVisitor.getElement()));
} else {
myMatchingVisitor.setResult(matches(text, myMatchingVisitor.getElement().getText()));
}
}
}
private boolean matches(String a, String b) {
return myCaseSensitive ? a.equals(b) : a.equalsIgnoreCase(b);
}
}