newArguments = new ArrayList();
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ for (PsiExpression operand : operands) {
+ if (operand instanceof PsiLiteralExpression) {
+ final String text = operand.getText();
+ final int count = StringUtil.getOccurrenceCount(text, "{}");
+ for (int i = 0; i < count && usedArguments + i < arguments.length; i++) {
+ newArguments.add((PsiExpression)arguments[i + usedArguments].copy());
+ }
+ usedArguments += count;
+ newMethodCall.append(text.substring(1, text.length() - 1));
+ }
+ else {
+ newArguments.add((PsiExpression)operand.copy());
+ newMethodCall.append("{}");
+ }
+ }
+ while (usedArguments < arguments.length) {
+ newArguments.add(arguments[usedArguments++]);
+ }
+ newMethodCall.append('"');
+ if (!varArgs && newArguments.size() > 2) {
+ newMethodCall.append(", new Object[]{");
+ boolean comma = false;
+ for (PsiExpression newArgument : newArguments) {
+ if (comma) {
+ newMethodCall.append(',');
+ }
+ else {
+ comma =true;
+ }
+ newMethodCall.append(newArgument.getText());
+ }
+ newMethodCall.append('}');
+ }
+ else {
+ for (PsiExpression newArgument : newArguments) {
+ newMethodCall.append(',').append(newArgument.getText());
+ }
+ }
+ newMethodCall.append(')');
+ replaceExpression(methodCallExpression, newMethodCall.toString());
+ }
+
+ public static int isAvailable(PsiExpression expression) {
+ int count = 0;
+ if (!(expression instanceof PsiPolyadicExpression)) {
+ return count;
+ }
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ for (PsiExpression operand : operands) {
+ if (operand instanceof PsiLiteralExpression) {
+ if (!ExpressionUtils.hasStringType(operand)) {
+ return count;
+ }
+ continue;
+ }
+ if (!(operand instanceof PsiReferenceExpression)) {
+ return count;
+ }
+ count++;
+ }
+ return count;
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new StringConcatenationArgumentToLogCallVisitor();
+ }
+
+ private static class StringConcatenationArgumentToLogCallVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String referenceName = methodExpression.getReferenceName();
+ if (!logNames.contains(referenceName)) {
+ return;
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null || !"org.slf4j.Logger".equals(containingClass.getQualifiedName())) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length == 0) {
+ return;
+ }
+ PsiExpression argument = arguments[0];
+ if (!ExpressionUtils.hasStringType(argument)) {
+ if (arguments.length < 2) {
+ return;
+ }
+ argument = arguments[1];
+ if (!ExpressionUtils.hasStringType(argument)) {
+ return;
+ }
+ }
+ argument = ParenthesesUtils.stripParentheses(argument);
+ if (argument == null || !containsConcatenation(argument)) {
+ return;
+ }
+ registerMethodCallError(expression, argument);
+ }
+
+ private static boolean containsConcatenation(@Nullable PsiExpression expression) {
+ if (expression instanceof PsiParenthesizedExpression) {
+ final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
+ containsConcatenation(parenthesizedExpression.getExpression());
+ }
+ else if (expression instanceof PsiPolyadicExpression) {
+ final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
+ if (!ExpressionUtils.hasStringType(polyadicExpression)) {
+ return false;
+ }
+ final IElementType tokenType = polyadicExpression.getOperationTokenType();
+ if (!JavaTokenType.PLUS.equals(tokenType)) {
+ return false;
+ }
+ final PsiExpression[] operands = polyadicExpression.getOperands();
+ for (PsiExpression operand : operands) {
+ if (operand instanceof PsiReferenceExpression) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenationArgumentToLogCall.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenationArgumentToLogCall.html
new file mode 100644
index 000000000000..1d12ca412f2d
--- /dev/null
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenationArgumentToLogCall.html
@@ -0,0 +1,10 @@
+
+
+This inspection reports non-constant string concatenations used as an argument to a SLF4J log method.
+Concatenation will be evaluated even when the logging message will not be logged; this can negatively impact performance.
+It is recommended to use parameterization instead which will only be evaluated when the string is actually logged and not when logging is disabled.
+
+
+New in 12, Powered by InspectionGadgets
+
+
\ No newline at end of file