mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[codeInsight] IDEA-113640 Provide intention to combine System.out.println(String.format(...)) into System.out.printf
This patch fixes the notes from the code review, it inclues: - renaming method to methodNameReference for variables that contain the name of a method that is being called, i.e. either `println` or `print` or `format` - using a different overloaded createProblemDescriptor method that does not accept a `TextRange` - using `getParent` in quick fixes to get the `PsiMethodExpressionCall` - proper handling arguments with parenthesis Signed-off-by: Nikita Eshkeev <nikita.eshkeev@jetbrains.com> GitOrigin-RevId: ea1e335372bf7b1ce3e6c87a3816baa0ab54e11e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7f537d3466
commit
299e3d31e1
@@ -8,13 +8,19 @@ class Main {
|
||||
static {
|
||||
String s1 = "test";
|
||||
String s1n = format("test%n");
|
||||
String s1n1 = format(("test%n"));
|
||||
String s2 = "test";
|
||||
String s21 = "test";
|
||||
String s2n = format(Locale.US, "test%n");
|
||||
String s2n1 = format(Locale.US, ((("test%n"))));
|
||||
String s3 = "test";
|
||||
String s31 = "test";
|
||||
String s3l = "test";
|
||||
String s3n = String.format(Locale.US, "test%n");
|
||||
String s3l1 = "test";
|
||||
String s3n1 = String.format(Locale.US, ("test%n"));
|
||||
|
||||
System.out.println(/* one */ /* two */ /* three */ "hello, " /* four */);
|
||||
System.out.println(/* one */ /* two */ /* three */ "hello" /* four */);
|
||||
System.out.println(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
}
|
||||
|
||||
Main() {
|
||||
|
||||
@@ -4,7 +4,9 @@ import java.io.PrintStream;
|
||||
class Main {
|
||||
static {
|
||||
System.out.print(/* begin */ "Hello, World!"/* end */);
|
||||
System.out.print((/* begin */ "Hello, World!"/* end */));
|
||||
System.out.print(String.format(/* begin */ "Hello, World!%n"/* end */));
|
||||
System.out.print(String.format((/* begin */ "Hello, World!%n"/* end */)));
|
||||
}
|
||||
|
||||
Main() {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// "Fix all 'Redundant call to 'String.format()'' problems in file" "true"
|
||||
import java.io.PrintStream;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
class Main {
|
||||
static {
|
||||
System.out.print(/* one */ "hello" /* two */);
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
System.out.print((format(/* one */ Locale.CANADA /* two */, /* three */ "hello%n" /* four */)));
|
||||
}
|
||||
|
||||
Main() {
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
}
|
||||
void f() {
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ ("hello") /* two */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
System.out.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
}
|
||||
void out(PrintStream printer) {
|
||||
printer.print(/* one */ ("hello") /* two */);
|
||||
printer.print(/* one */ ("hello") /* two */);
|
||||
printer.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
printer.print(/* one */ /* two */ /* three */ ("hello") /* four */);
|
||||
}
|
||||
void caller() {
|
||||
printf(String.format(/* one */ ("hello") /* two */));
|
||||
printf(((String.format(/* one */ ("hello") /* two */))));
|
||||
printf(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
printf((String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
}
|
||||
|
||||
static void printf(String value) {}
|
||||
}
|
||||
@@ -8,13 +8,19 @@ class Main {
|
||||
static {
|
||||
String s1 = f<caret>ormat("test");
|
||||
String s1n = format("test%n");
|
||||
String s1n1 = format(("test%n"));
|
||||
String s2 = format(Locale.US, "test");
|
||||
String s21 = format(Locale.US, ("test"));
|
||||
String s2n = format(Locale.US, "test%n");
|
||||
String s2n1 = format(Locale.US, ((("test%n"))));
|
||||
String s3 = String.format("test");
|
||||
String s31 = String.format((("test")));
|
||||
String s3l = String.format(Locale.US, "test");
|
||||
String s3n = String.format(Locale.US, "test%n");
|
||||
String s3l1 = String.format(Locale.US, ("test"));
|
||||
String s3n1 = String.format(Locale.US, ("test%n"));
|
||||
|
||||
System.out.println(String.format(/* one */ Locale.CANADA /* two */, /* three */ "hello, " /* four */));
|
||||
System.out.println(String.format(/* one */ Locale.CANADA /* two */, /* three */ "hello" /* four */));
|
||||
System.out.println(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
}
|
||||
|
||||
Main() {
|
||||
|
||||
@@ -4,7 +4,9 @@ import java.io.PrintStream;
|
||||
class Main {
|
||||
static {
|
||||
System.out.print(String.<caret>format(/* begin */ "Hello, World!"/* end */));
|
||||
System.out.print(String.format((/* begin */ "Hello, World!"/* end */)));
|
||||
System.out.print(String.format(/* begin */ "Hello, World!%n"/* end */));
|
||||
System.out.print(String.format((/* begin */ "Hello, World!%n"/* end */)));
|
||||
}
|
||||
|
||||
Main() {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// "Fix all 'Redundant call to 'String.format()'' problems in file" "true"
|
||||
import java.io.PrintStream;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
class Main {
|
||||
static {
|
||||
System.out.<caret>printf(String.format(/* one */ "hello" /* two */));
|
||||
System.out.printf(String.format(/* one */ ("hello") /* two */));
|
||||
System.out.printf(format(/* one */ ("hello") /* two */);
|
||||
System.out.printf(((String.format(/* one */ ("hello") /* two */))));
|
||||
System.out.printf(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
System.out.printf((String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
System.out.printf((format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
System.out.printf((format(/* one */ Locale.CANADA /* two */, /* three */ "hello%n" /* four */)));
|
||||
}
|
||||
|
||||
Main() {
|
||||
System.out.printf(String.format(/* one */ ("hello") /* two */));
|
||||
System.out.printf(((String.format(/* one */ ("hello") /* two */))));
|
||||
System.out.printf(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
System.out.printf((String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
}
|
||||
void f() {
|
||||
System.out.printf(String.format(/* one */ ("hello") /* two */));
|
||||
System.out.printf(((String.format(/* one */ ("hello") /* two */))));
|
||||
System.out.printf(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
System.out.printf((String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
}
|
||||
void out(PrintStream printer) {
|
||||
printer.printf(String.format(/* one */ ("hello") /* two */));
|
||||
printer.printf(((String.format(/* one */ ("hello") /* two */))));
|
||||
printer.printf(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
printer.printf((String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
}
|
||||
void caller() {
|
||||
printf(String.format(/* one */ ("hello") /* two */));
|
||||
printf(((String.format(/* one */ ("hello") /* two */))));
|
||||
printf(String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */));
|
||||
printf((String.format(/* one */ Locale.CANADA /* two */, /* three */ ("hello") /* four */)));
|
||||
}
|
||||
|
||||
static void printf(String value) {}
|
||||
}
|
||||
@@ -4,12 +4,12 @@ package com.siyeh.ig.performance;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiLiteralUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.callMatcher.CallMapper;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
@@ -70,28 +70,28 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
final PsiExpressionList args = call.getArgumentList();
|
||||
if (args.getExpressionCount() != 1) return null;
|
||||
|
||||
final PsiElement method = call.getMethodExpression().getReferenceNameElement();
|
||||
if (method == null) return null;
|
||||
final PsiElement methodNameReference = call.getMethodExpression().getReferenceNameElement();
|
||||
if (methodNameReference == null) return null;
|
||||
|
||||
final PsiExpression formatValue = args.getExpressions()[0];
|
||||
if (containsNewlineToken(formatValue)) return null;
|
||||
|
||||
return myManager.createProblemDescriptor(method, (TextRange) null,
|
||||
return myManager.createProblemDescriptor(methodNameReference,
|
||||
InspectionGadgetsBundle.message("redundant.call.problem.descriptor"),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly,
|
||||
new ReplaceWithPrintFix());
|
||||
new ReplaceWithPrintFix(),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor getRedundantStringFormatProblem(@NotNull final PsiMethodCallExpression call) {
|
||||
final PsiElement method = call.getMethodExpression().getReferenceNameElement();
|
||||
if (method == null) return null;
|
||||
final PsiElement methodNameReference = call.getMethodExpression().getReferenceNameElement();
|
||||
if (methodNameReference == null) return null;
|
||||
|
||||
if (isStringFormatCallRedundant(call)) {
|
||||
return myManager.createProblemDescriptor(method, (TextRange) null,
|
||||
return myManager.createProblemDescriptor(methodNameReference,
|
||||
InspectionGadgetsBundle.message("redundant.call.problem.descriptor"),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly,
|
||||
new RemoveRedundantStringFormatFix());
|
||||
new RemoveRedundantStringFormatFix(),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly);
|
||||
}
|
||||
final PsiMethodCallExpression printlnCall = PsiTreeUtil.getParentOfType(call, PsiMethodCallExpression.class);
|
||||
final boolean isPrintlnCall = PRINTSTREAM_PRINTLN.test(printlnCall);
|
||||
@@ -100,10 +100,10 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
|
||||
}
|
||||
|
||||
return myManager.createProblemDescriptor(method, (TextRange) null,
|
||||
return myManager.createProblemDescriptor(methodNameReference,
|
||||
InspectionGadgetsBundle.message("redundant.call.problem.descriptor"),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly,
|
||||
new StringFormatToPrintfQuickFix(isPrintlnCall));
|
||||
new StringFormatToPrintfQuickFix(isPrintlnCall),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@@ -122,10 +122,11 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
private static boolean containsNewlineToken(@Nullable final PsiExpression expression) {
|
||||
if (expression == null) {
|
||||
private static boolean containsNewlineToken(@Nullable final PsiExpression expr) {
|
||||
if (expr == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpression expression = PsiUtil.skipParenthesizedExprDown(expr);
|
||||
if (expression instanceof PsiLiteralExpression) {
|
||||
final PsiLiteralExpression literalExpression = (PsiLiteralExpression)expression;
|
||||
final String expressionText = literalExpression.getText();
|
||||
@@ -156,13 +157,20 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement methodName = descriptor.getPsiElement();
|
||||
if (methodName == null) return;
|
||||
if ((methodName == null) || !(methodName.getParent() instanceof PsiReferenceExpression) ||
|
||||
!(methodName.getParent().getParent() instanceof PsiMethodCallExpression)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiMethodCallExpression printStreamPrintfCall = PsiTreeUtil.getParentOfType(methodName, PsiMethodCallExpression.class);
|
||||
|
||||
if (printStreamPrintfCall == null) return;
|
||||
final PsiMethodCallExpression printStreamPrintfCall = (PsiMethodCallExpression)methodName.getParent().getParent();
|
||||
|
||||
ExpressionUtils.bindCallTo(printStreamPrintfCall, "print");
|
||||
|
||||
final PsiExpressionList argumentList = printStreamPrintfCall.getArgumentList();
|
||||
final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(argumentList.getExpressions()[0]);
|
||||
if (arg instanceof PsiMethodCallExpression && STRING_FORMAT.test((PsiMethodCallExpression)arg) && isStringFormatCallRedundant((PsiMethodCallExpression)arg)) {
|
||||
removeRedundantStringFormatCall((PsiMethodCallExpression)arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,29 +181,17 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project,
|
||||
@NotNull ProblemDescriptor descriptor) {
|
||||
public void applyFix(@NotNull final Project project,
|
||||
@NotNull final ProblemDescriptor descriptor) {
|
||||
final PsiElement methodName = descriptor.getPsiElement();
|
||||
if (methodName == null) return;
|
||||
|
||||
final PsiMethodCallExpression stringFormat = PsiTreeUtil.getParentOfType(methodName, PsiMethodCallExpression.class);
|
||||
if (stringFormat == null) return;
|
||||
|
||||
final PsiElement parent = stringFormat.getParent();
|
||||
if (parent instanceof PsiExpressionList && ((PsiExpressionList)parent).getExpressionCount() == 1 && parent.getParent() instanceof PsiMethodCallExpression){
|
||||
final PsiMethodCallExpression printCall = (PsiMethodCallExpression)parent.getParent();
|
||||
final PsiExpression[] args = stringFormat.getArgumentList().getExpressions();
|
||||
if (args.length > 1) {
|
||||
new CommentTracker().deleteAndRestoreComments(args[0]);
|
||||
}
|
||||
new CommentTracker().replaceAndRestoreComments(printCall.getArgumentList(), stringFormat.getArgumentList());
|
||||
}
|
||||
else {
|
||||
final CommentTracker ct = new CommentTracker();
|
||||
final PsiExpression[] args = stringFormat.getArgumentList().getExpressions();
|
||||
final String expression = ct.text(args[args.length - 1]);
|
||||
ct.replaceAndRestoreComments(stringFormat, expression);
|
||||
if ((methodName == null) || !(methodName.getParent() instanceof PsiReferenceExpression) ||
|
||||
!(methodName.getParent().getParent() instanceof PsiMethodCallExpression)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiMethodCallExpression stringFormat = (PsiMethodCallExpression)methodName.getParent().getParent();
|
||||
|
||||
removeRedundantStringFormatCall(stringFormat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,10 +210,12 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
@Override
|
||||
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
|
||||
final PsiElement methodName = descriptor.getPsiElement();
|
||||
if (methodName == null) return;
|
||||
if ((methodName == null) || !(methodName.getParent() instanceof PsiReferenceExpression) ||
|
||||
!(methodName.getParent().getParent() instanceof PsiMethodCallExpression)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiMethodCallExpression stringFormatCall = PsiTreeUtil.getParentOfType(methodName, PsiMethodCallExpression.class);
|
||||
if (stringFormatCall == null) return;
|
||||
final PsiMethodCallExpression stringFormatCall = (PsiMethodCallExpression)methodName.getParent().getParent();
|
||||
|
||||
final PsiMethodCallExpression printlnCall = PsiTreeUtil.getParentOfType(stringFormatCall, PsiMethodCallExpression.class);
|
||||
if (printlnCall == null) return;
|
||||
@@ -244,7 +242,8 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
@Nullable
|
||||
@Contract(pure = true)
|
||||
private static PsiExpression getArgWithFormatValue(@NotNull final PsiExpressionList stringFormatArgs) {
|
||||
final PsiExpression firstFormatArg = stringFormatArgs.getExpressions()[0];
|
||||
final PsiExpression firstFormatArg = PsiUtil.skipParenthesizedExprDown(stringFormatArgs.getExpressions()[0]);
|
||||
if (firstFormatArg == null) return null;
|
||||
final PsiType firstType = firstFormatArg.getType();
|
||||
|
||||
if (firstType == null) return null;
|
||||
@@ -252,7 +251,9 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
if (firstType.equalsToText(Locale.class.getName())) {
|
||||
if (stringFormatArgs.getExpressionCount() <= 1) return null;
|
||||
|
||||
final PsiExpression secondFormatArg = stringFormatArgs.getExpressions()[1];
|
||||
final PsiExpression secondFormatArg = PsiUtil.skipParenthesizedExprDown(stringFormatArgs.getExpressions()[1]);
|
||||
if (secondFormatArg == null) return null;
|
||||
|
||||
final PsiType secondType = secondFormatArg.getType();
|
||||
if (secondType == null || !secondType.equalsToText(String.class.getName())) return null;
|
||||
|
||||
@@ -264,7 +265,10 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void appendWithNewlineToken(@NotNull final PsiElement formatArg) {
|
||||
private static void appendWithNewlineToken(@NotNull final PsiExpression expr) {
|
||||
final PsiElement formatArg = PsiUtil.skipParenthesizedExprDown(expr);
|
||||
if (formatArg == null) return;
|
||||
|
||||
final String newLineToken = "%n";
|
||||
|
||||
if (formatArg instanceof PsiLiteralExpression) {
|
||||
@@ -272,7 +276,7 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
formatArg.replace(replacement);
|
||||
}
|
||||
else if (formatArg instanceof PsiPolyadicExpression){
|
||||
final PsiElement lastChild = formatArg.getLastChild();
|
||||
final PsiElement lastChild = skipParenIfPossible(formatArg.getLastChild());
|
||||
if (lastChild instanceof PsiLiteralExpression) {
|
||||
final PsiLiteralExpression replacement = joinWithNewlineToken((PsiLiteralExpression)lastChild);
|
||||
lastChild.replace(replacement);
|
||||
@@ -290,6 +294,13 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement skipParenIfPossible(@NotNull PsiElement element) {
|
||||
if (!(element instanceof PsiExpression)) return element;
|
||||
|
||||
return PsiUtil.skipParenthesizedExprDown((PsiExpression)element);
|
||||
}
|
||||
|
||||
@Contract(value = "null -> null; !null -> !null", pure = true)
|
||||
private static PsiLiteralExpression joinWithNewlineToken(@Nullable final PsiLiteralExpression expression) {
|
||||
if (expression == null) return null;
|
||||
@@ -318,5 +329,26 @@ public final class RedundantStringFormatCallInspection extends LocalInspectionTo
|
||||
return (PsiLiteralExpression)factory.createExpressionFromText(newExpression.toString(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeRedundantStringFormatCall(@NotNull PsiMethodCallExpression stringFormat) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(stringFormat.getParent());
|
||||
if (parent instanceof PsiExpressionList && ((PsiExpressionList)parent).getExpressionCount() == 1 && parent.getParent() instanceof PsiMethodCallExpression){
|
||||
final PsiMethodCallExpression printCall = (PsiMethodCallExpression)parent.getParent();
|
||||
final PsiExpression[] args = stringFormat.getArgumentList().getExpressions();
|
||||
if (args.length > 1) {
|
||||
new CommentTracker().deleteAndRestoreComments(args[0]);
|
||||
}
|
||||
new CommentTracker().replaceAndRestoreComments(printCall.getArgumentList(), stringFormat.getArgumentList());
|
||||
}
|
||||
else {
|
||||
final CommentTracker ct = new CommentTracker();
|
||||
final PsiExpression[] args = stringFormat.getArgumentList().getExpressions();
|
||||
final PsiExpression element = PsiUtil.skipParenthesizedExprDown(args[args.length - 1]);
|
||||
if (element == null) return;
|
||||
final String expression = ct.text(element);
|
||||
ct.replaceAndRestoreComments(stringFormat, expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user