<commit_before>package dotty.tools.scaladoc.tasty

import collection.JavaConverters._
import dotty.tools.scaladoc._
import dotty.tools.scaladoc.{Signature => DSignature}
import dotty.tools.scaladoc.Inkuire

import scala.quoted._

import SymOps._
import NameNormalizer._
import SyntheticsSupport._

trait ClassLikeSupport:
  self: TastyParser =>
  import qctx.reflect._

  private given qctx.type = qctx

  private def bareClasslikeKind(using Quotes)(symbol: reflect.Symbol): Kind =
    import reflect._
    if symbol.flags.is(Flags.Module) then Kind.Object
    else if symbol.flags.is(Flags.Trait) then  Kind.Trait(Nil, Nil)
    else if symbol.flags.is(Flags.Enum) then Kind.Enum(Nil, Nil)
    else if symbol.flags.is(Flags.Enum) && symbol.flags.is(Flags.Case) then Kind.EnumCase(Kind.Object)
    else Kind.Class(Nil, Nil)

  private def kindForClasslike(classDef: ClassDef): Kind =
    def typeArgs = classDef.getTypeParams.map(mkTypeArgument(_))

    def parameterModifier(parameter: Symbol): String =
      val fieldSymbol = classDef.symbol.declaredField(parameter.normalizedName)
      def isVal = fieldSymbol.flags.is(Flags.ParamAccessor) &&
        !classDef.symbol.flags.is(Flags.Case) &&
        !fieldSymbol.flags.is(Flags.Private)

      if fieldSymbol.flags.is(Flags.Mutable) then "var "
      else if isVal then "val "
      else ""

    def args = if constructorWithoutParamLists(classDef) then Nil else
      val constr =
        Some(classDef.constructor.symbol)
          .filter(s => s.exists && !s.isHiddenByVisibility)
          .map( _.tree.asInstanceOf[DefDef])
      constr.fold(Nil)(
        _.termParamss.map(pList => ParametersList(pList.params.map(p => mkParameter(p, parameterModifier)), paramListModifier(pList.params)))
        )

    if classDef.symbol.flags.is(Flags.Module) then Kind.Object
    else if classDef.symbol.flags.is(Flags.Trait) then
      Kind.Trait(typeArgs, args)
    else if classDef.symbol.flags.is(Flags.Enum) && classDef.symbol.flags.is(Flags.Case) then Kind.EnumCase(Kind.Class(typeArgs, args))
    else if classDef.symbol.flags.is(Flags.Enum) then Kind.Enum(typeArgs, args)
    else Kind.Class(typeArgs, args)

  def mkClass(classDef: ClassDef)(
    dri: DRI = classDef.symbol.dri,
    name: String = classDef.symbol.normalizedName,
    signatureOnly: Boolean = false,
    modifiers: Seq[Modifier] = classDef.symbol.getExtraModifiers(),
  ): Member =
    def unpackTreeToClassDef(tree: Tree): ClassDef = tree match
      case tree: ClassDef => tree
      case TypeDef(_, tbt: TypeBoundsTree) => unpackTreeToClassDef(tbt.tpe.typeSymbol.tree)
      case TypeDef(_, tt: TypeTree) => unpackTreeToClassDef(tt.tpe.typeSymbol.tree)
      case c: Apply =>
        c.symbol.owner.tree.symbol.tree match
          case tree: ClassDef => tree
      case tt: TypeTree => unpackTreeToClassDef(tt.tpe.typeSymbol.tree)

    def getSupertypesGraph(classDef: Tree, link: LinkToType): Seq[(LinkToType, LinkToType)] =
      val smbl = classDef.symbol
      val parents = unpackTreeToClassDef(classDef).parents
      parents.flatMap { case tree =>
        val symbol = if tree.symbol.isClassConstructor then tree.symbol.owner else tree.symbol
        val superLink = LinkToType(tree.asSignature, symbol.dri, bareClasslikeKind(symbol))
        Seq(link -> superLink) ++ getSupertypesGraph(tree, superLink)
      }

    val supertypes = getSupertypes(using qctx)(classDef).map {
      case (symbol, tpe) =>
        LinkToType(tpe.asSignature, symbol.dri, bareClasslikeKind(symbol))
    }
    val selfSiangture: DSignature = typeForClass(classDef).asSignature

    val graph = HierarchyGraph.withEdges(
      getSupertypesGraph(classDef, LinkToType(selfSiangture, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)))
    )

    val baseMember = mkMember(classDef.symbol, kindForClasslike(classDef), selfSiangture)(
      modifiers = modifiers,
      graph = graph,
      deprecated = classDef.symbol.isDeprecated()
    )

    if summon[DocContext].args.generateInkuire then {

      val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type]

      def varName(t: Inkuire.TypeLike): Option[String] = t match {
        case tpe: Inkuire.Type      => Some(tpe.name.name)
        case tl: Inkuire.TypeLambda => varName(tl.result)
        case _                      => None
      }

      val variableNames: Set[String] = classType.params.map(_.typ)
        .flatMap(varName(_).toList).toSet

      val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type])

      val isModule = classDef.symbol.flags.is(Flags.Module)

      if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents)))

      classDef.symbol.declaredTypes.foreach {
        case typeSymbol: Symbol =>
          val typeDef = typeSymbol.tree.asInstanceOf[TypeDef]
          if typeDef.rhs.symbol.fullName.contains("java") then
            val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported
            val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames)
            t match
              case t: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported
              case _ =>
            tJava match
              case tJava: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty)))
              case _ =>
      }

      classDef.symbol.declaredMethods
        .filter { (s: Symbol) =>
          !s.flags.is(Flags.Private) &&<commit_msg>More sane Java classes hack<commit_after>package dotty.tools.scaladoc.tasty

import collection.JavaConverters._
import dotty.tools.scaladoc._
import dotty.tools.scaladoc.{Signature => DSignature}
import dotty.tools.scaladoc.Inkuire

import scala.quoted._

import SymOps._
import NameNormalizer._
import SyntheticsSupport._

trait ClassLikeSupport:
  self: TastyParser =>
  import qctx.reflect._

  private given qctx.type = qctx

  private def bareClasslikeKind(using Quotes)(symbol: reflect.Symbol): Kind =
    import reflect._
    if symbol.flags.is(Flags.Module) then Kind.Object
    else if symbol.flags.is(Flags.Trait) then  Kind.Trait(Nil, Nil)
    else if symbol.flags.is(Flags.Enum) then Kind.Enum(Nil, Nil)
    else if symbol.flags.is(Flags.Enum) && symbol.flags.is(Flags.Case) then Kind.EnumCase(Kind.Object)
    else Kind.Class(Nil, Nil)

  private def kindForClasslike(classDef: ClassDef): Kind =
    def typeArgs = classDef.getTypeParams.map(mkTypeArgument(_))

    def parameterModifier(parameter: Symbol): String =
      val fieldSymbol = classDef.symbol.declaredField(parameter.normalizedName)
      def isVal = fieldSymbol.flags.is(Flags.ParamAccessor) &&
        !classDef.symbol.flags.is(Flags.Case) &&
        !fieldSymbol.flags.is(Flags.Private)

      if fieldSymbol.flags.is(Flags.Mutable) then "var "
      else if isVal then "val "
      else ""

    def args = if constructorWithoutParamLists(classDef) then Nil else
      val constr =
        Some(classDef.constructor.symbol)
          .filter(s => s.exists && !s.isHiddenByVisibility)
          .map( _.tree.asInstanceOf[DefDef])
      constr.fold(Nil)(
        _.termParamss.map(pList => ParametersList(pList.params.map(p => mkParameter(p, parameterModifier)), paramListModifier(pList.params)))
        )

    if classDef.symbol.flags.is(Flags.Module) then Kind.Object
    else if classDef.symbol.flags.is(Flags.Trait) then
      Kind.Trait(typeArgs, args)
    else if classDef.symbol.flags.is(Flags.Enum) && classDef.symbol.flags.is(Flags.Case) then Kind.EnumCase(Kind.Class(typeArgs, args))
    else if classDef.symbol.flags.is(Flags.Enum) then Kind.Enum(typeArgs, args)
    else Kind.Class(typeArgs, args)

  def mkClass(classDef: ClassDef)(
    dri: DRI = classDef.symbol.dri,
    name: String = classDef.symbol.normalizedName,
    signatureOnly: Boolean = false,
    modifiers: Seq[Modifier] = classDef.symbol.getExtraModifiers(),
  ): Member =
    def unpackTreeToClassDef(tree: Tree): ClassDef = tree match
      case tree: ClassDef => tree
      case TypeDef(_, tbt: TypeBoundsTree) => unpackTreeToClassDef(tbt.tpe.typeSymbol.tree)
      case TypeDef(_, tt: TypeTree) => unpackTreeToClassDef(tt.tpe.typeSymbol.tree)
      case c: Apply =>
        c.symbol.owner.tree.symbol.tree match
          case tree: ClassDef => tree
      case tt: TypeTree => unpackTreeToClassDef(tt.tpe.typeSymbol.tree)

    def getSupertypesGraph(classDef: Tree, link: LinkToType): Seq[(LinkToType, LinkToType)] =
      val smbl = classDef.symbol
      val parents = unpackTreeToClassDef(classDef).parents
      parents.flatMap { case tree =>
        val symbol = if tree.symbol.isClassConstructor then tree.symbol.owner else tree.symbol
        val superLink = LinkToType(tree.asSignature, symbol.dri, bareClasslikeKind(symbol))
        Seq(link -> superLink) ++ getSupertypesGraph(tree, superLink)
      }

    val supertypes = getSupertypes(using qctx)(classDef).map {
      case (symbol, tpe) =>
        LinkToType(tpe.asSignature, symbol.dri, bareClasslikeKind(symbol))
    }
    val selfSiangture: DSignature = typeForClass(classDef).asSignature

    val graph = HierarchyGraph.withEdges(
      getSupertypesGraph(classDef, LinkToType(selfSiangture, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)))
    )

    val baseMember = mkMember(classDef.symbol, kindForClasslike(classDef), selfSiangture)(
      modifiers = modifiers,
      graph = graph,
      deprecated = classDef.symbol.isDeprecated()
    )

    if summon[DocContext].args.generateInkuire then {

      val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type]

      def varName(t: Inkuire.TypeLike): Option[String] = t match {
        case tpe: Inkuire.Type      => Some(tpe.name.name)
        case tl: Inkuire.TypeLambda => varName(tl.result)
        case _                      => None
      }

      val variableNames: Set[String] = classType.params.map(_.typ)
        .flatMap(varName(_).toList).toSet

      val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type])

      val isModule = classDef.symbol.flags.is(Flags.Module)

      if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents)))

      classDef.symbol.declaredTypes.foreach {
        case typeSymbol: Symbol =>
          val typeDef = typeSymbol.tree.asInstanceOf[TypeDef]
          if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then
            val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported
            val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames)
            t match
              case t: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported
              case _ =>
            tJava match
              case tJava: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty)))
              case _ =>
      }

      classDef.symbol.declaredMethods
        .filter { (s: Symbol) =>
          !s.flags.is(Flags.Private) &&
{'fraction_non_alphanumeric': 0.11228776474706809, 'fraction_numerical': 0.0, 'mean_word_length': 3.266990291262136, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 49, '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': '3018707', 'n_tokens_mistral': 3661, 'n_tokens_neox': 3593, 'n_words': 714}