blob: 4c41d90a9afac79578556c1f7ccd568f573f8dcd [file] [log] [blame]
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.equalsAndHashcode;
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.MethodSignatureUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author max
*/
public class EqualsAndHashcode extends BaseJavaBatchLocalInspectionTool {
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
final Project project = holder.getProject();
Pair<PsiMethod, PsiMethod> pair = CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<Pair<PsiMethod, PsiMethod>>() {
@Override
public Result<Pair<PsiMethod, PsiMethod>> compute() {
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiClass psiObjectClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Override
@Nullable
public PsiClass compute() {
return psiFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT, GlobalSearchScope.allScope(project));
}
}
);
if (psiObjectClass == null) {
return Result.create(null, ProjectRootManager.getInstance(project));
}
PsiMethod[] methods = psiObjectClass.getMethods();
PsiMethod myEquals = null;
PsiMethod myHashCode = null;
for (PsiMethod method : methods) {
@NonNls final String name = method.getName();
if ("equals".equals(name)) {
myEquals = method;
}
else if ("hashCode".equals(name)) {
myHashCode = method;
}
}
return Result.create(Pair.create(myEquals, myHashCode), psiObjectClass);
}
});
if (pair == null) return new PsiElementVisitor() {};
//jdk wasn't configured for the project
final PsiMethod myEquals = pair.first;
final PsiMethod myHashCode = pair.second;
if (myEquals == null || myHashCode == null || !myEquals.isValid() || !myHashCode.isValid()) return new PsiElementVisitor() {};
return new JavaElementVisitor() {
@Override public void visitClass(PsiClass aClass) {
super.visitClass(aClass);
boolean [] hasEquals = {false};
boolean [] hasHashCode = {false};
processClass(aClass, hasEquals, hasHashCode, myEquals, myHashCode);
if (hasEquals[0] != hasHashCode[0]) {
PsiIdentifier identifier = aClass.getNameIdentifier();
holder.registerProblem(identifier != null ? identifier : aClass,
hasEquals[0]
? InspectionsBundle.message("inspection.equals.hashcode.only.one.defined.problem.descriptor", "<code>equals()</code>", "<code>hashCode()</code>")
: InspectionsBundle.message("inspection.equals.hashcode.only.one.defined.problem.descriptor","<code>hashCode()</code>", "<code>equals()</code>"),
(LocalQuickFix[])null);
}
}
};
}
private static void processClass(final PsiClass aClass,
final boolean[] hasEquals,
final boolean[] hasHashCode,
PsiMethod equals, PsiMethod hashcode) {
final PsiMethod[] methods = aClass.getMethods();
for (PsiMethod method : methods) {
if (MethodSignatureUtil.areSignaturesEqual(method, equals)) {
hasEquals[0] = true;
}
else if (MethodSignatureUtil.areSignaturesEqual(method, hashcode)) {
hasHashCode[0] = true;
}
}
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("inspection.equals.hashcode.display.name");
}
@Override
@NotNull
public String getGroupDisplayName() {
return "";
}
@Override
@NotNull
public String getShortName() {
return "EqualsAndHashcode";
}
}