InvalidComparatorMethodReferenceInspection: fixes according to IDEA-CR-13278
[idea/community.git] / java / java-analysis-impl / src / com / intellij / codeInspection / InvalidComparatorMethodReferenceInspection.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeInspection;
17
18 import com.intellij.codeInsight.FileModificationService;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.psi.*;
21 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
22 import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionBase;
23 import org.jetbrains.annotations.Nls;
24 import org.jetbrains.annotations.NotNull;
25
26 public class InvalidComparatorMethodReferenceInspection extends BaseJavaBatchLocalInspectionTool {
27   @NotNull
28   @Override
29   public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
30     return new JavaElementVisitor() {
31       @Override
32       public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
33         PsiExpression qualifierExpression = expression.getQualifierExpression();
34         PsiElement referenceNameElement = expression.getReferenceNameElement();
35         if (!(qualifierExpression instanceof PsiReferenceExpressionBase) || referenceNameElement == null) {
36           return;
37         }
38         String name = referenceNameElement.getText();
39         if (!name.equals("min") && !name.equals("max")) {
40           return;
41         }
42         PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
43         if (!(functionalInterfaceType instanceof PsiClassType)) {
44           return;
45         }
46         PsiClass targetType = ((PsiClassType)functionalInterfaceType).resolve();
47         if (targetType == null) {
48           return;
49         }
50         String targetClassName = targetType.getQualifiedName();
51         if(targetClassName == null || !targetClassName.equals(CommonClassNames.JAVA_UTIL_COMPARATOR)) {
52           return;
53         }
54         PsiElement refType = ((PsiReference)qualifierExpression).resolve();
55         if (!(refType instanceof PsiClass)) {
56           return;
57         }
58         String className = ((PsiClass)refType).getQualifiedName();
59         if (className == null || (!className.equals(CommonClassNames.JAVA_LANG_INTEGER) && !className.equals(Math.class.getName()))) {
60           return;
61         }
62         //noinspection DialogTitleCapitalization
63         holder
64           .registerProblem(expression,
65                            "Method reference mapped to Comparator interface does not fulfill the Comparator contract",
66                            new ReplaceWithComparatorQuickFix(name.equals("min")));
67       }
68     };
69   }
70
71   private static class ReplaceWithComparatorQuickFix implements LocalQuickFix {
72     private final boolean reverse;
73
74     public ReplaceWithComparatorQuickFix(boolean reverse) {
75       this.reverse = reverse;
76     }
77
78     @Nls
79     @NotNull
80     @Override
81     public String getName() {
82       return "Replace with " + (reverse ? "Comparator.reverseOrder()" : "Comparator.naturalOrder()");
83     }
84
85     @Nls
86     @NotNull
87     @Override
88     public String getFamilyName() {
89       return "Replace with comparator";
90     }
91
92     @Override
93     public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
94       PsiElement element = descriptor.getPsiElement();
95       if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
96       PsiElement parent = element.getParent();
97       if (parent != null) {
98         PsiExpression newMethodExpression = JavaPsiFacade.getElementFactory(project)
99           .createExpressionFromText(CommonClassNames.JAVA_UTIL_COMPARATOR + "." + (reverse ? "reverseOrder()" : "naturalOrder()"), parent);
100         PsiElement shortMethodExpression = JavaCodeStyleManager.getInstance(project).shortenClassReferences(newMethodExpression);
101         element.replace(shortMethodExpression);
102       }
103     }
104   }
105 }