mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-inspections] IDEA-197280 Non-constant string concatenation as argument" could also be triggered for String.format
- Support simple cases for String.format - Support simple cases for MessageFormat.format GitOrigin-RevId: 50f52f526923950e30746691414bb89ce5fca5ab
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8a1cf90bc0
commit
a750ec4eb0
@@ -1918,8 +1918,10 @@ arrays.as.list.with.zero.or.one.argument.display.name=Call to 'Arrays.asList()'
|
||||
arrays.as.list.with.one.argument.problem.descriptor=Call to <code>#ref()</code> with only one argument #loc
|
||||
arrays.as.list.with.zero.arguments.problem.descriptor=Call to <code>#ref()</code> to create an empty List #loc
|
||||
string.concatenation.argument.to.log.call.display.name=Non-constant string concatenation as argument to logging call
|
||||
string.concatenation.argument.to.log.call.problem.descriptor=Non-constant string concatenation as argument to <code>#ref()</code> logging call #loc
|
||||
string.concatenation.argument.to.log.call.problem.descriptor=Evaluated string as argument to <code>#ref()</code> logging call #loc
|
||||
string.concatenation.argument.to.log.call.quickfix=Replace concatenation with parameterized log message
|
||||
string.concatenation.argument.to.log.string.format.call.quickfix=Replace 'String.format()' with parameterized log message
|
||||
string.concatenation.argument.to.log.message.format.call.quickfix=Replace 'Message.format()' with parameterized log message
|
||||
assignment.to.superclass.field.display.name=Constructor assigns value to field defined in superclass
|
||||
assignment.to.superclass.field.problem.descriptor=Assignment to field ''{0}'' defined in superclass ''{1}'' #loc
|
||||
inner.class.referenced.via.subclass.display.name=Inner class referenced via subclass
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.siyeh.ig.bugs.message;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -67,7 +68,10 @@ public final class MessageFormatUtil {
|
||||
if (part.getParsedType() == MessageFormatParsedType.FORMAT_ELEMENT &&
|
||||
part.getMessageFormatElement() != null &&
|
||||
part.getMessageFormatElement().getIndex() != null) {
|
||||
placeholderIndexes.add(new MessageFormatPlaceholder(part.getMessageFormatElement().getIndex()));
|
||||
placeholderIndexes.add(new MessageFormatPlaceholder(part.getMessageFormatElement().getIndex(),
|
||||
new TextRange(part.start, part.start + part.text.length()),
|
||||
part.getMessageFormatElement().formatType == null &&
|
||||
part.getMessageFormatElement().currentPart == MessageFormatElementPart.ARGUMENT_INDEX));
|
||||
}
|
||||
}
|
||||
return new MessageFormatResult(errors.isEmpty(), errors, placeholderIndexes);
|
||||
@@ -445,7 +449,7 @@ public final class MessageFormatUtil {
|
||||
@NotNull List<MessageFormatPlaceholder> placeholders) {
|
||||
}
|
||||
|
||||
public record MessageFormatPlaceholder(int index) {
|
||||
public record MessageFormatPlaceholder(int index, @NotNull TextRange range, boolean isString) {
|
||||
}
|
||||
|
||||
static class MessageFormatPart {
|
||||
|
||||
@@ -203,7 +203,8 @@ public final class FormatDecode {
|
||||
|
||||
final Validator allowed;
|
||||
if (isAllVerifier) {
|
||||
allowed = new AllValidatorWithRange(TextRange.create(matcher.start(), matcher.end()));
|
||||
allowed = new AllValidatorWithRange(TextRange.create(matcher.start(), matcher.end()),
|
||||
new Spec(posSpec, flags, width, precision, dateSpec, conversion));
|
||||
}
|
||||
else if (dateSpec != null) { // a t or T
|
||||
checkFlags(flagBits, LEFT_JUSTIFY | PREVIOUS, specifier);
|
||||
@@ -414,9 +415,16 @@ public final class FormatDecode {
|
||||
|
||||
private static class AllValidatorWithRange extends AllValidator {
|
||||
private final @NotNull TextRange myRange;
|
||||
private final @NotNull Spec mySpec;
|
||||
|
||||
AllValidatorWithRange(@NotNull TextRange range) {
|
||||
AllValidatorWithRange(@NotNull TextRange range, @NotNull Spec spec) {
|
||||
myRange = range;
|
||||
mySpec = spec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Spec getSpec() {
|
||||
return mySpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -528,7 +536,7 @@ public final class FormatDecode {
|
||||
}
|
||||
}
|
||||
|
||||
static class MultiValidator extends Validator {
|
||||
public static class MultiValidator extends Validator {
|
||||
private final Set<Validator> validators = new HashSet<>(3);
|
||||
|
||||
@Nullable
|
||||
@@ -556,7 +564,7 @@ public final class FormatDecode {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<Validator> getValidators() {
|
||||
public Set<Validator> getValidators() {
|
||||
return validators;
|
||||
}
|
||||
|
||||
@@ -589,6 +597,19 @@ public final class FormatDecode {
|
||||
public @Nullable TextRange getRange() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public @Nullable Spec getSpec() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public record Spec(@Nullable String posSpec ,
|
||||
@Nullable String flags,
|
||||
@Nullable String width,
|
||||
@Nullable String precision,
|
||||
@Nullable String dateSpec,
|
||||
@Nullable String conversion){
|
||||
|
||||
}
|
||||
|
||||
public static class FormatArgument {
|
||||
@@ -608,13 +629,15 @@ public final class FormatDecode {
|
||||
return myExpression;
|
||||
}
|
||||
|
||||
public static FormatArgument extract(@NotNull PsiCallExpression expression, List<String> methodNames, List<String> classNames) {
|
||||
@Nullable
|
||||
public static FormatArgument extract(@NotNull PsiCallExpression expression, @NotNull List<String> methodNames, @NotNull List<String> classNames) {
|
||||
return extract(expression, methodNames, classNames, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FormatArgument extract(@NotNull PsiCallExpression expression,
|
||||
List<String> methodNames,
|
||||
List<String> classNames,
|
||||
@NotNull List<String> methodNames,
|
||||
@NotNull List<String> classNames,
|
||||
boolean allowNotConstant) {
|
||||
final PsiExpressionList argumentList = expression.getArgumentList();
|
||||
if (argumentList == null) return null;
|
||||
|
||||
+254
-9
@@ -7,16 +7,22 @@ import com.intellij.codeInspection.options.OptPane;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiLiteralUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import com.siyeh.ig.bugs.message.MessageFormatUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.format.FormatDecode;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import one.util.streamex.EntryStream;
|
||||
@@ -27,11 +33,11 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.codeInspection.options.OptPane.*;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.anyOf;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.staticCall;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
@@ -51,6 +57,10 @@ public final class StringConcatenationArgumentToLogCallInspection extends BaseIn
|
||||
private static final String LOG4J_LOGGER = "org.apache.logging.log4j.Logger";
|
||||
private static final String LOG4J_BUILDER = "org.apache.logging.log4j.LogBuilder";
|
||||
private static final String GET_LOGGER = "getLogger";
|
||||
private static final CallMatcher MESSAGE_FORMAT_FORMAT = anyOf(
|
||||
staticCall("java.text.MessageFormat", "format").parameterCount(2)
|
||||
);
|
||||
private static final String SLF4J_LOGGER = "org.slf4j.Logger";
|
||||
|
||||
@SuppressWarnings("PublicField") public int warnLevel = 0;
|
||||
|
||||
@@ -86,16 +96,26 @@ public final class StringConcatenationArgumentToLogCallInspection extends BaseIn
|
||||
@Nullable
|
||||
@Override
|
||||
protected LocalQuickFix buildFix(Object... infos) {
|
||||
if (!(infos[0] instanceof ProblemType problemType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(infos[1] instanceof PsiMethodCallExpression logCall)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(infos[2] instanceof PsiExpression targetExpression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isFormattedLog4J(logCall)) return null;
|
||||
|
||||
if (!StringConcatenationArgumentToLogCallFix.isAvailable((PsiExpression)infos[0])) {
|
||||
return null;
|
||||
}
|
||||
return new StringConcatenationArgumentToLogCallFix();
|
||||
return switch (problemType) {
|
||||
case CONCATENATION ->
|
||||
StringConcatenationArgumentToLogCallFix.isAvailable(targetExpression) ? new StringConcatenationArgumentToLogCallFix() : null;
|
||||
case STRING_FORMAT -> StringFormatArgumentToLogCallFix.create(targetExpression);
|
||||
case MESSAGE_FORMAT -> MessageFormatArgumentToLogCallFix.create(targetExpression);
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isFormattedLog4J(@NotNull PsiMethodCallExpression logCall) {
|
||||
@@ -331,6 +351,218 @@ public final class StringConcatenationArgumentToLogCallInspection extends BaseIn
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class FormatArgumentToLogCallFix extends PsiUpdateModCommandQuickFix {
|
||||
|
||||
@NotNull
|
||||
private final Map<TextRange, Integer> myTextMapping;
|
||||
|
||||
@NotNull
|
||||
private final String format;
|
||||
|
||||
private FormatArgumentToLogCallFix(@NotNull Map<TextRange, Integer> textMapping,
|
||||
@NotNull String format) {
|
||||
myTextMapping = textMapping;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
|
||||
if (!(element.getParent() instanceof PsiReferenceExpression referenceExpression &&
|
||||
referenceExpression.getParent() instanceof PsiMethodCallExpression callExpression)) {
|
||||
return;
|
||||
}
|
||||
PsiExpression[] expressions = callExpression.getArgumentList().getExpressions();
|
||||
if (expressions.length != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiExpression expression = expressions[0];
|
||||
if (!(expression instanceof PsiMethodCallExpression formatCallExpression)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
CommentTracker tracker = new CommentTracker();
|
||||
for (PsiElement child : callExpression.getChildren()) {
|
||||
if (child instanceof PsiExpressionList) {
|
||||
builder.append(createNewArgumentsFromCall(formatCallExpression, tracker));
|
||||
}
|
||||
else {
|
||||
builder.append(tracker.text(child));
|
||||
}
|
||||
}
|
||||
|
||||
tracker.replace(callExpression, builder.toString());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String createNewArgumentsFromCall(@NotNull PsiMethodCallExpression formatCallExpression,
|
||||
@NotNull CommentTracker tracker) {
|
||||
List<String> arguments = new ArrayList<>();
|
||||
List<Map.Entry<TextRange, Integer>> placeholders =
|
||||
myTextMapping.entrySet()
|
||||
.stream()
|
||||
.sorted(Comparator.<Map.Entry<TextRange, Integer>>comparingInt(t -> t.getKey().getStartOffset()).reversed())
|
||||
.toList();
|
||||
String formatWithPlaceholders = format;
|
||||
PsiExpression[] expressions = formatCallExpression.getArgumentList().getExpressions();
|
||||
for (Map.Entry<TextRange, Integer> placeholder : placeholders) {
|
||||
formatWithPlaceholders = formatWithPlaceholders.substring(0, placeholder.getKey().getStartOffset()) + "{}" +
|
||||
formatWithPlaceholders.substring(placeholder.getKey().getEndOffset());
|
||||
|
||||
arguments.add(tracker.text(expressions[placeholder.getValue()]));
|
||||
}
|
||||
arguments.add(formatWithPlaceholders);
|
||||
Collections.reverse(arguments);
|
||||
return "(" + String.join(", ", arguments) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static class MessageFormatArgumentToLogCallFix extends FormatArgumentToLogCallFix {
|
||||
|
||||
private MessageFormatArgumentToLogCallFix(@NotNull Map<TextRange, Integer> result,
|
||||
@NotNull String format) {
|
||||
super(result, format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message("string.concatenation.argument.to.log.message.format.call.quickfix");
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
static LocalQuickFix create(@NotNull PsiExpression expression) {
|
||||
if (!(expression instanceof PsiMethodCallExpression callExpression)) {
|
||||
return null;
|
||||
}
|
||||
PsiExpression[] arguments = callExpression.getArgumentList().getExpressions();
|
||||
if (!(arguments[0] instanceof PsiLiteralExpression literalExpression && literalExpression.getValue() instanceof String pattern)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MessageFormatUtil.MessageFormatResult result = MessageFormatUtil.checkFormat(pattern);
|
||||
if (!result.valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<TextRange, Integer> mapping = new HashMap<>();
|
||||
|
||||
List<MessageFormatUtil.MessageFormatPlaceholder> placeholders = result.placeholders();
|
||||
for (MessageFormatUtil.MessageFormatPlaceholder placeholder : placeholders) {
|
||||
if (!placeholder.isString()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (placeholder.index() + 1 >= arguments.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TextRange actualRange = ExpressionUtils.findStringLiteralRange(literalExpression, placeholder.range().getStartOffset(),
|
||||
placeholder.range().getEndOffset());
|
||||
if (actualRange == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
mapping.put(actualRange, placeholder.index() + 1);
|
||||
}
|
||||
Set<Integer> argumentIndexes = new HashSet<>(mapping.values());
|
||||
if (argumentIndexes.size() != arguments.length - 1) {
|
||||
return null;
|
||||
}
|
||||
return new MessageFormatArgumentToLogCallFix(mapping, literalExpression.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringFormatArgumentToLogCallFix extends FormatArgumentToLogCallFix {
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix");
|
||||
}
|
||||
|
||||
private StringFormatArgumentToLogCallFix(@NotNull Map<TextRange, Integer> result,
|
||||
@NotNull String format) {
|
||||
super(result, format);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static LocalQuickFix create(@NotNull PsiExpression originalExpression) {
|
||||
if (!(originalExpression instanceof PsiMethodCallExpression callExpression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FormatDecode.FormatArgument formatArgument =
|
||||
FormatDecode.FormatArgument.extract(callExpression, List.of("format"), List.of("String"), true);
|
||||
if (formatArgument == null || formatArgument.getIndex() != 1) {
|
||||
return null;
|
||||
}
|
||||
PsiExpression expression = formatArgument.getExpression();
|
||||
if (!(expression instanceof PsiLiteralExpression literalExpression && literalExpression.getText() != null)) {
|
||||
return null;
|
||||
}
|
||||
PsiExpression[] arguments = Objects.requireNonNull(callExpression.getArgumentList()).getExpressions();
|
||||
int argumentCount = arguments.length - formatArgument.getIndex();
|
||||
if (!(literalExpression.getValue() instanceof String formatterString)) {
|
||||
return null;
|
||||
}
|
||||
FormatDecode.Validator[] validators;
|
||||
try {
|
||||
validators = FormatDecode.decodeNoVerify(formatterString, argumentCount);
|
||||
}
|
||||
catch (FormatDecode.IllegalFormatException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (argumentCount != validators.length) return null;
|
||||
Map<TextRange, Integer> result = new HashMap<>();
|
||||
for (int i = 0; i < validators.length; i++) {
|
||||
int index = formatArgument.getIndex() + i;
|
||||
if (index >= arguments.length) return null;
|
||||
|
||||
FormatDecode.Validator metaValidator = validators[i];
|
||||
if (metaValidator == null) continue;
|
||||
Collection<FormatDecode.Validator> unpacked = metaValidator instanceof FormatDecode.MultiValidator multi ?
|
||||
multi.getValidators() : List.of(metaValidator);
|
||||
if (unpacked.size() != 1) return null;
|
||||
FormatDecode.Validator validator = unpacked.iterator().next();
|
||||
if (validator == null) return null;
|
||||
PsiExpression argument = arguments[index];
|
||||
if (!possibleToConvert(validator, argument)) return null;
|
||||
TextRange stringRange = validator.getRange();
|
||||
if (stringRange == null) return null;
|
||||
TextRange range = ExpressionUtils.findStringLiteralRange(expression, stringRange.getStartOffset(),
|
||||
stringRange.getEndOffset());
|
||||
if (range == null) return null;
|
||||
result.put(range, index);
|
||||
}
|
||||
|
||||
return new StringFormatArgumentToLogCallFix(result, literalExpression.getText());
|
||||
}
|
||||
|
||||
private static boolean possibleToConvert(@NotNull FormatDecode.Validator validator, PsiExpression argument) {
|
||||
FormatDecode.Spec spec = validator.getSpec();
|
||||
if (spec == null) return false;
|
||||
if (spec.conversion() == null ||
|
||||
!StringUtil.isEmpty(spec.width()) ||
|
||||
!StringUtil.isEmpty(spec.dateSpec()) ||
|
||||
!StringUtil.isEmpty(spec.flags()) ||
|
||||
!StringUtil.isEmpty(spec.precision())) {
|
||||
return false;
|
||||
}
|
||||
return switch (spec.conversion()) {
|
||||
case "s" -> true;
|
||||
case "b" -> argument.getType() != null && TypeConversionUtil.isBooleanType(argument.getType());
|
||||
case "d" -> argument.getType() != null && TypeConversionUtil.isIntegralNumberType(argument.getType());
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private enum ProblemType {
|
||||
CONCATENATION, STRING_FORMAT, MESSAGE_FORMAT
|
||||
}
|
||||
|
||||
private class StringConcatenationArgumentToLogCallVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
@@ -356,7 +588,7 @@ public final class StringConcatenationArgumentToLogCallInspection extends BaseIn
|
||||
return;
|
||||
}
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
if (!InheritanceUtil.isInheritor(containingClass, "org.slf4j.Logger") &&
|
||||
if (!InheritanceUtil.isInheritor(containingClass, SLF4J_LOGGER) &&
|
||||
!InheritanceUtil.isInheritor(containingClass, LOG4J_LOGGER) &&
|
||||
!InheritanceUtil.isInheritor(containingClass, LOG4J_BUILDER)) {
|
||||
return;
|
||||
@@ -366,6 +598,19 @@ public final class StringConcatenationArgumentToLogCallInspection extends BaseIn
|
||||
if (arguments.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (arguments.length == 1 && arguments[0] instanceof PsiMethodCallExpression callExpression) {
|
||||
FormatDecode.FormatArgument formatArgument =
|
||||
FormatDecode.FormatArgument.extract(callExpression, List.of("format"), List.of("String"), true);
|
||||
if (formatArgument != null) {
|
||||
registerMethodCallError(expression, ProblemType.STRING_FORMAT, expression, callExpression);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MESSAGE_FORMAT_FORMAT.test(callExpression)) {
|
||||
registerMethodCallError(expression, ProblemType.MESSAGE_FORMAT, expression, callExpression);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PsiExpression argument = arguments[0];
|
||||
if (!ExpressionUtils.hasStringType(argument)) {
|
||||
if (arguments.length < 2) {
|
||||
@@ -379,7 +624,7 @@ public final class StringConcatenationArgumentToLogCallInspection extends BaseIn
|
||||
if (!containsNonConstantConcatenation(argument)) {
|
||||
return;
|
||||
}
|
||||
registerMethodCallError(expression, argument, expression);
|
||||
registerMethodCallError(expression, ProblemType.CONCATENATION, expression, argument);
|
||||
}
|
||||
|
||||
private static boolean containsNonConstantConcatenation(@Nullable PsiExpression expression) {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class LessArgumentsStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(LessArgumentsStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%s something %b %d", "text", true));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class MessageFormatFormatter {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(MessageFormatFormatter.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(MessageFormat.format("{1}, {0, number, #.00}", 1, 2));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class MessageFormatMissingParameter {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(MessageFormatMissingParameter.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(MessageFormat.format("{2}, 2 {1} {0} {126}", "1", 2, 3.0));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class SimpleMessMessageFormatMoreArguments {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleMessMessageFormatMoreArguments.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(MessageFormat.format("{2}, 2 {1} {0}", "1", 2, 3.0, 125));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class MoreArgumentsStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(MoreArgumentsStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%s something %b %d", "text", true, 1, 125));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class NumberedStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(NumberedStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo("{} {} {} {}", "d", "c", "b", "a");
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class NumberedStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(NumberedStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%4$s %3$s %2$s %1$s", "a", "b", "c", "d"));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class SimpleStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%s test %<s %<s", "test"));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class SimpleMessageFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleMessageFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.info("{}, 2 {} {}", 3.0, 2, "1");
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class SimpleMessageFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleMessageFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(MessageFormat.format("{2}, 2 {1} {0}", "1", 2, 3.0));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class SimpleStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo("{} something {} {}", "text", true, 1);
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class SimpleStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%s something %b %d", "text", true, 1));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class StringFormatWithWidth {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(SimpleMessageFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d"));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class WrongStringFormat {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(WrongStringFormat.class);
|
||||
|
||||
void f() {
|
||||
LOG.in<caret>fo(String.format("%d something %D %d", "text", true, 1));
|
||||
}
|
||||
|
||||
}
|
||||
+24
-2
@@ -13,12 +13,12 @@ public class StringConcatenationArgumentToLogCallFixTest extends IGQuickFixesTes
|
||||
super.setUp();
|
||||
myDefaultHint = InspectionGadgetsBundle.message("string.concatenation.argument.to.log.call.quickfix");
|
||||
myFixture.addClass("package org.slf4j; public interface Logger { void info(String format); }");
|
||||
myFixture.addClass("package org.slf4j; public class LoggerFactory { public static Logger getLogger(Class clazz) { return null; }}");
|
||||
myFixture.addClass("package org.slf4j; public final class LoggerFactory { public static Logger getLogger(Class clazz) { return null; }}");
|
||||
myFixture.addClass("package org.apache.logging.log4j; public interface LogBuilder { void log(String format); LogBuilder withLocation(); }");
|
||||
myFixture.addClass("package org.apache.logging.log4j; public interface Logger { LogBuilder atInfo(); void info(String format, Object... arguments); LogBuilder withLocation(); }");
|
||||
myFixture.addClass("""
|
||||
package org.apache.logging.log4j;
|
||||
public class LogManager {
|
||||
public final class LogManager {
|
||||
public static Logger getLogger(Class clazz) {
|
||||
return null;
|
||||
}
|
||||
@@ -26,6 +26,14 @@ public class StringConcatenationArgumentToLogCallFixTest extends IGQuickFixesTes
|
||||
return null;
|
||||
}
|
||||
}""");
|
||||
|
||||
myFixture.addClass( """
|
||||
package java.text;
|
||||
public final class MessageFormat {
|
||||
public static String format(String format, Object... params);
|
||||
}"""
|
||||
);
|
||||
|
||||
myFixture.enableInspections(new StringConcatenationArgumentToLogCallInspection());
|
||||
}
|
||||
|
||||
@@ -42,6 +50,20 @@ public class StringConcatenationArgumentToLogCallFixTest extends IGQuickFixesTes
|
||||
InspectionGadgetsBundle.message("string.concatenation.argument.to.log.call.display.name")));
|
||||
}
|
||||
|
||||
public void testSimpleMessageFormat() { doTest(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.message.format.call.quickfix")); }
|
||||
public void testMessageFormatMissingParameter() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.message.format.call.quickfix")); }
|
||||
public void testMessageFormatMoreArguments() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.message.format.call.quickfix")); }
|
||||
public void testMessageFormatFormatter() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.message.format.call.quickfix")); }
|
||||
|
||||
public void testSimpleStringFormat() { doTest(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
public void testStringFormatWithWidth() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
public void testNumberedStringFormat() { doTest(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
public void testWrongStringFormat() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
public void testLessArgumentsStringFormat() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
public void testMoreArgumentsStringFormat() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
public void testPreviousArgumentStringFormat() { assertQuickfixNotAvailable(InspectionGadgetsBundle.message("string.concatenation.argument.to.log.string.format.call.quickfix")); }
|
||||
|
||||
|
||||
@Override
|
||||
protected String getRelativePath() {
|
||||
return "logging/string_concatenation_argument_to_log_call";
|
||||
|
||||
+40
-9
@@ -38,7 +38,7 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
|
||||
"""
|
||||
package org.slf4j;\s
|
||||
public class LoggerFactory {
|
||||
public final class LoggerFactory {
|
||||
public static Logger getLogger(Class clazz) {
|
||||
return null;\s
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
|
||||
"""
|
||||
package org.apache.logging.log4j;
|
||||
public class LogManager {
|
||||
public final class LogManager {
|
||||
public static Logger getLogger() {
|
||||
return null;
|
||||
}
|
||||
@@ -69,6 +69,11 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
public interface LogBuilder {
|
||||
void log(String format, Object p0);
|
||||
void log(String format, Object... params);
|
||||
}""",
|
||||
"""
|
||||
package java.text;
|
||||
public final class MessageFormat {
|
||||
public static String format(String format, Object... params);
|
||||
}"""
|
||||
};
|
||||
}
|
||||
@@ -81,7 +86,7 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
Logger logger = LoggerFactory.getLogger(X.class);
|
||||
final String CONST = "const";
|
||||
String var = "var";
|
||||
logger./*Non-constant string concatenation as argument to 'debug()' logging call*/debug/**/("string " + var + CONST);
|
||||
logger./*Evaluated string as argument to 'debug()' logging call*/debug/**/("string " + var + CONST);
|
||||
}
|
||||
}"""
|
||||
);
|
||||
@@ -104,8 +109,8 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
class Logging {
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
void m(int i) {
|
||||
LOG./*Non-constant string concatenation as argument to 'info()' logging call*/info/**/("hello? " + i);
|
||||
LOG./*Non-constant string concatenation as argument to 'fatal()' logging call*/fatal/**/("you got me " + i);
|
||||
LOG./*Evaluated string as argument to 'info()' logging call*/info/**/("hello? " + i);
|
||||
LOG./*Evaluated string as argument to 'fatal()' logging call*/fatal/**/("you got me " + i);
|
||||
}
|
||||
}""");
|
||||
}
|
||||
@@ -114,12 +119,12 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
doTest("""
|
||||
import org.apache.logging.log4j.*;
|
||||
|
||||
class Log4JFormatted {
|
||||
final class Log4JFormatted {
|
||||
|
||||
private static final Logger logger = LogManager.getFormattedLogger();
|
||||
|
||||
public static void m(String a) {
|
||||
logger./*Non-constant string concatenation as argument to 'info()' logging call*/info/**/("1" + "2" + a);
|
||||
logger./*Evaluated string as argument to 'info()' logging call*/info/**/("1" + "2" + a);
|
||||
}
|
||||
}""");
|
||||
}
|
||||
@@ -130,9 +135,35 @@ public class StringConcatenationArgumentToLogCallInspectionTest extends LightJav
|
||||
class Logging {
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
void m(int i) {
|
||||
LOG.atDebug()./*Non-constant string concatenation as argument to 'log()' logging call*/log/**/("hello? " + i);
|
||||
LOG.atInfo()./*Non-constant string concatenation as argument to 'log()' logging call*/log/**/("you got me " + i);
|
||||
LOG.atDebug()./*Evaluated string as argument to 'log()' logging call*/log/**/("hello? " + i);
|
||||
LOG.atInfo()./*Evaluated string as argument to 'log()' logging call*/log/**/("you got me " + i);
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
|
||||
public void testSlfStringFormat() {
|
||||
doTest("""
|
||||
import org.slf4j.*;
|
||||
class X {
|
||||
void foo() {
|
||||
Logger log = LoggerFactory.getLogger(X.class);
|
||||
log./*Evaluated string as argument to 'info()' logging call*/info/**/(String.format("%s %d", "1", 1));
|
||||
}
|
||||
}"""
|
||||
);
|
||||
}
|
||||
public void testSlfMessageFormat() {
|
||||
doTest("""
|
||||
import org.slf4j.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class X {
|
||||
void foo() {
|
||||
Logger log = LoggerFactory.getLogger(X.class);
|
||||
log./*Evaluated string as argument to 'info()' logging call*/info/**/(MessageFormat.format("{1}, {0}", "1", 2));
|
||||
}
|
||||
}"""
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user