<commit_before>package com.intellij.psi.impl;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
 * @author ik, dsl
 */
public class PsiSubstitutorImpl implements PsiSubstitutorEx {
  private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiSubstitutorImpl");
  private final Map<PsiTypeParameter, PsiType> mySubstitutionMap;

  protected PsiSubstitutorImpl(Map<PsiTypeParameter, PsiType> map) {
    mySubstitutionMap = map;
  }

  public PsiSubstitutorImpl() {
    mySubstitutionMap = new HashMap<PsiTypeParameter, PsiType>();
  }

  public PsiType substitute(PsiTypeParameter typeParameter){
    if(!mySubstitutionMap.containsKey(typeParameter)){
      return typeParameter.getManager().getElementFactory().createType(typeParameter);
    }
    return mySubstitutionMap.get(typeParameter);
  }

  public PsiType substitute(PsiType type) {
    if (type == null) return null;
    PsiType substituted = type.accept(myInternalSubstitutionVisitor);
    return correctExternalSubstitution(substituted, type);
  }

  public PsiType substituteAndCapture(PsiType type) {
    if (type == null) return null;
    PsiType substituted = type.accept(myInternalCapturingSubstitutionVisitor);
    return correctExternalSubstitution(substituted, type);
  }

  public PsiType substituteAndFullCapture(PsiType type) {
    if (type == null) return null;
    PsiType substituted = type.accept(myInternalFullCapturingSubstitutionVisitor);
    return correctExternalSubstitution(substituted, type);
  }

  private PsiType rawTypeForTypeParameter(final PsiTypeParameter typeParameter) {
    final PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
    if (extendsTypes.length > 0) {
      // First bound
      return substitute(extendsTypes[0]);
    }
    else {
      // Object
      return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
    }
  }

  private abstract static class SubstitutionVisitor extends PsiTypeVisitorEx<PsiType> {
    public PsiType visitType(PsiType type) {
      LOG.assertTrue(false);
      return null;
    }

    public PsiType visitWildcardType(PsiWildcardType wildcardType) {
      final PsiType bound = wildcardType.getBound();
      if (bound == null) {
        return wildcardType;
      }
      else {
        final PsiType newBound = bound.accept(this);
        if (newBound == null) {
          return null;
        }
        else if (newBound instanceof PsiWildcardType) {
          final PsiType newBoundBound = ((PsiWildcardType)newBound).getBound();
          if (newBoundBound != null) {
            return PsiWildcardType.changeBound(wildcardType, newBoundBound);
          }
          else {
            return PsiWildcardType.createUnbounded(wildcardType.getManager());
          }
        }
        else {
          return PsiWildcardType.changeBound(wildcardType, newBound);
        }
      }
    }

    public PsiType visitPrimitiveType(PsiPrimitiveType primitiveType) {
      return primitiveType;
    }

    public PsiType visitArrayType(PsiArrayType arrayType) {
      final PsiType componentType = arrayType.getComponentType();
      final PsiType substitutedComponentType = componentType.accept(this);
      if (substitutedComponentType == null) return null;
      if (substitutedComponentType == componentType) return arrayType; // optimization
      return new PsiArrayType(substitutedComponentType);
    }

    public PsiType visitEllipsisType(PsiEllipsisType ellipsisType) {
      final PsiType componentType = ellipsisType.getComponentType();
      final PsiType substitutedComponentType = componentType.accept(this);
      if (substitutedComponentType == null) return null;
      if (substitutedComponentType == componentType) return ellipsisType; // optimization
      return new PsiEllipsisType(substitutedComponentType);
    }

    public PsiType visitTypeVariable(final PsiTypeVariable var) {
      return var;
    }

    public PsiType visitBottom(final Bottom bottom) {
      return bottom;
    }

    public abstract PsiType visitClassType(PsiClassType classType);
  }

  private final InternalSubstitutionVisitor myInternalSubstitutionVisitor = new InternalSubstitutionVisitor();
  private final InternalCapturingSubstitutionVisitor myInternalCapturingSubstitutionVisitor = new InternalCapturingSubstitutionVisitor();
  private final InternalFullCapturingSubstitutionVisitor myInternalFullCapturingSubstitutionVisitor =
    new InternalFullCapturingSubstitutionVisitor();

  private static final Key<Boolean> PREVENT_RECURSION_KEY = Key.create("PREVENT_RECURSION_KEY");

