RegExp: don't suggests simplifying replacements that are not equivalent in Unicode mode (IDEA-290490)

GitOrigin-RevId: cb85ddaee91cb6ff13596603e10fce7a55eac07c
This commit is contained in:
Bas Leijdekkers
2022-05-29 13:35:38 +00:00
committed by intellij-monorepo-bot
parent d213a56e85
commit be71678b09
3 changed files with 14 additions and 102 deletions
@@ -3,11 +3,11 @@
Reports regular expressions that can be simplified.
<p><b>Example:</b></p>
<pre><code>
[a] [0-9] xx* [ah-hz]
[a] xx* [ah-hz]
</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>
a \d x+ [ahz]
a x+ [ahz]
</code></pre>
<!-- tooltip end -->
<p><small>New in 2022.1</small>
@@ -19,8 +19,7 @@ import org.jetbrains.annotations.NotNull;
public class RegExpSimplifiableInspection extends LocalInspectionTool {
@Override
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
boolean isOnTheFly) {
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new RegExpSimplifiableVisitor(holder);
}
@@ -28,7 +27,6 @@ public class RegExpSimplifiableInspection extends LocalInspectionTool {
private final ProblemsHolder myHolder;
RegExpSimplifiableVisitor(@NotNull ProblemsHolder holder) {
super();
myHolder = holder;
}
@@ -58,23 +56,6 @@ public class RegExpSimplifiableInspection extends LocalInspectionTool {
registerProblem(regExpClass, text);
}
}
else if (isDigitRange(element)) {
// [^0-9] -> \D
registerProblem(regExpClass, "\\D");
}
}
else {
if (isWordCharClassExpression(elements)) {
// [^0-9a-zA-Z_] -> \W
registerProblem(regExpClass, "\\W");
return;
}
for (RegExpClassElement element : elements) {
if (isDigitRange(element)) {
// [^0-9abc] -> [^\dabc]
registerProblem(element, "\\d");
}
}
}
}
else {
@@ -87,25 +68,6 @@ public class RegExpSimplifiableInspection extends LocalInspectionTool {
registerProblem(regExpClass, element.getUnescapedText());
}
}
else {
if (isDigitRange(element)) {
// [0-9] -> \d
registerProblem(regExpClass, "\\d");
}
}
}
else {
if (isWordCharClassExpression(elements)) {
// [0-9a-zA-Z_] -> \w
registerProblem(regExpClass, "\\w");
return;
}
for (RegExpClassElement element : elements) {
// [0-9abc] -> [\dabc]
if (isDigitRange(element)) {
registerProblem(element, "\\d");
}
}
}
}
}
@@ -119,7 +81,7 @@ public class RegExpSimplifiableInspection extends LocalInspectionTool {
}
PsiElement sibling = closure.getPrevSibling();
RegExpAtom atom = closure.getAtom();
if (sibling instanceof RegExpElement && atom.getClass() == sibling.getClass() && sibling.textMatches(atom) && !containsGroup(atom)) {
if (sibling instanceof RegExpElement && atom.getClass() == sibling.getClass() && sibling.textMatches(atom) && !containsGroup(atom)) {
final String text = atom.getUnescapedText() + '+';
myHolder.registerProblem(closure.getParent(),
TextRange.from(sibling.getStartOffsetInParent(), sibling.getTextLength() + closure.getTextLength()),
@@ -191,60 +153,6 @@ public class RegExpSimplifiableInspection extends LocalInspectionTool {
return atom instanceof RegExpGroup || PsiTreeUtil.findChildOfType(atom, RegExpGroup.class) != null;
}
private static boolean isDigitRange(RegExpElement element) {
if (!(element instanceof RegExpCharRange)) {
return false;
}
final RegExpCharRange charRange = (RegExpCharRange)element;
final RegExpChar from = charRange.getFrom();
final RegExpChar to = charRange.getTo();
return from.getValue() == '0' && to != null && to.getValue() == '9';
}
private static boolean isWordCharClassExpression(RegExpClassElement[] elements) {
if (elements.length != 4) {
return false;
}
boolean lowerCaseChars = false;
boolean upperCaseChars = false;
boolean digits = false;
boolean underscore = false;
for (RegExpClassElement element : elements) {
if (element instanceof RegExpChar) {
final RegExpChar aChar = (RegExpChar)element;
if (aChar.getValue() == '_') {
underscore = true;
}
}
else if (element instanceof RegExpSimpleClass) {
final RegExpSimpleClass simpleClass = (RegExpSimpleClass)element;
if (simpleClass.getKind() == RegExpSimpleClass.Kind.DIGIT) {
digits = true;
}
}
else if (element instanceof RegExpCharRange) {
final RegExpCharRange range = (RegExpCharRange)element;
final RegExpChar from = range.getFrom();
final RegExpChar to = range.getTo();
if (to == null) {
break;
}
final int fromValue = from.getValue();
final int toValue = to.getValue();
if (fromValue == '0' && toValue == '9') {
digits = true;
}
else if (fromValue == 'A' && toValue == 'Z') {
upperCaseChars = true;
}
else if (fromValue == 'a' && toValue == 'z') {
lowerCaseChars = true;
}
}
}
return underscore && digits && lowerCaseChars && upperCaseChars;
}
private static String getInverseSimpleClassText(RegExpSimpleClass simpleClass) {
switch (simpleClass.getKind()) {
case DIGIT:
@@ -22,19 +22,19 @@ public class RegExpSimplifiableInspectionTest extends RegExpInspectionTestCase {
}
public void testNegatedDigitRange() {
doTest("[^0-9]", "\\D");
highlightTest("[^0-9]"); // no warn; replacing with \D is not equivalent in Unicode context
}
public void testNegatedWordClassCharExpression() {
doTest("[^0-9a-zA-Z_]", "\\W");
highlightTest("[^0-9a-zA-Z_]"); // no warn; replacing with \W is not equivalent in Unicode context
}
public void testDigitRange() {
doTest("[^0-9abc]", 2, 3, "\\d", "[^\\dabc]");
highlightTest("[^0-9abc]"); // no warn; replacing with [^\dabc] is not equivalent in Unicode context
}
public void testDigitRange2() {
doTest("[0-9abc]", 1, 3, "\\d", "[\\dabc]");
highlightTest("[0-9abc]"); // no warn; replacing with \d is not equivalent in Unicode context
}
public void testSingleElementClass() {
@@ -46,11 +46,15 @@ public class RegExpSimplifiableInspectionTest extends RegExpInspectionTestCase {
}
public void testSimpleDigitRange() {
doTest("[0-9]", "\\d");
highlightTest("[0-9]"); // no warn; replacing with \d is not equivalent in Unicode context
}
public void testWordCharClassExpression() {
doTest("[0-9a-zA-Z_]", "\\w");
highlightTest("[0-9a-zA-Z_]"); // no warn; replacing with \w is not equivalent in Unicode context
}
public void testProperty() {
doTest("\\p{IsDigit}", "\\d");
}
public void testStarToPlusNoWarm() {