package com.intellij.codeInspection.equalsAndHashcode;

import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.MethodSignatureUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

/**
 * @author max
 */
public class EqualsAndHashcode extends BaseJavaLocalInspectionTool {

  private PsiMethod myHashCode;
  private PsiMethod myEquals;

  public void projectOpened(Project project) {
    final PsiManager psiManager = PsiManager.getInstance(project);
    final PsiClass psiObjectClass = psiManager.findClass("java.lang.Object");
    if (psiObjectClass != null) {
      PsiMethod[] methods = psiObjectClass.getMethods();
      for (PsiMethod method : methods) {
        @NonNls final String name = method.getName();
        if ("equals".equals(name)) {
          myEquals = method;
        }
        else if ("hashCode".equals(name)) {
          myHashCode = method;
        }
      }
    }
  }

  @NotNull
  public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
    //jdk wasn't configured for the project
    if (myEquals == null || myHashCode == null || !myEquals.isValid() || !myHashCode.isValid()) return new PsiElementVisitor() {
      public void visitReferenceExpression(final PsiReferenceExpression expression) {
      }
    };
    return new PsiElementVisitor() {
      public void visitClass(PsiClass aClass) {
        super.visitClass(aClass);
        boolean [] hasEquals = new boolean[] {false};
        boolean [] hasHashCode = new boolean[] {false};
        processClass(aClass, hasEquals, hasHashCode);
        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);
        }
      }

      public void visitReferenceExpression(PsiReferenceExpression expression) {
        //do nothing
      }
    };
  }

  private void processClass(final PsiClass aClass, final boolean[] hasEquals, final boolean[] hasHashCode) {
    final PsiMethod[] methods = aClass.getMethods();
    for (PsiMethod method : methods) {
      if (MethodSignatureUtil.areSignaturesEqual(method, myEquals)) {
        hasEquals[0] = true;
      }
      else if (MethodSignatureUtil.areSignaturesEqual(method, myHashCode)) {
        hasHashCode[0] = true;
      }
    }
  }

  @NotNull
  public String getDisplayName() {
    return InspectionsBundle.message("inspection.equals.hashcode.display.name");
  }

  @NotNull
  public String getGroupDisplayName() {
    return "";
  }

  @NotNull
  public String getShortName() {
    return "EqualsAndHashcode";
  }

  public void projectClosed(Project project) {
    myEquals = null;
    myHashCode = null;
  }
}

@@ -300,23 +300,128 @@
 api.
-project.Project
+application.ApplicationManager;%0Aimport com.intellij.openapi.project.Project;%0Aimport com.intellij.openapi.util.Computable
 ;%0Aim
@@ -577,16 +577,59 @@
 NotNull;
+%0Aimport org.jetbrains.annotations.Nullable;
 %0A%0A/**%0A *
@@ -927,16 +927,181 @@
 tClass =
+ ApplicationManager.getApplication().runReadAction(%0A        new Computable%3CPsiClass%3E() %7B%0A          @Nullable%0A          public PsiClass compute() %7B%0A            return
  psiMana
@@ -1135,16 +1135,45 @@
 ject%22);%0A
+          %7D%0A        %7D%0A    );%0A
     if (

read action added