<commit_before>package com.intellij.codeInsight.generation;

import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;

/**
 * @author dsl
 */
public class GenerateEqualsHelper implements Runnable {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.generation.GenerateEqualsHelper");
  private PsiClass myClass;
  private PsiField[] myEqualsFields;
  private PsiField[] myHashCodeFields;
  private HashSet<PsiField> myNonNullSet;
  private final PsiElementFactory myFactory;
  private String myParameterName;

  private static @NonNls final String BASE_OBJECT_PARAMETER_NAME = "object";
  private static @NonNls final String BASE_OBJECT_LOCAL_NAME = "that";
  private static @NonNls final String RESULT_VARIABLE = "result";
  private static @NonNls final String TEMP_VARIABLE = "temp";

  private final PsiClass myJavaLangObject;
  private String myClassInstanceName;

  @NonNls private static final HashMap<String, MessageFormat> PRIMITIVE_HASHCODE_FORMAT = new HashMap<String, MessageFormat>();
  private final boolean mySuperHasHashCode;
  private CodeStyleManager myCodeStyleManager;
  private final Project myProject;

  public static class NoObjectClassException extends Exception {
  }

  public GenerateEqualsHelper(Project project,
                              PsiClass aClass,
                              PsiField[] equalsFields,
                              PsiField[] hashCodeFields,
                              PsiField[] nonNullFields) throws NoObjectClassException {
    myClass = aClass;
    myEqualsFields = equalsFields;
    myHashCodeFields = hashCodeFields;
    myProject = project;

    myNonNullSet = new HashSet<PsiField>();
    for (PsiField field : nonNullFields) {
      myNonNullSet.add(field);
    }
    final PsiManager manager = PsiManager.getInstance(project);

    myFactory = manager.getElementFactory();
    myJavaLangObject = manager.findClass(CommonClassNames.JAVA_LANG_OBJECT, aClass.getResolveScope());
    if (myJavaLangObject == null) {
      throw new NoObjectClassException();
    }

    mySuperHasHashCode = superMethodExists(getHashCodeSignature());
    myCodeStyleManager = CodeStyleManager.getInstance(manager.getProject());
  }

  private static String getUniqueLocalVarName(String base, PsiField[] fields) {
    String id = base;
    int index = 0;
    while (true) {
      if (index > 0) {
        id = base + index;
      }
      index++;
      boolean anyEqual = false;
      for (PsiField equalsField : fields) {
        if (id.equals(equalsField.getName())) {
          anyEqual = true;
          break;
        }
      }
      if (!anyEqual) break;
    }


    return id;
  }

  public void run() {
    try {
      final PsiElement[] members = generateMembers();
      for (PsiElement member : members) {
        myClass.add(member);
      }
    }
    catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }

  public PsiElement[] generateMembers() throws IncorrectOperationException {
    PsiMethod equals = null;
    if (myEqualsFields != null && findMethod(myClass, getEqualsSignature(myProject, myClass.getResolveScope())) == null) {
      equals = createEquals();
    }

    PsiMethod hashCode = null;
    if (myHashCodeFields != null && findMethod(myClass, getHashCodeSignature()) == null) {
      if (myHashCodeFields.length > 0) {
        hashCode = createHashCode();
      }
      else {
        if (!mySuperHasHashCode) {
          final PsiMethod trivialHashCode = myFactory.createMethodFromText("public int hashCode() {\nreturn 0;\n}", null);
          hashCode = (PsiMethod)myCodeStyleManager.reformat(trivialHashCode);
        }
      }
    }
    if (hashCode != null && equals != null) {
      return new PsiMethod[]{equals, hashCode};
    }
    else if (equals != null) {
      return new PsiMethod[]{equals};
    }
    else if (hashCode != null) {
      return new PsiMethod[]{hashCode};
    }
    else {
      return null;
    }
  }


