2 * Copyright 2000-2009 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
.BaseJavaLocalInspectionTool
;
19 import com
.intellij
.codeInspection
.InspectionsBundle
;
20 import com
.intellij
.codeInspection
.LocalQuickFix
;
21 import com
.intellij
.codeInspection
.ProblemsHolder
;
22 import com
.intellij
.openapi
.application
.ApplicationManager
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.util
.Computable
;
25 import com
.intellij
.psi
.*;
26 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
27 import org
.jetbrains
.annotations
.NonNls
;
28 import org
.jetbrains
.annotations
.NotNull
;
29 import org
.jetbrains
.annotations
.Nullable
;
31 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
36 public class EqualsAndHashcode
extends BaseJavaLocalInspectionTool
{
38 private PsiMethod myHashCode
;
39 private PsiMethod myEquals
;
40 private JavaPsiFacade myPsiFacade
;
41 private final AtomicBoolean myInitialized
= new AtomicBoolean();
43 public void projectOpened(Project project
) {
44 myPsiFacade
= JavaPsiFacade
.getInstance(project
);
48 public PsiElementVisitor
buildVisitor(@NotNull final ProblemsHolder holder
, boolean isOnTheFly
) {
49 if (!myInitialized
.getAndSet(true)) {
50 final PsiClass psiObjectClass
= ApplicationManager
.getApplication().runReadAction(
51 new Computable
<PsiClass
>() {
53 public PsiClass
compute() {
54 return myPsiFacade
.findClass("java.lang.Object");
58 if (psiObjectClass
!= null) {
59 PsiMethod
[] methods
= psiObjectClass
.getMethods();
60 for (PsiMethod method
: methods
) {
61 @NonNls final String name
= method
.getName();
62 if ("equals".equals(name
)) {
65 else if ("hashCode".equals(name
)) {
72 //jdk wasn't configured for the project
73 if (myEquals
== null || myHashCode
== null || !myEquals
.isValid() || !myHashCode
.isValid()) return new PsiElementVisitor() {};
75 return new JavaElementVisitor() {
76 @Override public void visitClass(PsiClass aClass
) {
77 super.visitClass(aClass
);
78 boolean [] hasEquals
= new boolean[] {false};
79 boolean [] hasHashCode
= new boolean[] {false};
80 processClass(aClass
, hasEquals
, hasHashCode
);
81 if (hasEquals
[0] != hasHashCode
[0]) {
82 PsiIdentifier identifier
= aClass
.getNameIdentifier();
83 holder
.registerProblem(identifier
!= null ? identifier
: aClass
,
85 ? InspectionsBundle
.message("inspection.equals.hashcode.only.one.defined.problem.descriptor", "<code>equals()</code>", "<code>hashCode()</code>")
86 : InspectionsBundle
.message("inspection.equals.hashcode.only.one.defined.problem.descriptor","<code>hashCode()</code>", "<code>equals()</code>"),
87 (LocalQuickFix
[])null);
91 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
97 private void processClass(final PsiClass aClass
, final boolean[] hasEquals
, final boolean[] hasHashCode
) {
98 final PsiMethod
[] methods
= aClass
.getMethods();
99 for (PsiMethod method
: methods
) {
100 if (MethodSignatureUtil
.areSignaturesEqual(method
, myEquals
)) {
103 else if (MethodSignatureUtil
.areSignaturesEqual(method
, myHashCode
)) {
104 hasHashCode
[0] = true;
110 public String
getDisplayName() {
111 return InspectionsBundle
.message("inspection.equals.hashcode.display.name");
115 public String
getGroupDisplayName() {
120 public String
getShortName() {
121 return "EqualsAndHashcode";
124 public void projectClosed(Project project
) {