  private class InternalSubstitutionVisitor extends SubstitutionVisitor {
    public PsiType visitClassType(PsiClassType classType) {
      final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
      final PsiClass aClass = resolveResult.getElement();
      if (aClass == null) return classType;
      if (aClass instanceof PsiTypeParameter) {
        final PsiTypeParameter typeParameter = ((PsiTypeParameter)aClass);
        if (!mySubstitutionMap.containsKey(typeParameter)) {
          return classType;
        }
        else {
          return substituteTypeParameter(typeParameter);
        }
      }
      final Map<PsiTypeParameter, PsiType> hashMap = new HashMap<PsiTypeParameter, PsiType>();
      if (!processClass(aClass, resolveResult.getSubstitutor(), hashMap)) {
        return null;
      }
      return aClass.getManager().getElementFactory().createType(aClass, createSubstitutor(hashMap), classType.getLanguageLevel());
    }

    protected PsiType substituteTypeParameter(final PsiTypeParameter typeParameter) {
      PsiType substituted = mySubstitutionMap.get(typeParameter);
      if (typeParameter.getUserData(PREVENT_RECURSION_KEY) != null) return PsiWildcardType.createUnbounded(typeParameter.getManager());
      if (substituted instanceof PsiWildcardType && !((PsiWildcardType)substituted).isSuper()) {
        PsiType originalBound = ((PsiWildcardType)substituted).getBound();
        PsiManager manager = typeParameter.getManager();
        final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
        for (PsiType boundType : boundTypes) {
          PsiType substitutedBoundType;
          synchronized (PsiLock.LOCK) {
            //prevent infinite recursion
            try {
              typeParameter.putUserData(PREVENT_RECURSION_KEY, Boolean.TRUE);
              substitutedBoundType = boundType.accept(this);
            }
            finally {
              typeParameter.putUserData(PREVENT_RECURSION_KEY, null);
            }
          }
          PsiWildcardType wildcardType = (PsiWildcardType)substituted;
          if (substitutedBoundType != null && !substitutedBoundType.equalsToText("java.lang.Object")) {<commit_msg>cleanup<commit_after>package com.intellij.psi.impl;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
 * @author ik, dsl
 */
public class PsiSubstitutorImpl implements PsiSubstitutorEx {
  private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiSubstitutorImpl");
  private final Map<PsiTypeParameter, PsiType> mySubstitutionMap;

  protected PsiSubstitutorImpl(Map<PsiTypeParameter, PsiType> map) {
    mySubstitutionMap = map;
  }

  public PsiSubstitutorImpl() {
    mySubstitutionMap = new HashMap<PsiTypeParameter, PsiType>();
  }

  public PsiType substitute(PsiTypeParameter typeParameter){
    if(!mySubstitutionMap.containsKey(typeParameter)){
      return typeParameter.getManager().getElementFactory().createType(typeParameter);
    }
    return mySubstitutionMap.get(typeParameter);
  }

  public PsiType substitute(PsiType type) {
    if (type == null) return null;
    PsiType substituted = type.accept(myInternalSubstitutionVisitor);
    return correctExternalSubstitution(substituted, type);
  }

  public PsiType substituteAndCapture(PsiType type) {
    if (type == null) return null;
    PsiType substituted = type.accept(myInternalCapturingSubstitutionVisitor);
    return correctExternalSubstitution(substituted, type);
  }

  public PsiType substituteAndFullCapture(PsiType type) {
    if (type == null) return null;
    PsiType substituted = type.accept(myInternalFullCapturingSubstitutionVisitor);
    return correctExternalSubstitution(substituted, type);
  }

  private PsiType rawTypeForTypeParameter(final PsiTypeParameter typeParameter) {
    final PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
    if (extendsTypes.length > 0) {
      // First bound
      return substitute(extendsTypes[0]);
    }
    else {
      // Object
      return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
    }
  }

  private abstract static class SubstitutionVisitor extends PsiTypeVisitorEx<PsiType> {
    public PsiType visitType(PsiType type) {
      LOG.assertTrue(false);
      return null;
    }

    public PsiType visitWildcardType(PsiWildcardType wildcardType) {
      final PsiType bound = wildcardType.getBound();
      if (bound == null) {
        return wildcardType;
      }
      else {
        final PsiType newBound = bound.accept(this);
        if (newBound == null) {
          return null;
        }
        else if (newBound instanceof PsiWildcardType) {
          final PsiType newBoundBound = ((PsiWildcardType)newBound).getBound();
          if (newBoundBound != null) {
            return PsiWildcardType.changeBound(wildcardType, newBoundBound);
          }
          else {
            return PsiWildcardType.createUnbounded(wildcardType.getManager());
          }
        }
        else {
          return PsiWildcardType.changeBound(wildcardType, newBound);
        }
      }
    }

    public PsiType visitPrimitiveType(PsiPrimitiveType primitiveType) {
      return primitiveType;
    }

    public PsiType visitArrayType(PsiArrayType arrayType) {
      final PsiType componentType = arrayType.getComponentType();
      final PsiType substitutedComponentType = componentType.accept(this);
      if (substitutedComponentType == null) return null;
      if (substitutedComponentType == componentType) return arrayType; // optimization
      return new PsiArrayType(substitutedComponentType);
    }

    public PsiType visitEllipsisType(PsiEllipsisType ellipsisType) {
      final PsiType componentType = ellipsisType.getComponentType();
      final PsiType substitutedComponentType = componentType.accept(this);
      if (substitutedComponentType == null) return null;
      if (substitutedComponentType == componentType) return ellipsisType; // optimization
      return new PsiEllipsisType(substitutedComponentType);
    }

    public PsiType visitTypeVariable(final PsiTypeVariable var) {
      return var;
    }

    public PsiType visitBottom(final Bottom bottom) {
      return bottom;
    }

    public abstract PsiType visitClassType(PsiClassType classType);
  }

  private final InternalSubstitutionVisitor myInternalSubstitutionVisitor = new InternalSubstitutionVisitor();
  private final InternalCapturingSubstitutionVisitor myInternalCapturingSubstitutionVisitor = new InternalCapturingSubstitutionVisitor();
  private final InternalFullCapturingSubstitutionVisitor myInternalFullCapturingSubstitutionVisitor =
    new InternalFullCapturingSubstitutionVisitor();

  private static final Key<Boolean> PREVENT_RECURSION_KEY = Key.create("PREVENT_RECURSION_KEY");

  private class InternalSubstitutionVisitor extends SubstitutionVisitor {
    public PsiType visitClassType(PsiClassType classType) {
      final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
      final PsiClass aClass = resolveResult.getElement();
      if (aClass == null) return classType;
      if (aClass instanceof PsiTypeParameter) {
        final PsiTypeParameter typeParameter = ((PsiTypeParameter)aClass);
        if (!mySubstitutionMap.containsKey(typeParameter)) {
          return classType;
        }
        else {
          return substituteTypeParameter(typeParameter);
        }
      }
      final Map<PsiTypeParameter, PsiType> hashMap = new HashMap<PsiTypeParameter, PsiType>();
      if (!processClass(aClass, resolveResult.getSubstitutor(), hashMap)) {
        return null;
      }
      return aClass.getManager().getElementFactory().createType(aClass, createSubstitutor(hashMap), classType.getLanguageLevel());
    }

    protected PsiType substituteTypeParameter(final PsiTypeParameter typeParameter) {
      PsiType substituted = mySubstitutionMap.get(typeParameter);
      if (typeParameter.getUserData(PREVENT_RECURSION_KEY) != null) return PsiWildcardType.createUnbounded(typeParameter.getManager());
      if (substituted instanceof PsiWildcardType && !((PsiWildcardType)substituted).isSuper()) {
        PsiType originalBound = ((PsiWildcardType)substituted).getBound();
        PsiManager manager = typeParameter.getManager();
        final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
        for (PsiType boundType : boundTypes) {
          PsiType substitutedBoundType;
          synchronized (PsiLock.LOCK) {
            //prevent infinite recursion
            try {
              typeParameter.putUserData(PREVENT_RECURSION_KEY, Boolean.TRUE);
              substitutedBoundType = boundType.accept(this);
            }
            finally {
              typeParameter.putUserData(PREVENT_RECURSION_KEY, null);
            }
          }
          PsiWildcardType wildcardType = (PsiWildcardType)substituted;
          if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) && !substitutedBoundType.equalsToText("java.lang.Object")) {
{'fraction_non_alphanumeric': 0.08216390682009543, 'fraction_numerical': 0.000280662363177098, 'mean_word_length': 3.836443841194435, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 19, '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': '5931271', 'n_tokens_mistral': 3992, 'n_tokens_neox': 3759, 'n_words': 795}