SSR: split utility class to make testing easier

GitOrigin-RevId: 4cfbc0832ff5b223fa8b60a238e74dc2e9f3067f
This commit is contained in:
Bas Leijdekkers
2022-08-24 16:29:32 +00:00
committed by intellij-monorepo-bot
parent 597deabb24
commit c7c709a23a
15 changed files with 129 additions and 115 deletions
@@ -671,7 +671,7 @@ public final class JavaStructuralSearchProfile extends StructuralSearchProfile {
@Override
public void visitElement(@NotNull PsiElement element) {
final String type = element.getText();
if (StructuralSearchUtil.isTypedVariable(type)) {
if (MatchUtil.isTypedVariable(type)) {
final ParameterInfo typeInfo = builder.findParameterization(element);
if (typeInfo != null) {
typeInfo.setArgumentContext(false);
@@ -14,6 +14,7 @@ import com.intellij.psi.util.JavaPsiPatternUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.structuralsearch.MatchOptions;
import com.intellij.structuralsearch.MatchUtil;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.impl.matcher.handlers.LiteralWithSubstitutionHandler;
import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler;
@@ -106,8 +107,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
myMatchingVisitor.setResult(handler.match(comment, other, myMatchingVisitor.getMatchContext()));
}
else {
myMatchingVisitor.setResult(myMatchingVisitor.matchText(StructuralSearchUtil.normalize(JavaMatchUtil.getCommentText(comment)),
StructuralSearchUtil.normalize(JavaMatchUtil.getCommentText(other))));
myMatchingVisitor.setResult(myMatchingVisitor.matchText(MatchUtil.normalize(JavaMatchUtil.getCommentText(comment)),
MatchUtil.normalize(JavaMatchUtil.getCommentText(other))));
}
}
@@ -1218,8 +1219,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor {
if ((value1 instanceof String || value1 instanceof Character) && (value2 instanceof String || value2 instanceof Character)) {
String patternValue = value1.toString();
if (!patternValue.isEmpty() && patternValue.equals(patternValue.trim())) {
myMatchingVisitor.setResult(myMatchingVisitor.matchText(StructuralSearchUtil.normalize(patternValue),
StructuralSearchUtil.normalize(value2.toString())));
myMatchingVisitor.setResult(myMatchingVisitor.matchText(MatchUtil.normalize(patternValue),
MatchUtil.normalize(value2.toString())));
}
else {
myMatchingVisitor.setResult(myMatchingVisitor.matchText(patternValue, value2.toString()));
@@ -15,8 +15,8 @@ import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.structuralsearch.MalformedPatternException;
import com.intellij.structuralsearch.MatchUtil;
import com.intellij.structuralsearch.SSRBundle;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.impl.matcher.CompiledPattern;
import com.intellij.structuralsearch.impl.matcher.JavaCompiledPattern;
import com.intellij.structuralsearch.impl.matcher.JavaMatchUtil;
@@ -508,7 +508,7 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor {
final SubstitutionHandler substitutionHandler =
new SubstitutionHandler("__" + referenceText.replace('.', '_'), false, classQualifier ? 0 : 1, 1, true);
final boolean caseSensitive = myCompilingVisitor.getContext().getOptions().isCaseSensitiveMatch();
substitutionHandler.setPredicate(new RegExpPredicate(StructuralSearchUtil.shieldRegExpMetaChars(referenceText),
substitutionHandler.setPredicate(new RegExpPredicate(MatchUtil.shieldRegExpMetaChars(referenceText),
caseSensitive, null, false, false));
myCompilingVisitor.getContext().getPattern().setHandler(expr, substitutionHandler);
}
@@ -3,7 +3,7 @@ package com.intellij.structuralsearch.impl.matcher.predicates;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.MatchUtil;
import com.intellij.structuralsearch.impl.matcher.MatchContext;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
@@ -42,14 +42,14 @@ public class ExprTypePredicate extends MatchPredicate {
while (true) {
int index = types.indexOf('|', pos);
if (index == -1) break;
String token = StructuralSearchUtil.normalizeWhiteSpace(types.substring(pos, index));
String token = MatchUtil.normalizeWhiteSpace(types.substring(pos, index));
if (!token.isEmpty()) {
result.add(token);
}
pos = index + 1;
}
if (pos < types.length()) {
result.add(StructuralSearchUtil.normalizeWhiteSpace(types.substring(pos)));
result.add(MatchUtil.normalizeWhiteSpace(types.substring(pos)));
}
return result;
}
@@ -0,0 +1,95 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.structuralsearch;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.text.Normalizer;
import java.util.regex.Pattern;
/**
* @author Bas Leijdekkers
*/
public class MatchUtil {
private static final String REG_EXP_META_CHARS = ".$|()[]{}^?*+\\";
private static final Pattern ACCENTS = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
public static boolean isTypedVariable(@NotNull String name) {
return name.length() > 1 && name.charAt(0) == '$' && name.charAt(name.length() - 1) == '$';
}
public static boolean containsRegExpMetaChar(String s) {
return s.chars().anyMatch(MatchUtil::isRegExpMetaChar);
}
public static boolean isRegExpMetaChar(int ch) {
return REG_EXP_META_CHARS.indexOf(ch) >= 0;
}
@NotNull
public static String shieldRegExpMetaChars(@NotNull String word) {
return shieldRegExpMetaChars(word, new StringBuilder(word.length())).toString();
}
public static String makeExtremeSpacesOptional(String word) {
if (word.trim().isEmpty()) return word;
String result = word;
if (word.startsWith(" ")) result = "(?:\\s|\\b)" + result.substring(1);
if (word.endsWith(" ")) result = result.substring(0, result.length() - 1) + "(?:\\s|\\b)";
return result;
}
@NotNull
public static StringBuilder shieldRegExpMetaChars(String word, StringBuilder out) {
for (int i = 0, length = word.length(); i < length; ++i) {
if (isRegExpMetaChar(word.charAt(i))) {
out.append("\\");
}
out.append(word.charAt(i));
}
return out;
}
public static Pattern[] createPatterns(String[] prefixes) {
final Pattern[] patterns = new Pattern[prefixes.length];
for (int i = 0; i < prefixes.length; i++) {
final String s = shieldRegExpMetaChars(prefixes[i]);
patterns[i] = Pattern.compile("\\b(" + s + "\\w+)\\b");
}
return patterns;
}
@NotNull
public static String normalizeWhiteSpace(@NotNull String text) {
text = text.trim();
final StringBuilder result = new StringBuilder();
boolean white = false;
for (int i = 0, length = text.length(); i < length; i++) {
final char c = text.charAt(i);
if (StringUtil.isWhiteSpace(c)) {
if (!white) {
result.append(' ');
white = true;
}
}
else {
white = false;
result.append(c);
}
}
return result.toString();
}
@NotNull
public static String stripAccents(@NotNull String input) {
return ACCENTS.matcher(Normalizer.normalize(input, Normalizer.Form.NFD)).replaceAll("");
}
@NotNull
public static String normalize(@NotNull String text) {
return stripAccents(normalizeWhiteSpace(text));
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2020 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-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.structuralsearch;
import com.intellij.openapi.util.InvalidDataException;
@@ -138,7 +138,7 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
for (int i = 0, length = regexp.length(); i < length; i++) {
final int c = regexp.codePointAt(i);
if (c == '.') {
if (i == length - 1 || !StructuralSearchUtil.isRegExpMetaChar(regexp.codePointAt(i + 1))) {
if (i == length - 1 || !MatchUtil.isRegExpMetaChar(regexp.codePointAt(i + 1))) {
result.append('.'); // consider dot not followed by other meta char a mistake
}
else {
@@ -163,7 +163,7 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
else if (c == '(' || c == ')') {
// do nothing
}
else if (StructuralSearchUtil.isRegExpMetaChar(c)) {
else if (MatchUtil.isRegExpMetaChar(c)) {
return ""; // can't convert
}
else {
@@ -180,7 +180,7 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
if (result.length() > 0) {
result.append('|');
}
StructuralSearchUtil.shieldRegExpMetaChars(type.trim(), result);
MatchUtil.shieldRegExpMetaChars(type.trim(), result);
}
return result.toString();
}
@@ -278,7 +278,7 @@ public abstract class StructuralSearchProfileBase extends StructuralSearchProfil
if (StringUtil.isQuotedString(value)) {
if (mySubstitutionPatterns == null) {
final String[] prefixes = myGlobalVisitor.getContext().getPattern().getTypedVarPrefixes();
mySubstitutionPatterns = StructuralSearchUtil.createPatterns(prefixes);
mySubstitutionPatterns = MatchUtil.createPatterns(prefixes);
}
for (Pattern substitutionPattern : mySubstitutionPatterns) {
@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.structuralsearch;
import com.intellij.ide.highlighter.XmlFileType;
@@ -7,7 +7,6 @@ import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.*;
import com.intellij.openapi.util.text.NaturalComparator;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.structuralsearch.plugin.ui.Configuration;
import com.intellij.util.SmartList;
@@ -15,17 +14,13 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.Normalizer;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* @author Eugene.Kudelevsky
*/
public final class StructuralSearchUtil {
private static final String REG_EXP_META_CHARS = ".$|()[]{}^?*+\\";
private static final Pattern ACCENTS = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
private static final Comparator<? super Configuration> CONFIGURATION_COMPARATOR =
Comparator.comparing(Configuration::getCategory, NaturalComparator.INSTANCE)
.thenComparing(Configuration::getName, NaturalComparator.INSTANCE);
@@ -137,10 +132,6 @@ public final class StructuralSearchUtil {
return ourDefaultFileType;
}
public static boolean isTypedVariable(@NotNull String name) {
return name.length() > 1 && name.charAt(0) == '$' && name.charAt(name.length() - 1) == '$';
}
public static Collection<LanguageFileType> getSuitableFileTypes() {
return Collections.unmodifiableCollection(getNames2FileTypes().values());
}
@@ -168,50 +159,6 @@ public final class StructuralSearchUtil {
return getNames2FileTypes().get(name);
}
public static boolean containsRegExpMetaChar(String s) {
return s.chars().anyMatch(StructuralSearchUtil::isRegExpMetaChar);
}
public static boolean isRegExpMetaChar(int ch) {
return REG_EXP_META_CHARS.indexOf(ch) >= 0;
}
@NotNull
public static String shieldRegExpMetaChars(@NotNull String word) {
return shieldRegExpMetaChars(word, new StringBuilder(word.length())).toString();
}
public static String makeExtremeSpacesOptional(String word) {
if (word.trim().isEmpty()) return word;
String result = word;
if (word.startsWith(" ")) result = "(?:\\s|\\b)" + result.substring(1);
if (word.endsWith(" ")) result = result.substring(0, result.length() - 1) + "(?:\\s|\\b)";
return result;
}
@NotNull
public static StringBuilder shieldRegExpMetaChars(String word, StringBuilder out) {
for (int i = 0, length = word.length(); i < length; ++i) {
if (isRegExpMetaChar(word.charAt(i))) {
out.append("\\");
}
out.append(word.charAt(i));
}
return out;
}
public static Pattern[] createPatterns(String[] prefixes) {
final Pattern[] patterns = new Pattern[prefixes.length];
for (int i = 0; i < prefixes.length; i++) {
final String s = shieldRegExpMetaChars(prefixes[i]);
patterns[i] = Pattern.compile("\\b(" + s + "\\w+)\\b");
}
return patterns;
}
public static List<Configuration> getPredefinedTemplates() {
if (ourPredefinedConfigurations == null) {
final List<Configuration> result = new ArrayList<>();
@@ -239,37 +186,6 @@ public final class StructuralSearchUtil {
return profile != null ? profile.getAlternativeText(matchedNode, previousText) : null;
}
@NotNull
public static String normalizeWhiteSpace(@NotNull String text) {
text = text.trim();
final StringBuilder result = new StringBuilder();
boolean white = false;
for (int i = 0, length = text.length(); i < length; i++) {
final char c = text.charAt(i);
if (StringUtil.isWhiteSpace(c)) {
if (!white) {
result.append(' ');
white = true;
}
}
else {
white = false;
result.append(c);
}
}
return result.toString();
}
@NotNull
public static String stripAccents(@NotNull String input) {
return ACCENTS.matcher(Normalizer.normalize(input, Normalizer.Form.NFD)).replaceAll("");
}
@NotNull
public static String normalize(@NotNull String text) {
return stripAccents(normalizeWhiteSpace(text));
}
public static PatternContext findPatternContextByID(@Nullable String id, @NotNull Language language) {
return findPatternContextByID(id, getProfileByLanguage(language));
}
@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.structuralsearch.impl.matcher;
import com.intellij.dupLocator.iterators.NodeIterator;
@@ -6,7 +6,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.xml.*;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.MatchUtil;
import com.intellij.structuralsearch.XmlMatchUtil;
import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler;
import com.intellij.structuralsearch.impl.matcher.iterators.ListNodeIterator;
@@ -125,8 +125,8 @@ public class XmlMatchingVisitor extends XmlElementVisitor {
myMatchingVisitor.getMatchContext()));
}
else {
myMatchingVisitor.setResult(myMatchingVisitor.matchText(StructuralSearchUtil.normalize(text.getText()),
StructuralSearchUtil.normalize(other.getCommentText())));
myMatchingVisitor.setResult(myMatchingVisitor.matchText(MatchUtil.normalize(text.getText()),
MatchUtil.normalize(other.getCommentText())));
}
}
}
@@ -5,6 +5,7 @@ import com.intellij.dupLocator.util.NodeFilter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.structuralsearch.MalformedPatternException;
import com.intellij.structuralsearch.MatchUtil;
import com.intellij.structuralsearch.StructuralSearchProfile;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.impl.matcher.CompiledPattern;
@@ -163,7 +164,7 @@ public class GlobalCompilingVisitor {
word = content.substring(start, matcher.start());
if (!word.isEmpty()) {
hasLiteralContent = true;
buf.append(StructuralSearchUtil.makeExtremeSpacesOptional(StructuralSearchUtil.shieldRegExpMetaChars(word)));
buf.append(MatchUtil.makeExtremeSpacesOptional(MatchUtil.shieldRegExpMetaChars(word)));
processTokenizedName(word, kind);
}
@@ -192,7 +193,7 @@ public class GlobalCompilingVisitor {
if (!word.isEmpty()) {
hasLiteralContent = true;
buf.append(StructuralSearchUtil.makeExtremeSpacesOptional(StructuralSearchUtil.shieldRegExpMetaChars(word)));
buf.append(MatchUtil.makeExtremeSpacesOptional(MatchUtil.shieldRegExpMetaChars(word)));
processTokenizedName(word, kind);
}
@@ -205,7 +205,7 @@ public final class PatternCompiler {
final Pattern[] patterns = new Pattern[applicablePrefixes.length];
for (int i = 0; i < applicablePrefixes.length; i++) {
patterns[i] = Pattern.compile(StructuralSearchUtil.shieldRegExpMetaChars(applicablePrefixes[i]) + "\\w+\\b");
patterns[i] = Pattern.compile(MatchUtil.shieldRegExpMetaChars(applicablePrefixes[i]) + "\\w+\\b");
}
final int[] varEndOffsets = findAllTypedVarOffsets(file, patterns);
@@ -3,6 +3,7 @@ package com.intellij.structuralsearch.impl.matcher.predicates;
import com.intellij.psi.PsiElement;
import com.intellij.structuralsearch.MalformedPatternException;
import com.intellij.structuralsearch.MatchUtil;
import com.intellij.structuralsearch.SSRBundle;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.impl.matcher.MatchContext;
@@ -32,7 +33,7 @@ public final class RegExpPredicate extends MatchPredicate {
}
public RegExpPredicate(@NotNull String regexp, boolean caseSensitive, String _baseHandlerName, boolean _wholeWords, boolean _target) {
couldBeOptimized = !StructuralSearchUtil.containsRegExpMetaChar(regexp);
couldBeOptimized = !MatchUtil.containsRegExpMetaChar(regexp);
if (!_wholeWords) {
simpleString = couldBeOptimized;
}
@@ -101,7 +101,7 @@ public final class ReplacementBuilder {
@Override
public void visitElement(@NotNull PsiElement element) {
final String text = element.getText();
if (StructuralSearchUtil.isTypedVariable(text)) {
if (MatchUtil.isTypedVariable(text)) {
final Collection<ParameterInfo> infos = findParameterization(Replacer.stripTypedVariableDecoration(text));
for (ParameterInfo info : infos) {
if (info.getElement() == null) {
@@ -183,7 +183,7 @@ public final class ReplacementBuilder {
public ParameterInfo findParameterization(PsiElement element) {
if (element == null) return null;
final String text = element.getText();
if (!StructuralSearchUtil.isTypedVariable(text)) return null;
if (!MatchUtil.isTypedVariable(text)) return null;
return ContainerUtil.find(findParameterization(Replacer.stripTypedVariableDecoration(text)), info -> info.getElement() == element);
}
}
@@ -5,13 +5,13 @@ import com.intellij.structuralsearch.MalformedPatternException;
import com.intellij.structuralsearch.MatchOptions;
import com.intellij.structuralsearch.MatchVariableConstraint;
import com.intellij.structuralsearch.plugin.ui.Configuration;
import com.intellij.testFramework.LightPlatformTestCase;
import junit.framework.TestCase;
import org.jetbrains.annotations.NotNull;
/**
* @author Bas Leijdekkers
*/
public class StringToConstraintsTransformerTest extends LightPlatformTestCase {
public class StringToConstraintsTransformerTest extends TestCase {
private MatchOptions myOptions;
@@ -6,7 +6,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.elementType
import com.intellij.structuralsearch.StructuralSearchUtil
import com.intellij.structuralsearch.MatchUtil
import com.intellij.structuralsearch.impl.matcher.CompiledPattern
import com.intellij.structuralsearch.impl.matcher.GlobalMatchingVisitor
import com.intellij.structuralsearch.impl.matcher.handlers.LiteralWithSubstitutionHandler
@@ -1019,8 +1019,8 @@ class KotlinMatchingVisitor(private val myMatchingVisitor: GlobalMatchingVisitor
)
}
else -> myMatchingVisitor.result = myMatchingVisitor.matchText(
StructuralSearchUtil.normalize(getCommentText(comment)),
StructuralSearchUtil.normalize(getCommentText(other))
MatchUtil.normalize(getCommentText(comment)),
MatchUtil.normalize(getCommentText(other))
)
}
}