  private PsiMethod createEquals() throws IncorrectOperationException {
    CodeStyleManager codeStyleManager = myCodeStyleManager;
    final PsiType objectType = myFactory.createType(myJavaLangObject);
    String[] nameSuggestions = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, objectType).names;
    final String objectBaseName = nameSuggestions.length > 0 ? nameSuggestions[0] : BASE_OBJECT_PARAMETER_NAME;
    myParameterName = getUniqueLocalVarName(objectBaseName, myEqualsFields);
    final PsiType classType = myFactory.createType(myClass);
    nameSuggestions = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, classType).names;
    String instanceBaseName = nameSuggestions.length > 0 && nameSuggestions[0].length() < 10 ? nameSuggestions[0] : BASE_OBJECT_LOCAL_NAME;
    myClassInstanceName = getUniqueLocalVarName(instanceBaseName, myEqualsFields);

    @NonNls StringBuffer buffer = new StringBuffer();
    buffer.append("public boolean equals(Object ").append(myParameterName).append(") {\n");
    addEqualsPrologue(buffer);
    if (myEqualsFields.length > 0) {
      addClassInstance(buffer);<commit_msg>id-based equals & hashCode generation<commit_after>package com.intellij.codeInsight.generation;

import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;

/**
 * @author dsl
 */
public class GenerateEqualsHelper implements Runnable {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.generation.GenerateEqualsHelper");
  private PsiClass myClass;
  private PsiField[] myEqualsFields;
  private PsiField[] myHashCodeFields;
  private HashSet<PsiField> myNonNullSet;
  private final PsiElementFactory myFactory;
  private String myParameterName;

  private static @NonNls final String BASE_OBJECT_PARAMETER_NAME = "object";
  private static @NonNls final String BASE_OBJECT_LOCAL_NAME = "that";
  private static @NonNls final String RESULT_VARIABLE = "result";
  private static @NonNls final String TEMP_VARIABLE = "temp";

  private final PsiClass myJavaLangObject;
  private String myClassInstanceName;

  @NonNls private static final HashMap<String, MessageFormat> PRIMITIVE_HASHCODE_FORMAT = new HashMap<String, MessageFormat>();
  private final boolean mySuperHasHashCode;
  private CodeStyleManager myCodeStyleManager;
  private final Project myProject;

  public static class NoObjectClassException extends Exception {
  }

  public GenerateEqualsHelper(Project project,
                              PsiClass aClass,
                              PsiField[] equalsFields,
                              PsiField[] hashCodeFields,
                              PsiField[] nonNullFields) throws NoObjectClassException {
    myClass = aClass;
    myEqualsFields = equalsFields;
    myHashCodeFields = hashCodeFields;
    myProject = project;

    myNonNullSet = new HashSet<PsiField>();
    for (PsiField field : nonNullFields) {
      myNonNullSet.add(field);
    }
    final PsiManager manager = PsiManager.getInstance(project);

    myFactory = manager.getElementFactory();
    myJavaLangObject = manager.findClass(CommonClassNames.JAVA_LANG_OBJECT, aClass.getResolveScope());
    if (myJavaLangObject == null) {
      throw new NoObjectClassException();
    }

    mySuperHasHashCode = superMethodExists(getHashCodeSignature());
    myCodeStyleManager = CodeStyleManager.getInstance(manager.getProject());
  }

  private static String getUniqueLocalVarName(String base, PsiField[] fields) {
    String id = base;
    int index = 0;
    while (true) {
      if (index > 0) {
        id = base + index;
      }
      index++;
      boolean anyEqual = false;
      for (PsiField equalsField : fields) {
        if (id.equals(equalsField.getName())) {
          anyEqual = true;
          break;
        }
      }
      if (!anyEqual) break;
    }


    return id;
  }

  public void run() {
    try {
      final PsiElement[] members = generateMembers();
      for (PsiElement member : members) {
        myClass.add(member);
      }
    }
    catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }

  public PsiElement[] generateMembers() throws IncorrectOperationException {
    PsiMethod equals = null;
    if (myEqualsFields != null && findMethod(myClass, getEqualsSignature(myProject, myClass.getResolveScope())) == null) {
      equals = createEquals();
    }

    PsiMethod hashCode = null;
    if (myHashCodeFields != null && findMethod(myClass, getHashCodeSignature()) == null) {
      if (myHashCodeFields.length > 0) {
        hashCode = createHashCode();
      }
      else {
        if (!mySuperHasHashCode) {
          final PsiMethod trivialHashCode = myFactory.createMethodFromText("public int hashCode() {\nreturn 0;\n}", null);
          hashCode = (PsiMethod)myCodeStyleManager.reformat(trivialHashCode);
        }
      }
    }
    if (hashCode != null && equals != null) {
      return new PsiMethod[]{equals, hashCode};
    }
    else if (equals != null) {
      return new PsiMethod[]{equals};
    }
    else if (hashCode != null) {
      return new PsiMethod[]{hashCode};
    }
    else {
      return PsiElement.EMPTY_ARRAY;
    }
  }


  private PsiMethod createEquals() throws IncorrectOperationException {
    CodeStyleManager codeStyleManager = myCodeStyleManager;
    final PsiType objectType = myFactory.createType(myJavaLangObject);
    String[] nameSuggestions = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, objectType).names;
    final String objectBaseName = nameSuggestions.length > 0 ? nameSuggestions[0] : BASE_OBJECT_PARAMETER_NAME;
    myParameterName = getUniqueLocalVarName(objectBaseName, myEqualsFields);
    final PsiType classType = myFactory.createType(myClass);
    nameSuggestions = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, classType).names;
    String instanceBaseName = nameSuggestions.length > 0 && nameSuggestions[0].length() < 10 ? nameSuggestions[0] : BASE_OBJECT_LOCAL_NAME;
    myClassInstanceName = getUniqueLocalVarName(instanceBaseName, myEqualsFields);

    @NonNls StringBuffer buffer = new StringBuffer();
    buffer.append("public boolean equals(Object ").append(myParameterName).append(") {\n");
    addEqualsPrologue(buffer);
    if (myEqualsFields.length > 0) {
      addClassInstance(buffer);
{'fraction_non_alphanumeric': 0.09374488292123792, 'fraction_numerical': 0.0019649582446373015, 'mean_word_length': 3.87624750499002, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3405867', 'n_tokens_mistral': 3530, 'n_tokens_neox': 3464, 'n_words': 762}