mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
TextBlockMigrationInspection: option to replace concatenation only, less noisy highlighting (IDEA-224582)
GitOrigin-RevId: a420c84ac6daa81ab7eb69112161ac2adc3d30d5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4989493636
commit
3021c81a97
@@ -2,23 +2,36 @@
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl;
|
||||
import com.intellij.psi.util.PsiLiteralUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
public class TextBlockMigrationInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
|
||||
public boolean mySuggestLiteralReplacement = true;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(InspectionsBundle.message("inspection.text.block.migration.suggest.literal.replacement"),
|
||||
this,
|
||||
"mySuggestLiteralReplacement");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
@@ -27,22 +40,41 @@ public class TextBlockMigrationInspection extends AbstractBaseJavaLocalInspectio
|
||||
@Override
|
||||
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
|
||||
if (!isConcatenation(expression)) return;
|
||||
int newLinesCnt = 0;
|
||||
for (PsiExpression operand : expression.getOperands()) {
|
||||
String text = getExpressionText(operand, false);
|
||||
if (text == null) return;
|
||||
if (newLinesCnt <= 1) newLinesCnt += StringUtils.countMatches(text, "\n");
|
||||
int nNewLines = 0;
|
||||
PsiExpression[] operands = expression.getOperands();
|
||||
TextRange firstNewLineTextRange = null;
|
||||
for (PsiExpression operand : operands) {
|
||||
PsiLiteralExpressionImpl literal = getLiteralExpression(operand);
|
||||
if (literal == null) return;
|
||||
String text = literal.getText();
|
||||
int newLineIdx = getNewLineIndex(text, 0);
|
||||
if (newLineIdx == -1) continue;
|
||||
if (firstNewLineTextRange == null) {
|
||||
int operandOffset = literal.getTextOffset() - expression.getTextOffset();
|
||||
firstNewLineTextRange = new TextRange(operandOffset + newLineIdx, operandOffset + newLineIdx + 2);
|
||||
}
|
||||
while (nNewLines <= 1 && newLineIdx != -1) {
|
||||
nNewLines++;
|
||||
newLineIdx = getNewLineIndex(text, newLineIdx + 1);
|
||||
}
|
||||
if (nNewLines > 1) break;
|
||||
}
|
||||
if (newLinesCnt <= 1) return;
|
||||
holder.registerProblem(expression, InspectionsBundle.message("inspection.text.block.migration.message", "Concatenation"),
|
||||
if (nNewLines <= 1) return;
|
||||
holder.registerProblem(expression, firstNewLineTextRange,
|
||||
InspectionsBundle.message("inspection.text.block.migration.message", "Concatenation"),
|
||||
new ReplaceWithTextBlockFix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLiteralExpression(PsiLiteralExpression expression) {
|
||||
String text = getExpressionText(expression, false);
|
||||
if (text == null || StringUtils.countMatches(text, "\n") <= 1) return;
|
||||
holder.registerProblem(expression, InspectionsBundle.message("inspection.text.block.migration.message", "String"),
|
||||
if (!mySuggestLiteralReplacement) return;
|
||||
PsiLiteralExpressionImpl literal = getLiteralExpression(expression);
|
||||
if (literal == null) return;
|
||||
String text = literal.getText();
|
||||
int newLineIdx = getNewLineIndex(text, 0);
|
||||
if (newLineIdx == -1 || getNewLineIndex(text, newLineIdx + 1) == -1) return;
|
||||
holder.registerProblem(expression, new TextRange(newLineIdx, newLineIdx + 2),
|
||||
InspectionsBundle.message("inspection.text.block.migration.message", "String"),
|
||||
new ReplaceWithTextBlockFix());
|
||||
}
|
||||
};
|
||||
@@ -79,7 +111,9 @@ public class TextBlockMigrationInspection extends AbstractBaseJavaLocalInspectio
|
||||
boolean escapeStartQuote = false;
|
||||
for (int i = 0; i < operands.length; i++) {
|
||||
PsiExpression operand = operands[i];
|
||||
String text = getExpressionText(operand, true);
|
||||
PsiLiteralExpressionImpl literal = getLiteralExpression(operand);
|
||||
if (literal == null) return;
|
||||
String text = getLiteralText(literal);
|
||||
if (text == null) return;
|
||||
boolean isLastLine = i == operands.length - 1;
|
||||
text = PsiLiteralUtil.escapeTextBlockCharacters(text, escapeStartQuote, isLastLine, isLastLine);
|
||||
@@ -91,16 +125,36 @@ public class TextBlockMigrationInspection extends AbstractBaseJavaLocalInspectio
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNewLineIndex(@NotNull String text, int start) {
|
||||
int i = start;
|
||||
while (i < text.length()) {
|
||||
char c = text.charAt(i);
|
||||
if (c == '\\') {
|
||||
if (i + 1 < text.length() && text.charAt(i + 1) == 'n') return i;
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static boolean isConcatenation(@NotNull PsiPolyadicExpression expression) {
|
||||
PsiType type = expression.getType();
|
||||
return type != null && type.equalsToText(CommonClassNames.JAVA_LANG_STRING);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getExpressionText(@NotNull PsiExpression expression, boolean isRawText) {
|
||||
private static PsiLiteralExpressionImpl getLiteralExpression(@NotNull PsiExpression expression) {
|
||||
PsiLiteralExpressionImpl literal = tryCast(PsiUtil.skipParenthesizedExprDown(expression), PsiLiteralExpressionImpl.class);
|
||||
if (literal == null || literal.getLiteralElementType() == JavaTokenType.TEXT_BLOCK_LITERAL) return null;
|
||||
if (literal.getLiteralElementType() == JavaTokenType.STRING_LITERAL && isRawText) return literal.getInnerText();
|
||||
return literal;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getLiteralText(@NotNull PsiLiteralExpressionImpl literal) {
|
||||
if (literal.getLiteralElementType() == JavaTokenType.STRING_LITERAL) return literal.getInnerText();
|
||||
Object value = literal.getValue();
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenation() {
|
||||
String foobarbaz = "foo\n" <caret>+
|
||||
String foobarbaz = "foo<caret>\n" +
|
||||
"bar\n" +
|
||||
"baz";
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenationWithMultipleNewLines() {
|
||||
String text = "This<caret> text should be on the same line as \\n this one\n" +
|
||||
String text = "This text should be on the same line as \\n this one<caret>\n" +
|
||||
"foo\n" +
|
||||
"bar\n";
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenationWithMultipleNewLines() {
|
||||
String html = "<html>\n" +<caret>
|
||||
String html = "<html>\n<caret>" +
|
||||
" <body>\n" +
|
||||
" <p>Hello, world</p>\n" +
|
||||
" </body>\n" +
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenationWithNonStrings() {
|
||||
String answer = "T<caret>he answer to the meaning of life,\n" +
|
||||
String answer = "The answer to the meaning of life,<caret>\n" +
|
||||
"the universe,\n" +
|
||||
"and everything\n" +
|
||||
"is " + 42 + '\n';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenationWithOneNewLine() {
|
||||
String code = "<<caret>html>\n" +
|
||||
String code = "<html><caret>\n" +
|
||||
"</html>";
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenationWithExtraSpaces() {
|
||||
String code = "<<caret>html> \n" +
|
||||
String code = "<html> <caret>\n" +
|
||||
" <body>\n" +
|
||||
" </body>\n" +
|
||||
"</html> ";
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void concatenationWithThreeQuotes() {
|
||||
String quotes = "<caret>this concatenation contains\n" +
|
||||
String quotes = "this concatenation contains<caret>\n" +
|
||||
" three quotes\n" +
|
||||
"one after another\n" +
|
||||
"\"" +
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void literalWithNewLine() {
|
||||
String foo = "foo\nbar<caret>\nbaz\n";
|
||||
String foo = "foo<caret>\nbar\nbaz\n";
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
class TextBlockMigration {
|
||||
|
||||
void literalWithNewLine() {
|
||||
String foo = "foo\nbar<caret>";
|
||||
String foo = "foo<caret>\nbar";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1011,6 +1011,7 @@ inspection.fold.expression.into.string.fix.name=Fold expression into 'String.joi
|
||||
inspection.fold.expression.fix.family.name=Fold expression
|
||||
inspection.text.block.migration.name=Text block can be used
|
||||
inspection.text.block.migration.message={0} can be replaced with text block
|
||||
inspection.text.block.migration.suggest.literal.replacement=Suggest to replace string with line breaks
|
||||
inspection.replace.with.text.block.fix=Replace with text block
|
||||
|
||||
inspection.text.block.backward.migration.name=Text block can be replaced with regular string literal
|
||||
|
||||
Reference in New Issue
Block a user