<commit_before>package org.jetbrains.plugins.scala.codeInspection.declarationRedundancy.cheapRefSearch

import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.{PsiClass, PsiElement, SmartPsiElementPointer}
import org.jetbrains.plugins.scala.extensions.PsiElementExt
import org.jetbrains.plugins.scala.lang.psi.api.base.ScConstructorInvocation
import org.jetbrains.plugins.scala.lang.psi.api.expr.ScNewTemplateDefinition
import org.jetbrains.plugins.scala.lang.psi.api.statements.params.{ScParameterType, ScTypeParam}
import org.jetbrains.plugins.scala.lang.psi.api.statements.{ScFunction, ScValueOrVariable}
import org.jetbrains.plugins.scala.lang.psi.api.toplevel.{ScModifierListOwner, ScNamedElement}
import org.jetbrains.plugins.scala.lang.psi.api.toplevel.templates.ScExtendsBlock

import scala.ref.WeakReference

trait ElementUsage {
  def targetCanBePrivate: Boolean
}

private object ElementUsageWithoutReference extends ElementUsage {
  override val targetCanBePrivate: Boolean = false
}

private final class ElementUsageWithReference private(
  reference: SmartPsiElementPointer[PsiElement],
  target: WeakReference[ScNamedElement]
) extends ElementUsage {

  private def referenceLeaksTargetType: Boolean = {

    val directParent = reference.getElement.getParent

    def isPrivate(modifierListOwner: ScModifierListOwner): Boolean =
      modifierListOwner.getModifierList.accessModifier.exists(_.isPrivate)

    def getGrandParent(e: PsiElement): Option[PsiElement] =
      e.parent.flatMap(_.parent)

    getGrandParent(reference.getElement) match {

      case Some(f: ScFunction) if f.returnTypeElement.contains(directParent) =>
        !isPrivate(f)

      case Some(p: ScValueOrVariable) if p.typeElement.contains(directParent) =>
        !isPrivate(p)

      case Some(c: ScConstructorInvocation) if c.typeElement == directParent =>

        val extendsBlock = getGrandParent(c).collect { case e: ScExtendsBlock => e }

        val modifierListOwner = extendsBlock.flatMap(_.parent)
          .collect { case m: ScModifierListOwner => m }

        val newTemplateDefinition = extendsBlock.flatMap(_.parent)
          .collect { case n: ScNewTemplateDefinition => n }

        newTemplateDefinition.isEmpty && !modifierListOwner.exists(isPrivate)

      case Some(t: ScParameterType) => getGrandParent(t).flatMap(getGrandParent) match {
        case Some(f: ScFunction) => !isPrivate(f)
        case _ => false
      }

      case Some(t: ScTypeParam) => getGrandParent(t) match {
        case Some(f: ScFunction) => !isPrivate(f)<commit_msg>Factor our Some #SCL-20656<commit_after>package org.jetbrains.plugins.scala.codeInspection.declarationRedundancy.cheapRefSearch
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.{PsiClass, PsiElement, SmartPsiElementPointer}
import org.jetbrains.plugins.scala.extensions.PsiElementExt
import org.jetbrains.plugins.scala.lang.psi.api.base.ScConstructorInvocation
import org.jetbrains.plugins.scala.lang.psi.api.expr.ScNewTemplateDefinition
import org.jetbrains.plugins.scala.lang.psi.api.statements.params.{ScParameterType, ScTypeParam}
import org.jetbrains.plugins.scala.lang.psi.api.statements.{ScFunction, ScValueOrVariable}
import org.jetbrains.plugins.scala.lang.psi.api.toplevel.{ScModifierListOwner, ScNamedElement}
import org.jetbrains.plugins.scala.lang.psi.api.toplevel.templates.ScExtendsBlock

import scala.ref.WeakReference

trait ElementUsage {
  def targetCanBePrivate: Boolean
}

private object ElementUsageWithoutReference extends ElementUsage {
  override val targetCanBePrivate: Boolean = false
}

private final class ElementUsageWithReference private(
  reference: SmartPsiElementPointer[PsiElement],
  target: WeakReference[ScNamedElement]
) extends ElementUsage {

  private def referenceLeaksTargetType: Boolean = {

    val directParent = reference.getElement.getParent

    def isPrivate(modifierListOwner: ScModifierListOwner): Boolean =
      modifierListOwner.getModifierList.accessModifier.exists(_.isPrivate)

    def getGrandParent(e: PsiElement): Option[PsiElement] =
      e.parent.flatMap(_.parent)

    getGrandParent(reference.getElement).exists {

      case f: ScFunction if f.returnTypeElement.contains(directParent) =>
        !isPrivate(f)

      case p: ScValueOrVariable if p.typeElement.contains(directParent) =>
        !isPrivate(p)

      case c: ScConstructorInvocation if c.typeElement == directParent =>

        val extendsBlock = getGrandParent(c).collect { case e: ScExtendsBlock => e }

        val modifierListOwner = extendsBlock.flatMap(_.parent)
          .collect { case m: ScModifierListOwner => m }

        val newTemplateDefinition = extendsBlock.flatMap(_.parent)
          .collect { case n: ScNewTemplateDefinition => n }

        newTemplateDefinition.isEmpty && !modifierListOwner.exists(isPrivate)

      case t: ScParameterType => getGrandParent(t).flatMap(getGrandParent).exists {
        case f: ScFunction => !isPrivate(f)
        case _ => false
      }

      case t: ScTypeParam => getGrandParent(t).exists {
        case f: ScFunction => !isPrivate(f)
{'fraction_non_alphanumeric': 0.09371942868323224, 'fraction_numerical': 0.0009782821365681863, 'mean_word_length': 4.617582417582417, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, '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': '1925367', 'n_tokens_mistral': 1528, 'n_tokens_neox': 1453, 'n_words': 269}