diff options
Diffstat (limited to 'platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java')
-rw-r--r-- | platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java new file mode 100644 index 000000000000..d2e1e210534b --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java @@ -0,0 +1,130 @@ +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); + } +} |