SSR: scope matching for xml/html (IDEA-190055)

This commit is contained in:
Bas Leijdekkers
2018-04-11 20:36:04 +02:00
parent 767a0c64a8
commit 44ce044871
5 changed files with 50 additions and 35 deletions
@@ -51,6 +51,12 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile {
return element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_NAME;
}
@NotNull
@Override
public String getTypedVarString(PsiElement element) {
return element instanceof XmlText ? element.getText().trim() : super.getTypedVarString(element);
}
@NotNull
@Override
public NodeFilter getLexicalNodesFilter() {
@@ -85,8 +91,8 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile {
boolean physical) {
final String ext = extension != null ? extension : fileType.getDefaultExtension();
String text1 = context == PatternTreeContext.File ? text : "<QQQ>" + text + "</QQQ>";
final PsiFile fileFromText = PsiFileFactory.getInstance(project)
.createFileFromText("dummy." + ext, fileType, text1, LocalTimeCounter.currentTime(), physical, true);
final PsiFile fileFromText =
PsiFileFactory.getInstance(project).createFileFromText("dummy." + ext, fileType, text1, LocalTimeCounter.currentTime(), physical, true);
final XmlDocument document = HtmlUtil.getRealXmlDocument(((XmlFile)fileFromText).getDocument());
if (context == PatternTreeContext.File) {
@@ -147,13 +153,13 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile {
@Override
public StructuralReplaceHandler getReplaceHandler(@NotNull ReplacementContext context) {
return new MyReplaceHandler(context);
return new XmlReplaceHandler(context);
}
private static class MyReplaceHandler extends StructuralReplaceHandler {
private static class XmlReplaceHandler extends StructuralReplaceHandler {
private final ReplacementContext myContext;
MyReplaceHandler(ReplacementContext context) {
XmlReplaceHandler(ReplacementContext context) {
myContext = context;
}
@@ -1,3 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch.impl.matcher;
import com.intellij.structuralsearch.impl.matcher.strategies.XmlMatchingStrategy;
@@ -17,6 +18,6 @@ public class XmlCompiledPattern extends CompiledPattern {
}
public boolean isTypedVar(final String str) {
return str.startsWith(XML_TYPED_VAR_PREFIX);
return str.trim().startsWith(XML_TYPED_VAR_PREFIX);
}
}
@@ -8,6 +8,7 @@ import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.xml.*;
import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler;
import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIterator;
import com.intellij.xml.util.XmlUtil;
/**
* @author Eugene.Kudelevsky
@@ -21,16 +22,15 @@ public class XmlMatchingVisitor extends XmlElementVisitor {
@Override public void visitXmlAttribute(XmlAttribute attribute) {
final XmlAttribute another = (XmlAttribute)myMatchingVisitor.getElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(attribute.getName());
if (!myMatchingVisitor.setResult(isTypedVar || myMatchingVisitor.matchText(attribute.getName(), another.getName()))) return;
final XmlAttributeValue valueElement = attribute.getValueElement();
if (valueElement != null && !myMatchingVisitor.setResult(myMatchingVisitor.match(valueElement, another.getValueElement()))) return;
if (isTypedVar) {
final SubstitutionHandler handler =
(SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(attribute.getName());
myMatchingVisitor.setResult(handler.handle(another, myMatchingVisitor.getMatchContext()));
myMatchingVisitor.getMatchContext().pushResult();
final XmlElement name = attribute.getNameElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(name);
try {
if (!myMatchingVisitor.setResult(isTypedVar || myMatchingVisitor.matchText(name, another.getNameElement()))) return;
final XmlAttributeValue valueElement = attribute.getValueElement();
myMatchingVisitor.setResult(valueElement == null || myMatchingVisitor.matchSingle(valueElement, another.getValueElement()));
} finally {
myMatchingVisitor.scopeMatch(name, isTypedVar, another);
}
}
@@ -50,7 +50,9 @@ public class XmlMatchingVisitor extends XmlElementVisitor {
@Override public void visitXmlTag(XmlTag tag) {
final XmlTag another = (XmlTag)myMatchingVisitor.getElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(tag.getName());
final CompiledPattern pattern = myMatchingVisitor.getMatchContext().getPattern();
final XmlToken name = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_NAME);
final boolean isTypedVar = pattern.isTypedVar(name);
if (!myMatchingVisitor.setResult((isTypedVar || myMatchingVisitor.matchText(tag.getName(), another.getName())) &&
myMatchingVisitor.matchInAnyOrder(tag.getAttributes(), another.getAttributes()))) return;
@@ -63,11 +65,9 @@ public class XmlMatchingVisitor extends XmlElementVisitor {
}
if (isTypedVar) {
final PsiElement[] children = another.getChildren();
if (children.length > 1) {
final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(tag.getName());
myMatchingVisitor.setResult(handler.handle(children[1], myMatchingVisitor.getMatchContext()));
}
final SubstitutionHandler handler = (SubstitutionHandler)pattern.getHandler(name);
myMatchingVisitor.setResult(handler.handle(XmlUtil.getTokenOfType(another, XmlTokenType.XML_NAME),
myMatchingVisitor.getMatchContext()));
}
}
@@ -1,13 +1,10 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch.impl.matcher.compiler;
import com.intellij.psi.PsiElement;
import com.intellij.psi.XmlRecursiveElementVisitor;
import com.intellij.psi.XmlRecursiveElementWalkingVisitor;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
import com.intellij.psi.xml.XmlToken;
import com.intellij.psi.xml.*;
import com.intellij.structuralsearch.impl.matcher.CompiledPattern;
import com.intellij.structuralsearch.impl.matcher.filters.TagValueFilter;
import com.intellij.structuralsearch.impl.matcher.handlers.TopLevelMatchingHandler;
@@ -59,13 +56,16 @@ public class XmlCompilingVisitor extends XmlRecursiveElementVisitor {
}
}
@Override public void visitElement(PsiElement element) {
@Override
public void visitElement(PsiElement element) {
myCompilingVisitor.handle(element);
super.visitElement(element);
}
@Override
public void visitXmlToken(XmlToken token) {}
public void visitXmlToken(XmlToken token) {
if (token.getTokenType() == XmlTokenType.XML_NAME) super.visitXmlToken(token);
}
@Override
public void visitXmlText(XmlText text) {
@@ -39,6 +39,14 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase {
String in = "<img src=\"foobar.jpg\" alt=\"alt\" width=\"108\" height=\"71\" style=\"display:block\" >";
assertEquals(1, findMatchesCount(in, "<img alt '_other+ >", StdFileTypes.HTML));
assertEquals(1, findMatchesCount(in, "<img '_alt:alt = \"'_value\" '_other+ >", StdFileTypes.HTML));
assertEquals(1, findMatchesCount(in, "<img '_name{2,100} = '_value >", StdFileTypes.HTML));
String in2 = "<input readonly>" +
"<input readonly>" +
"<input type=button>";
assertEquals("should find tags without any attributes without value", 1, findMatchesCount(in2, "<input '_name{0,0} = '_value{0,0} >", StdFileTypes.HTML));
assertEquals("should find tags with any attributes without value", 2, findMatchesCount(in2, "<input '_name{1,1}='_value{0,0} >", StdFileTypes.HTML));
}
public void testHtmlSearchCaseInsensitive() {
@@ -161,10 +169,10 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase {
return PlatformTestUtil.getCommunityPath() + "/platform/structuralsearch/testData/html/";
}
//public void testXmlSearch2() {
// String s1 = "<body><p class=\"11\"> AAA </p><p class=\"22\"></p> <p> ZZZ </p> <p/> <p/> <p/> </body>";
// String s2 = "<p '_a?=\"'_t:[ regex( 11 ) ]\"> 'content? </p>";
//
// assertEquals(5,findMatchesCount(s1,s2,false,StdFileTypes.XML));
//}
public void testXmlSearch2() {
String s1 = "<body><p class=\"11\"> AAA </p><p class=\"22\"></p> <p> ZZZ </p> <p/> <p/> <p/> </body>";
String s2 = "<p '_a{0,0}=\"'_t:[ regex( 11 ) ]\"> 'content? </p>";
assertEquals(5, findMatchesCount(s1, s2, StdFileTypes.XML));
}
}