2 * Copyright 2000-2014 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.codeInspection.equalsAndHashcode;
18 import com.intellij.codeInspection.*;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.roots.ProjectRootManager;
22 import com.intellij.openapi.util.Computable;
23 import com.intellij.openapi.util.Pair;
24 import com.intellij.psi.*;
25 import com.intellij.psi.search.GlobalSearchScope;
26 import com.intellij.psi.util.CachedValueProvider;
27 import com.intellij.psi.util.CachedValuesManager;
28 import com.intellij.psi.util.MethodSignatureUtil;
29 import org.jetbrains.annotations.NonNls;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
36 public class EqualsAndHashcodeBase extends BaseJavaBatchLocalInspectionTool {
39 public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
40 final Project project = holder.getProject();
41 Pair<PsiMethod, PsiMethod> pair = CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<Pair<PsiMethod, PsiMethod>>() {
43 public Result<Pair<PsiMethod, PsiMethod>> compute() {
44 final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
45 final PsiClass psiObjectClass = ApplicationManager.getApplication().runReadAction(
46 new Computable<PsiClass>() {
49 public PsiClass compute() {
50 return psiFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT, GlobalSearchScope.allScope(project));
54 if (psiObjectClass == null) {
55 return Result.create(null, ProjectRootManager.getInstance(project));
57 PsiMethod[] methods = psiObjectClass.getMethods();
58 PsiMethod myEquals = null;
59 PsiMethod myHashCode = null;
60 for (PsiMethod method : methods) {
61 @NonNls final String name = method.getName();
62 if ("equals".equals(name)) {
65 else if ("hashCode".equals(name)) {
69 return Result.create(Pair.create(myEquals, myHashCode), psiObjectClass);
73 if (pair == null) return new PsiElementVisitor() {};
75 //jdk wasn't configured for the project
76 final PsiMethod myEquals = pair.first;
77 final PsiMethod myHashCode = pair.second;
78 if (myEquals == null || myHashCode == null || !myEquals.isValid() || !myHashCode.isValid()) return new PsiElementVisitor() {};
80 return new JavaElementVisitor() {
81 @Override public void visitClass(PsiClass aClass) {
82 super.visitClass(aClass);
83 boolean [] hasEquals = {false};
84 boolean [] hasHashCode = {false};
85 processClass(aClass, hasEquals, hasHashCode, myEquals, myHashCode);
86 if (hasEquals[0] != hasHashCode[0]) {
87 PsiIdentifier identifier = aClass.getNameIdentifier();
88 holder.registerProblem(identifier != null ? identifier : aClass,
90 ? InspectionsBundle.message("inspection.equals.hashcode.only.one.defined.problem.descriptor", "<code>equals()</code>", "<code>hashCode()</code>")
91 : InspectionsBundle.message("inspection.equals.hashcode.only.one.defined.problem.descriptor","<code>hashCode()</code>", "<code>equals()</code>"),
92 buildFixes(isOnTheFly, hasEquals[0]));
98 private static void processClass(final PsiClass aClass,
99 final boolean[] hasEquals,
100 final boolean[] hasHashCode,
101 PsiMethod equals, PsiMethod hashcode) {
102 final PsiMethod[] methods = aClass.getMethods();
103 for (PsiMethod method : methods) {
104 if (MethodSignatureUtil.areSignaturesEqual(method, equals)) {
107 else if (MethodSignatureUtil.areSignaturesEqual(method, hashcode)) {
108 hasHashCode[0] = true;
115 public String getDisplayName() {
116 return InspectionsBundle.message("inspection.equals.hashcode.display.name");
121 public String getGroupDisplayName() {
127 public String getShortName() {
128 return "EqualsAndHashcode";
131 protected LocalQuickFix[] buildFixes(boolean isOnTheFly, boolean hasEquals) {
132 return LocalQuickFix.EMPTY_ARRAY;