<commit_before>package com.intellij.codeInspection.miscGenerics;

import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.util.IncorrectOperationException;

import java.util.*;
import java.text.MessageFormat;

/**
 * @author ven
 */
public class SuspiciousCollectionsMethodCallsInspection extends GenericsInspectionToolBase {
  private static final Logger LOG =
    Logger.getInstance("#com.intellij.codeInspection.miscGenerics.SuspiciousCollectionsMethodCallsInspection");

  private void setupPatternMethods(PsiManager manager,
                                   GlobalSearchScope searchScope,
                                   List<PsiMethod> patternMethods,
                                   List<Integer> indices) throws IncorrectOperationException {
    final PsiElementFactory elementFactory = manager.getElementFactory();
    final PsiClass collectionClass = manager.findClass("java.util.Collection", searchScope);
    if (collectionClass != null) {
      addMethod(collectionClass.findMethodBySignature(elementFactory.createMethodFromText("boolean remove(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(collectionClass.findMethodBySignature(elementFactory.createMethodFromText("boolean contains(Object o);", null), false), 0,
                patternMethods, indices);
    }

    final PsiClass listClass = manager.findClass("java.util.List", searchScope);
    if (listClass != null) {
      addMethod(listClass.findMethodBySignature(elementFactory.createMethodFromText("boolean indexOf(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(listClass.findMethodBySignature(elementFactory.createMethodFromText("boolean lastIndexOf(Object o);", null), false), 0,
                patternMethods, indices);
    }

    final PsiClass mapClass = manager.findClass("java.util.Map", searchScope);
    if (mapClass != null) {
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean remove(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean get(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean containsKey(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean containsValue(Object o);", null), false), 1,
                patternMethods, indices);
    }

    patternMethods.remove(null);
  }

  private void addMethod(final PsiMethod patternMethod, int typeParamIndex, List<PsiMethod> patternMethods, List<Integer> indices) {
    if (patternMethod != null) {
      patternMethods.add(patternMethod);
      indices.add(new Integer(typeParamIndex));
    }
  }

  public ProblemDescriptor[] getDescriptions(PsiElement place, final InspectionManager manager) {
    final List<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
    final List<PsiMethod> patternMethods = new ArrayList<PsiMethod>();
    final List<Integer> indices = new ArrayList<Integer>();
    try {
      setupPatternMethods(place.getManager(), place.getResolveScope(), patternMethods, indices);
    }
    catch (IncorrectOperationException e) {
      LOG.error(e);
      return null;
    }

    place.accept(new PsiRecursiveElementVisitor() {
      public void visitMethodCallExpression(PsiMethodCallExpression methodCall) {
        final PsiExpression[] args = methodCall.getArgumentList().getExpressions();
        if (args.length != 1) return;
        PsiType argType = args[0].getType();
        if (argType instanceof PsiPrimitiveType) {
          argType = ((PsiPrimitiveType)argType).getBoxedType(methodCall.getManager(), methodCall.getResolveScope());
        }

        if (!(argType instanceof PsiClassType)) return;

        final PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
        final ResolveResult resolveResult = methodExpression.advancedResolve(false);
        final PsiMethod psiMethod = (PsiMethod)resolveResult.getElement();
        if (psiMethod == null) return;

        Iterator<Integer> indicesIterator = indices.iterator();
        for (Iterator<PsiMethod> methodsIterator = patternMethods.iterator(); methodsIterator.hasNext();) {
          PsiMethod patternMethod = methodsIterator.next();
          Integer index = indicesIterator.next();
          if (!patternMethod.getName().equals(methodExpression.getReferenceName())) continue;
          if (isInheritorOrSelf(psiMethod, patternMethod)) {
            PsiTypeParameter[] typeParameters = psiMethod.getContainingClass().getTypeParameters();
            int i = index.intValue();
            if (typeParameters.length <= i) return;
            final PsiTypeParameter typeParameter = typeParameters[i];
            PsiType typeParamMapping = resolveResult.getSubstitutor().substitute(typeParameter);
            if (typeParamMapping != null) {
              String message = null;
              if (!typeParamMapping.isAssignableFrom(argType)) {
                if (!typeParamMapping.isConvertibleFrom(argType)) {
                  String existsElementString = getExistsElementString (patternMethod);
                  message = MessageFormat.format("For no non-null object of type ''{0}'' can ''{1}'' return {2}", new Object[]{
                                                     PsiFormatUtil.formatType(argType, 0, PsiSubstitutor.EMPTY),
                                                     PsiFormatUtil.formatMethod(psiMethod, resolveResult.getSubstitutor(),
                                                                                PsiFormatUtil.SHOW_NAME |
                                                                                PsiFormatUtil.SHOW_CONTAINING_CLASS,
                                                                                PsiFormatUtil.SHOW_TYPE),
                                                     existsElementString});
                }
                else {
                  message = MessageFormat.format("Suspicious call to ''{0}''", new Object[]{
                                                     PsiFormatUtil.formatMethod(psiMethod, resolveResult.getSubstitutor(),
                                                                                PsiFormatUtil.SHOW_NAME |
                                                                                PsiFormatUtil.SHOW_CONTAINING_CLASS,
                                                                                PsiFormatUtil.SHOW_TYPE)});
                }
              }
              if (message != null) {
                problems.add(manager.createProblemDescriptor(args[0], message,
                                                             null,
                                                             ProblemHighlightType.GENERIC_ERROR_OR_WARNING));
              }
            }
            return;
          }
        }
      }

      private String getExistsElementString(final PsiMethod method) {
        if (PsiType.BOOLEAN.equals(method.getReturnType())) return "'true'";
        if (PsiType.INT.equals(method.getReturnType())) return "non-negative value";
        return "non-null value";
      }

      private boolean isInheritorOrSelf(PsiMethod inheritorCandidate, PsiMethod base) {
        PsiClass aClass = inheritorCandidate.getContainingClass();
        PsiClass bClass = base.getContainingClass();
        if (aClass == null || bClass == null) return false;
        PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(bClass, aClass, PsiSubstitutor.EMPTY);
        if (substitutor == null) return false;
        return MethodSignatureUtil.findMethodBySignature(bClass, inheritorCandidate.getSignature(substitutor), false) == base;<commit_msg>tests<commit_after>package com.intellij.codeInspection.miscGenerics;

import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.util.IncorrectOperationException;

import java.util.*;
import java.text.MessageFormat;

/**
 * @author ven
 */
public class SuspiciousCollectionsMethodCallsInspection extends GenericsInspectionToolBase {
  private static final Logger LOG =
    Logger.getInstance("#com.intellij.codeInspection.miscGenerics.SuspiciousCollectionsMethodCallsInspection");

  private void setupPatternMethods(PsiManager manager,
                                   GlobalSearchScope searchScope,
                                   List<PsiMethod> patternMethods,
                                   List<Integer> indices) throws IncorrectOperationException {
    final PsiElementFactory elementFactory = manager.getElementFactory();
    final PsiClass collectionClass = manager.findClass("java.util.Collection", searchScope);
    if (collectionClass != null) {
      addMethod(collectionClass.findMethodBySignature(elementFactory.createMethodFromText("boolean remove(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(collectionClass.findMethodBySignature(elementFactory.createMethodFromText("boolean contains(Object o);", null), false), 0,
                patternMethods, indices);
    }

    final PsiClass listClass = manager.findClass("java.util.List", searchScope);
    if (listClass != null) {
      addMethod(listClass.findMethodBySignature(elementFactory.createMethodFromText("boolean indexOf(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(listClass.findMethodBySignature(elementFactory.createMethodFromText("boolean lastIndexOf(Object o);", null), false), 0,
                patternMethods, indices);
    }

    final PsiClass mapClass = manager.findClass("java.util.Map", searchScope);
    if (mapClass != null) {
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean remove(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean get(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean containsKey(Object o);", null), false), 0,
                patternMethods, indices);
      addMethod(mapClass.findMethodBySignature(elementFactory.createMethodFromText("boolean containsValue(Object o);", null), false), 1,
                patternMethods, indices);
    }

    patternMethods.remove(null);
  }

  private void addMethod(final PsiMethod patternMethod, int typeParamIndex, List<PsiMethod> patternMethods, List<Integer> indices) {
    if (patternMethod != null) {
      patternMethods.add(patternMethod);
      indices.add(new Integer(typeParamIndex));
    }
  }

  public ProblemDescriptor[] getDescriptions(PsiElement place, final InspectionManager manager) {
    final List<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
    final List<PsiMethod> patternMethods = new ArrayList<PsiMethod>();
    final List<Integer> indices = new ArrayList<Integer>();
    try {
      setupPatternMethods(place.getManager(), place.getResolveScope(), patternMethods, indices);
    }
    catch (IncorrectOperationException e) {
      LOG.error(e);
      return null;
    }

    place.accept(new PsiRecursiveElementVisitor() {
      public void visitMethodCallExpression(PsiMethodCallExpression methodCall) {
        final PsiExpression[] args = methodCall.getArgumentList().getExpressions();
        if (args.length != 1) return;
        PsiType argType = args[0].getType();
        if (argType instanceof PsiPrimitiveType) {
          argType = ((PsiPrimitiveType)argType).getBoxedType(methodCall.getManager(), methodCall.getResolveScope());
        }

        if (!(argType instanceof PsiClassType)) return;

        final PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
        final ResolveResult resolveResult = methodExpression.advancedResolve(false);
        final PsiMethod psiMethod = (PsiMethod)resolveResult.getElement();
        if (psiMethod == null) return;

        Iterator<Integer> indicesIterator = indices.iterator();
        for (Iterator<PsiMethod> methodsIterator = patternMethods.iterator(); methodsIterator.hasNext();) {
          PsiMethod patternMethod = methodsIterator.next();
          Integer index = indicesIterator.next();
          if (!patternMethod.getName().equals(methodExpression.getReferenceName())) continue;
          if (isInheritorOrSelf(psiMethod, patternMethod)) {
            PsiTypeParameter[] typeParameters = psiMethod.getContainingClass().getTypeParameters();
            int i = index.intValue();
            if (typeParameters.length <= i) return;
            final PsiTypeParameter typeParameter = typeParameters[i];
            PsiType typeParamMapping = resolveResult.getSubstitutor().substitute(typeParameter);
            if (typeParamMapping != null) {
              String message = null;
              if (!typeParamMapping.isAssignableFrom(argType)) {
                if (!typeParamMapping.isConvertibleFrom(argType)) {
                  message = MessageFormat.format("Calling ''{1}'' may not succeed for non-null objects of type ''{0}''",
                                                 PsiFormatUtil.formatType(argType, 0, PsiSubstitutor.EMPTY),
                                                 PsiFormatUtil.formatMethod(psiMethod, resolveResult.getSubstitutor(),
                                                                            PsiFormatUtil.SHOW_NAME |
                                                                            PsiFormatUtil.SHOW_CONTAINING_CLASS,
                                                                            PsiFormatUtil.SHOW_TYPE));
                }
                else {
                  message = MessageFormat.format("Suspicious call to ''{0}''",
                                                 PsiFormatUtil.formatMethod(psiMethod, resolveResult.getSubstitutor(),
                                                                            PsiFormatUtil.SHOW_NAME |
                                                                            PsiFormatUtil.SHOW_CONTAINING_CLASS,
                                                                            PsiFormatUtil.SHOW_TYPE));
                }
              }
              if (message != null) {
                problems.add(manager.createProblemDescriptor(args[0], message,
                                                             null,
                                                             ProblemHighlightType.GENERIC_ERROR_OR_WARNING));
              }
            }
            return;
          }
        }
      }

      private boolean isInheritorOrSelf(PsiMethod inheritorCandidate, PsiMethod base) {
        PsiClass aClass = inheritorCandidate.getContainingClass();
        PsiClass bClass = base.getContainingClass();
        if (aClass == null || bClass == null) return false;
        PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(bClass, aClass, PsiSubstitutor.EMPTY);
        if (substitutor == null) return false;
        return MethodSignatureUtil.findMethodBySignature(bClass, inheritorCandidate.getSignature(substitutor), false) == base;
{'fraction_non_alphanumeric': 0.09026920227216596, 'fraction_numerical': 0.0019140528525561867, 'mean_word_length': 2.475751072961373, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 64, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5532802', 'n_tokens_mistral': 3910, 'n_tokens_neox': 3787, 'n_words': 743}