[java-inspections] EscapedSpaceInspection: fix 'Fix all' action (do all the fixes in a single literal even without fix-all)

GitOrigin-RevId: d5fa9d51b3b8e911c599be1381b2a9e6a2041223
This commit is contained in:
Tagir Valeev
2022-07-29 17:55:08 +00:00
committed by intellij-monorepo-bot
parent 2c3779a08a
commit 94528b7c67
11 changed files with 85 additions and 40 deletions
@@ -0,0 +1,8 @@
// "Replace '\s' sequences with spaces" "true-preview"
class X {
void test(String str) {
if (str.matches(" a b c d")) {
}
}
}
@@ -0,0 +1,8 @@
// "Fix all 'Non-terminal use of '\s' escape sequence' problems in file" "true"
class X {
void test(String str) {
if (str.matches(" a b c d")) {
}
}
}
@@ -1,4 +1,4 @@
// "Replace with a space" "true"
// "Replace '\s' sequences with spaces" "true-preview"
class X {
void test(String str) {
if (str.matches(" +")) {
@@ -0,0 +1,8 @@
// "Replace '\s' sequences with spaces" "true-preview"
class X {
void test(String str) {
if (str.matches("<caret>\sa\sb\sc\sd")) {
}
}
}
@@ -0,0 +1,8 @@
// "Fix all 'Non-terminal use of '\s' escape sequence' problems in file" "true"
class X {
void test(String str) {
if (str.matches("<caret>\sa\sb\sc\sd")) {
}
}
}
@@ -1,4 +1,4 @@
// "Replace with a space" "false"
// "Replace '\s' sequences with spaces" "false"
class X {
void test() {
String s = "\s<caret>\s\s!\s\s\s";
@@ -1,4 +1,4 @@
// "Replace with a space" "true"
// "Replace '\s' sequences with spaces" "true-preview"
class X {
void test(String str) {
if (str.matches("<caret>\s+")) {
@@ -1,4 +1,4 @@
// "Replace with a space" "false"
// "Replace '\s' sequences with spaces" "false"
class X {
void test(String str) {
if (str.matches("\\<caret>s+")) {
@@ -1,4 +1,4 @@
// "Replace with a space" "false"
// "Replace '\s' sequences with spaces" "false"
class X {
void test() {
String s = """
@@ -2439,7 +2439,7 @@ try.with.identical.catches.checkbox.different.comments=Do not report catch block
inspection.non.strict.comparison.equality.message=Can be replaced with equality
inspection.non.strict.comparison.equality.display.name=Non-strict inequality '>=' or '<=' can be replaced with '=='
inspection.quirk.method.reference.return.type.message=Target method return type mentions inaccessible class {0}. This will cause IllegalAccessError at runtime.
inspection.use.of.slash.s.fix.family=Replace with a space
inspection.use.of.slash.s.fix.family=Replace '\\s' sequences with spaces
inspection.use.of.slash.s.message=Use of '\\s' escape sequence in the middle of line is discouraged
inspection.use.of.slash.s.display.name=Non-terminal use of '\\s' escape sequence
negative.int.constant.in.long.context.display.name=Negative int hexadecimal constant in long context
@@ -9,6 +9,9 @@ import com.intellij.psi.*;
import com.intellij.util.ObjectUtils;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.psiutils.TypeUtils;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import one.util.streamex.IntStreamEx;
import org.jetbrains.annotations.NotNull;
public class EscapedSpaceInspection extends AbstractBaseJavaLocalInspectionTool implements CleanupLocalInspectionTool {
@@ -20,45 +23,49 @@ public class EscapedSpaceInspection extends AbstractBaseJavaLocalInspectionTool
public void visitLiteralExpression(@NotNull PsiLiteralExpression literal) {
PsiType type = literal.getType();
if (!TypeUtils.isJavaLangString(type)) return;
boolean block = literal.isTextBlock();
String text = literal.getText();
int pos = 1;
while (true) {
pos = text.indexOf('\\', pos);
if (pos == -1 || pos == text.length() - 1) return;
char next = text.charAt(pos + 1);
if (next == 'u') {
// unicode escape
pos += 6;
continue;
}
pos += 2;
if (next >= '0' && next <= '9') {
// octal escape
if (pos < text.length() && text.charAt(pos) >= '0' && text.charAt(pos) <= '9') pos++;
if (pos < text.length() && text.charAt(pos) >= '0' && text.charAt(pos) <= '9') pos++;
continue;
}
if (next != 's') {
// other escapes
continue;
}
if (pos > 4 && text.startsWith("\\s", pos - 4)) continue;
if (text.startsWith("\\s", pos)) continue;
if (block && (pos == text.length() || text.charAt(pos) == '\n')) continue;
holder.registerProblem(literal, TextRange.create(pos - 2, pos),
for (int pos : findPositions(literal)) {
holder.registerProblem(literal, TextRange.create(pos, pos + 2),
InspectionGadgetsBundle.message("inspection.use.of.slash.s.message"),
new ReplaceWithSpaceFix(pos - 2));
new ReplaceWithSpaceFix());
}
}
};
}
private static int[] findPositions(@NotNull PsiLiteralExpression literal) {
boolean block = literal.isTextBlock();
String text = literal.getText();
int pos = 1;
IntList list = new IntArrayList();
while (true) {
pos = text.indexOf('\\', pos);
if (pos == -1 || pos == text.length() - 1) break;
char next = text.charAt(pos + 1);
if (next == 'u') {
// unicode escape
pos += 6;
continue;
}
pos += 2;
if (next >= '0' && next <= '9') {
// octal escape
if (pos < text.length() && text.charAt(pos) >= '0' && text.charAt(pos) <= '9') pos++;
if (pos < text.length() && text.charAt(pos) >= '0' && text.charAt(pos) <= '9') pos++;
continue;
}
if (next != 's') {
// other escapes
continue;
}
if (pos > 4 && text.startsWith("\\s", pos - 4)) continue;
if (text.startsWith("\\s", pos)) continue;
if (block && (pos == text.length() || text.charAt(pos) == '\n')) continue;
list.add(pos - 2);
}
return list.toIntArray();
}
private static class ReplaceWithSpaceFix implements LocalQuickFix {
private final int myPos;
ReplaceWithSpaceFix(int pos) { myPos = pos; }
@Override
public @NotNull String getFamilyName() {
return InspectionGadgetsBundle.message("inspection.use.of.slash.s.fix.family");
@@ -68,9 +75,15 @@ public class EscapedSpaceInspection extends AbstractBaseJavaLocalInspectionTool
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiLiteralExpression literal = ObjectUtils.tryCast(descriptor.getStartElement(), PsiLiteralExpression.class);
if (literal == null) return;
int[] positions = findPositions(literal);
String text = literal.getText();
if (text.length() < myPos+2) return;
String newText = text.substring(0, myPos) + ' ' + text.substring(myPos + 2);
String newText = IntStreamEx.of(positions)
.takeWhile(pos -> pos < text.length() - 2)
.boxed()
.prepend(-2)
.append(text.length())
.pairMap((start, end) -> text.substring(start + 2, end))
.joining(" ");
literal.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(newText, null));
}
}