primitive type comparison internal inspection
[idea/community.git] / plugins / devkit / src / inspections / internal / UsePrimitiveTypesInspection.java
1 /*
2  * Copyright 2000-2015 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 org.jetbrains.idea.devkit.inspections.internal;
17
18 import com.intellij.codeInspection.LocalQuickFix;
19 import com.intellij.codeInspection.ProblemDescriptor;
20 import com.intellij.codeInspection.ProblemsHolder;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.psi.*;
23 import com.intellij.psi.tree.IElementType;
24 import com.intellij.psi.util.PsiUtil;
25 import com.siyeh.IntentionPowerPackBundle;
26 import com.siyeh.ig.PsiReplacementUtil;
27 import org.jetbrains.annotations.Nls;
28 import org.jetbrains.annotations.NonNls;
29 import org.jetbrains.annotations.NotNull;
30
31 public class UsePrimitiveTypesInspection extends InternalInspection {
32   @Override
33   public PsiElementVisitor buildInternalVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
34     return new JavaElementVisitor() {
35       @Override
36       public void visitBinaryExpression(PsiBinaryExpression expression) {
37         super.visitBinaryExpression(expression);
38         final IElementType tokenType = expression.getOperationTokenType();
39         if (tokenType.equals(JavaTokenType.EQEQ) || tokenType.equals(JavaTokenType.NE)) {
40           final PsiExpression lOperand = expression.getLOperand();
41           final PsiExpression rOperand = expression.getROperand();
42           if (rOperand != null && (isPrimitiveTypeRef(lOperand) || isPrimitiveTypeRef(rOperand))) {
43             final String name;
44             if (JavaTokenType.NE.equals(tokenType)) {
45               name = IntentionPowerPackBundle.message("replace.equality.with.not.equals.intention.name");
46             }
47             else {
48               name = IntentionPowerPackBundle.message("replace.equality.with.equals.intention.name");
49             }
50             holder.registerProblem(expression.getOperationSign(),
51                                    "Primitive types should be compared with .equals",
52                                    new ReplaceEqualityWithEqualsFix(name));
53           }
54         }
55       }
56     };
57   }
58   
59   private static boolean isPrimitiveTypeRef(PsiExpression expression) {
60     if (expression instanceof PsiReferenceExpression) {
61       final PsiElement target = ((PsiReferenceExpression)expression).resolve();
62       if (target instanceof PsiField) {
63         final PsiClass containingClass = ((PsiField)target).getContainingClass();
64         return containingClass != null && 
65                PsiType.class.getName().equals(containingClass.getQualifiedName()) && 
66                !"NULL".equals(((PsiField)target).getName());
67       }
68     }
69     return false;
70   }
71
72   private static class ReplaceEqualityWithEqualsFix implements LocalQuickFix {
73     private final String myName;
74
75     public ReplaceEqualityWithEqualsFix(String name) {
76       myName = name;
77     }
78
79     @Nls
80     @NotNull
81     @Override
82     public String getName() {
83       return myName;
84     }
85
86     @Nls
87     @NotNull
88     @Override
89     public String getFamilyName() {
90       return "Replace equality with .equals";
91     }
92
93     @Override
94     public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
95       final PsiElement psiElement = descriptor.getPsiElement();
96       if (psiElement instanceof PsiJavaToken) {
97
98         final IElementType tokenType = ((PsiJavaToken)psiElement).getTokenType();
99         final String prefix;
100         if (tokenType.equals(JavaTokenType.EQEQ)) {
101           prefix = "";
102         }
103         else if (tokenType.equals(JavaTokenType.NE)) {
104           prefix = "!";
105         }
106         else {
107           return;
108         }
109
110         final PsiElement parent = psiElement.getParent();
111         if (parent instanceof PsiBinaryExpression) {
112           final PsiExpression rOperand = ((PsiBinaryExpression)parent).getROperand();
113           final PsiExpression lOperand = ((PsiBinaryExpression)parent).getLOperand();
114           if (rOperand != null) {
115             final boolean flip = isPrimitiveTypeRef(rOperand);
116             if (flip || isPrimitiveTypeRef(lOperand)) {
117               final String rText = PsiUtil.skipParenthesizedExprUp(rOperand).getText();
118               final String lText = PsiUtil.skipParenthesizedExprUp(lOperand).getText();
119
120               final String lhText = flip ? rText : lText;
121               final String rhText = flip ? lText : rText;
122
123               @NonNls final String expString = prefix + lhText + ".equals(" + rhText + ')';
124               PsiReplacementUtil.replaceExpression((PsiBinaryExpression)parent, expString);
125             }
126           }
127         }
128       }
129     }
130   }
131 }