PsiElementVisitor (@NotNull ProblemsHolder holder, boolean isOnTheFly) { if (!HighlightingFeature.STRING_TEMPLATES.isAvailable(holder.getFile())) return PsiElementVisitor.EMPTY_VISITOR; return new JavaElementVisitor() { @Override public void visitPolyadicExpression(@NotNull PsiPolyadicExpression expression) { if (expression.getOperationTokenType() != JavaTokenType.PLUS) return; if (!ExpressionUtils.hasStringType(expression)) return; final ProblemHighlightType type = getProblemHighlightType(expression); if (type == null || (type == ProblemHighlightType.INFORMATION && !isOnTheFly)) return; holder.registerProblem(expression, JavaBundle.message("inspection.string.template.migration.string.message"), type, new ReplaceWithStringTemplateFix()); } @Nullable private static ProblemHighlightType getProblemHighlightType(@NotNull PsiPolyadicExpression expression) { PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiExpression.class); if (parent instanceof PsiNameValuePair || parent instanceof PsiCaseLabelElementList || parent instanceof PsiAnnotationMethod) { return null; } boolean hasString = false; boolean hasNotLiteralExpression = false; boolean hasLiteralExpression = false; for (PsiExpression operand : expression.getOperands()) { // Support for template concatenation is not yet implemented. if (operand instanceof PsiTemplateExpression) { return null; } if (operand instanceof PsiLiteralExpression && ExpressionUtils.hasStringType(operand)) { hasString = true; } // (1 + 2) * 3 + "str" else if (!isOnlyLiterals(operand)) { hasNotLiteralExpression = true; } else { hasLiteralExpression = true; } } // "str" + str if (hasString && hasNotLiteralExpression) { return ProblemHighlightType.WEAK_WARNING; } // (str + str) || "str" + 1 + 2) if (hasNotLiteralExpression || (hasString && hasLiteralExpression) || PsiUtil.isConstantExpression(expression)) { return ProblemHighlightType.INFORMATION; } else { return null; } } private static boolean isOnlyLiterals(@NotNull PsiExpression operand) { if (operand instanceof PsiLiteralExpression) { return true; } else if (operand instanceof PsiPolyadicExpression polyadic) { for (PsiExpression expression : polyadic.getOperands()) { if (!isOnlyLiterals(expression)) return false; } return true; } else if (operand instanceof PsiParenthesizedExpression) { final PsiExpression expression = PsiUtil.skipParenthesizedExprDown(operand); if (expression != null && !isOnlyLiterals(expression)) return false; return true; } else { return false; } } }; }