PsiElementVisitor (@NotNull final ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) { return new JavaElementVisitor() { @Override public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) { final PsiReferenceExpression methodExpression = expression.getMethodExpression(); final PsiElement nameElement = methodExpression.getReferenceNameElement(); final String methodName = methodExpression.getReferenceName(); if (nameElement == null || !"addAll".equals(methodName) && !"putAll".equals(methodName)) return; PsiExpression[] args = expression.getArgumentList().getExpressions(); if (args.length != 1) return; final PsiExpressionStatement parent = ObjectUtils.tryCast(expression.getParent(), PsiExpressionStatement.class); if (parent == null) return; PsiLocalVariable variable = ExpressionUtils.resolveLocalVariable(methodExpression.getQualifierExpression()); if (variable == null) return; if (PsiUtil.resolveClassInClassTypeOnly(variable.getType()) == null) return; if (statementHasSubsequentAddAll(parent, variable, methodName)) return; PsiType argType = args[0].getType(); if (!InheritanceUtil.isInheritor(argType, "putAll".equals(methodName) ? CommonClassNames.JAVA_UTIL_MAP : CommonClassNames.JAVA_UTIL_COLLECTION)) { return; } InitializerUsageStatus status = ControlFlowUtils.getInitializerUsageStatus(variable, parent); PsiNewExpression assignmentExpression; if (status == InitializerUsageStatus.DECLARED_JUST_BEFORE || status == InitializerUsageStatus.AT_WANTED_PLACE_ONLY) { if (!isCollectionConstructor(variable.getInitializer())) return; assignmentExpression = (PsiNewExpression)variable.getInitializer(); } else { assignmentExpression = getPreviousAssignment(variable, parent); } if (assignmentExpression == null || !isAddAllReplaceable(expression, assignmentExpression)) return; if (mayInheritComparator(args, argType, assignmentExpression)) return; final PsiMethod method = expression.resolveMethod(); if (method != null) { holder.registerProblem(nameElement, QuickFixBundle.message("collection.addall.can.be.replaced.with.constructor.fix.description"), new ReplaceAddAllWithConstructorFix(assignmentExpression, expression, methodName)); } } private boolean mayInheritComparator(PsiExpression[] args, PsiType argType, PsiNewExpression assignmentExpression) { PsiType type = assignmentExpression.getType(); PsiClass collectionType = Objects.requireNonNull(PsiUtil.resolveClassInClassTypeOnly(type)); String name = Objects.requireNonNull(collectionType.getQualifiedName()); return switch (name) { case "java.util.TreeSet", "java.util.concurrent.ConcurrentSkipListSet" -> // If declared arg type inherits SortedSet, the (SortedSet) copy constructor will be invoked, which inherits the comparator InheritanceUtil.isInheritor(argType, "java.util.SortedSet"); case "java.util.TreeMap", "java.util.concurrent.ConcurrentSkipListMap" -> // If declared arg type inherits SortedMap, the (SortedMap) copy constructor will be invoked, which inherits the comparator InheritanceUtil.isInheritor(argType, "java.util.SortedMap"); case "java.util.PriorityQueue", "java.util.concurrent.PriorityBlockingQueue" -> { // Here even (Collection) copy constructor inherits the comparator using runtime type checks, so we should be more conservative TypeConstraint constraint = TypeConstraint.fromDfType(CommonDataflow.getDfType(args[0])); PsiClassType sortedSet = JavaPsiFacade.getElementFactory(holder.getProject()).createTypeByFQClassName("java.util.SortedSet"); yield constraint.meet(TypeConstraints.instanceOf(sortedSet)) != TypeConstraints.BOTTOM || constraint.meet(TypeConstraints.instanceOf(type)) != TypeConstraints.BOTTOM; } default -> false; }; } }; }