<commit_before>package scala.meta.internal.metap

import java.io._
import java.util.HashMap
import scala.collection.mutable
import scala.math.Ordering
import scala.meta.internal.semanticdb3._
import scala.meta.internal.semanticdb3.Accessibility.Tag._
import scala.meta.internal.semanticdb3.Diagnostic._
import scala.meta.internal.semanticdb3.Diagnostic.Severity._
import scala.meta.internal.semanticdb3.Language._
import scala.meta.internal.semanticdb3.Scala._
import scala.meta.internal.semanticdb3.SingletonType.Tag._
import scala.meta.internal.semanticdb3.SymbolInformation._
import scala.meta.internal.semanticdb3.SymbolInformation.Kind._
import scala.meta.internal.semanticdb3.SymbolInformation.Property._
import scala.meta.internal.semanticdb3.SymbolOccurrence._
import scala.meta.internal.semanticdb3.SymbolOccurrence.Role._
import scala.meta.internal.semanticdb3.Type.Tag._

class Printer(out: PrintStream, doc: TextDocument) {
  def print(): Unit = {
    out.println(doc.uri)
    out.println(s"-" * doc.uri.length)
    out.println("")

    out.println(s"Summary:")
    out.println(s"Schema => SemanticDB v${doc.schema.value}")
    out.println(s"Uri => ${doc.uri}")
    out.println(s"Text => ${if (doc.text.nonEmpty) "non-empty" else "empty"}")
    out.print("Language => ")
    pprint(doc.language)
    out.println()
    if (doc.symbols.nonEmpty) out.println(s"Symbols => ${doc.symbols.length} entries")
    if (doc.occurrences.nonEmpty) out.println(s"Occurrences => ${doc.occurrences.length} entries")
    if (doc.diagnostics.nonEmpty) out.println(s"Diagnostics => ${doc.diagnostics.length} entries")
    if (doc.synthetics.nonEmpty) out.println(s"Synthetics => ${doc.synthetics.length} entries")

    if (doc.symbols.nonEmpty) {
      out.println("")
      out.println("Symbols:")
      doc.symbols.sorted.foreach(pprint)
    }

    if (doc.occurrences.nonEmpty) {
      out.println("")
      out.println("Occurrences:")
      doc.occurrences.sorted.foreach(pprint)
    }

    if (doc.diagnostics.nonEmpty) {
      out.println("")
      out.println("Diagnostics:")
      doc.diagnostics.sorted.foreach(pprint)
    }

    if (doc.synthetics.nonEmpty) {
      out.println("")
      out.println("Synthetics:")
      doc.synthetics.sorted.foreach(pprint)
    }
  }

  private val lineToOffsetCache = new HashMap[TextDocument, Array[Int]]
  implicit class DocumentOps(doc: TextDocument) {
    def substring(range: Option[Range]): Option[String] = {
      range.flatMap { range =>
        if (doc.text.nonEmpty) {
          var lineToOffset = lineToOffsetCache.get(doc)
          if (lineToOffset == null) {
            val chars = doc.text.toArray
            val buf = new mutable.ArrayBuffer[Int]
            buf += 0
            var i = 0
            while (i < chars.length) {
              if (chars(i) == '\n') buf += (i + 1)
              i += 1
            }
            if (buf.last != chars.length) buf += chars.length
            lineToOffset = buf.toArray
            lineToOffsetCache.put(doc, lineToOffset)
          }
          val startOffset = lineToOffset(range.startLine) + range.startCharacter
          val endOffset = lineToOffset(range.endLine) + range.endCharacter
          Some(doc.text.substring(startOffset, endOffset))
        } else {
          None
        }
      }
    }
  }

  private lazy val symtab: Map[String, SymbolInformation] = {
    doc.symbols.map(info => (info.symbol, info)).toMap
  }

  private def pprint(language: Language): Unit = {
    language match {
      case SCALA => out.print("Scala")
      case JAVA => out.print("Java")
      case _ => out.print("Unknown")
    }
  }

  private def pprint(range: Range): Unit = {
    out.print("[")
    out.print(range.startLine)
    out.print(":")
    out.print(range.startCharacter)
    out.print("..")
    out.print(range.endLine)
    out.print(":")
    out.print(range.endCharacter)
    out.print(")")
  }

  private def pprint(name: String): Unit = {
    if (name.nonEmpty) out.print(name)
    else out.print("<?>")
  }

  private def pprint(sym: String, role: Role): List[String] = {
    val buf = List.newBuilder[String]
    buf += sym
    symtab.get(sym) match {
      case Some(info) =>
        role match {
          case REFERENCE =>
            pprint(info.name)
          case DEFINITION =>
            // NOTE: This mode is only used to print symbols that are part
            // of complex types, so we don't need to fully support all symbols here.
            rep(info.annotations, " ", " ") { ann =>
              val syms = pprint(ann)
              syms.foreach(buf.+=)
            }
            opt(info.accessibility) { acc =>
              if (acc.symbol.nonEmpty) buf += acc.symbol
              pprint(acc)
            }
            if ((info.properties & COVARIANT.value) != 0) out.print("+")
            if ((info.properties & CONTRAVARIANT.value) != 0) out.print("-")
            if ((info.properties & VAL.value) != 0) out.print("val ")
            if ((info.properties & VAR.value) != 0) out.print("var ")
            info.kind match {
              case METHOD =>
                out.print("method ")
                out.print(info.name)
              case TYPE =>
                out.print("type ")
                out.print(info.name)
                out.print(" ")
              case PARAMETER =>
                out.print(info.name)
                out.print(": ")
              case TYPE_PARAMETER =>
                out.print(info.name)
                out.print(" ")
              case _ =>
                out.print("<?>")
                return buf.result
            }
            info.tpe match {
              case Some(tpe) =>
                val syms = pprint(tpe)
                syms.foreach(buf.+=)
              case None =>
                out.print("<?>")
            }
          case UNKNOWN_ROLE | Role.Unrecognized(_) =>
            ()
        }
      case None =>
        if (sym.isGlobal) pprint(sym.desc.name)
        else pprint(sym)
        role match {
          case REFERENCE => ()
          case DEFINITION => out.print(": <?>")
          case UNKNOWN_ROLE | Role.Unrecognized(_) => ()
        }
    }
    buf.result
  }

  private def pprint(tpe: Type): List[String] = {
    val buf = List.newBuilder[String]
    def ref(sym: String): Unit = {
      val syms = pprint(sym, REFERENCE)
      syms.foreach(buf.+=)
    }
    def defn(sym: String): Unit = {
      val syms = pprint(sym, DEFINITION)
      syms.foreach(buf.+=)
    }
    def prefix(tpe: Type): Unit = {
      tpe.tag match {
        case TYPE_REF =>
          val Some(TypeRef(pre, sym, args)) = tpe.typeRef
          pre match {
            case Some(pre) if pre.tag.isSingletonType =>
              prefix(pre)
              out.print(".")
            case Some(pre) =>
              prefix(pre)<commit_msg>Refactor Printer.pprint(sym, role)<commit_after>package scala.meta.internal.metap

import java.io._
import java.util.HashMap
import scala.collection.mutable
import scala.math.Ordering
import scala.meta.internal.semanticdb3._
import scala.meta.internal.semanticdb3.Accessibility.Tag._
import scala.meta.internal.semanticdb3.Diagnostic._
import scala.meta.internal.semanticdb3.Diagnostic.Severity._
import scala.meta.internal.semanticdb3.Language._
import scala.meta.internal.semanticdb3.Scala._
import scala.meta.internal.semanticdb3.SingletonType.Tag._
import scala.meta.internal.semanticdb3.SymbolInformation._
import scala.meta.internal.semanticdb3.SymbolInformation.Kind._
import scala.meta.internal.semanticdb3.SymbolInformation.Property._
import scala.meta.internal.semanticdb3.SymbolOccurrence._
import scala.meta.internal.semanticdb3.SymbolOccurrence.Role._
import scala.meta.internal.semanticdb3.Type.Tag._

class Printer(out: PrintStream, doc: TextDocument) {
  def print(): Unit = {
    out.println(doc.uri)
    out.println(s"-" * doc.uri.length)
    out.println("")

    out.println(s"Summary:")
    out.println(s"Schema => SemanticDB v${doc.schema.value}")
    out.println(s"Uri => ${doc.uri}")
    out.println(s"Text => ${if (doc.text.nonEmpty) "non-empty" else "empty"}")
    out.print("Language => ")
    pprint(doc.language)
    out.println()
    if (doc.symbols.nonEmpty) out.println(s"Symbols => ${doc.symbols.length} entries")
    if (doc.occurrences.nonEmpty) out.println(s"Occurrences => ${doc.occurrences.length} entries")
    if (doc.diagnostics.nonEmpty) out.println(s"Diagnostics => ${doc.diagnostics.length} entries")
    if (doc.synthetics.nonEmpty) out.println(s"Synthetics => ${doc.synthetics.length} entries")

    if (doc.symbols.nonEmpty) {
      out.println("")
      out.println("Symbols:")
      doc.symbols.sorted.foreach(pprint)
    }

    if (doc.occurrences.nonEmpty) {
      out.println("")
      out.println("Occurrences:")
      doc.occurrences.sorted.foreach(pprint)
    }

    if (doc.diagnostics.nonEmpty) {
      out.println("")
      out.println("Diagnostics:")
      doc.diagnostics.sorted.foreach(pprint)
    }

    if (doc.synthetics.nonEmpty) {
      out.println("")
      out.println("Synthetics:")
      doc.synthetics.sorted.foreach(pprint)
    }
  }

  private val lineToOffsetCache = new HashMap[TextDocument, Array[Int]]
  implicit class DocumentOps(doc: TextDocument) {
    def substring(range: Option[Range]): Option[String] = {
      range.flatMap { range =>
        if (doc.text.nonEmpty) {
          var lineToOffset = lineToOffsetCache.get(doc)
          if (lineToOffset == null) {
            val chars = doc.text.toArray
            val buf = new mutable.ArrayBuffer[Int]
            buf += 0
            var i = 0
            while (i < chars.length) {
              if (chars(i) == '\n') buf += (i + 1)
              i += 1
            }
            if (buf.last != chars.length) buf += chars.length
            lineToOffset = buf.toArray
            lineToOffsetCache.put(doc, lineToOffset)
          }
          val startOffset = lineToOffset(range.startLine) + range.startCharacter
          val endOffset = lineToOffset(range.endLine) + range.endCharacter
          Some(doc.text.substring(startOffset, endOffset))
        } else {
          None
        }
      }
    }
  }

  private lazy val symtab: Map[String, SymbolInformation] = {
    doc.symbols.map(info => (info.symbol, info)).toMap
  }

  private def pprint(language: Language): Unit = {
    language match {
      case SCALA => out.print("Scala")
      case JAVA => out.print("Java")
      case _ => out.print("Unknown")
    }
  }

  private def pprint(range: Range): Unit = {
    out.print("[")
    out.print(range.startLine)
    out.print(":")
    out.print(range.startCharacter)
    out.print("..")
    out.print(range.endLine)
    out.print(":")
    out.print(range.endCharacter)
    out.print(")")
  }

  private def pprint(name: String): Unit = {
    if (name.nonEmpty) out.print(name)
    else out.print("<?>")
  }

  private def pprint(sym: String, role: Role): List[String] = {
    val buf = List.newBuilder[String]
    buf += sym
    role match {
      case REFERENCE =>
        symtab.get(sym) match {
          case Some(info) => pprint(info.name)
          case None if sym.isGlobal => pprint(sym.desc.name)
          case _ => pprint(sym)
        }
      case DEFINITION =>
        symtab.get(sym) match {
          case Some(info) =>
            // NOTE: This mode is only used to print symbols that are part
            // of complex types, so we don't need to fully support all symbols here.
            rep(info.annotations, " ", " ") { ann =>
              val syms = pprint(ann)
              syms.foreach(buf.+=)
            }
            opt(info.accessibility) { acc =>
              if (acc.symbol.nonEmpty) buf += acc.symbol
              pprint(acc)
            }
            if ((info.properties & COVARIANT.value) != 0) out.print("+")
            if ((info.properties & CONTRAVARIANT.value) != 0) out.print("-")
            if ((info.properties & VAL.value) != 0) out.print("val ")
            if ((info.properties & VAR.value) != 0) out.print("var ")
            info.kind match {
              case METHOD =>
                out.print("method ")
                out.print(info.name)
              case TYPE =>
                out.print("type ")
                out.print(info.name)
                out.print(" ")
              case PARAMETER =>
                out.print(info.name)
                out.print(": ")
              case TYPE_PARAMETER =>
                out.print(info.name)
                out.print(" ")
              case _ =>
                out.print("<?>")
                return buf.result
            }
            info.tpe match {
              case Some(tpe) =>
                val syms = pprint(tpe)
                syms.foreach(buf.+=)
              case None =>
                out.print("<?>")
            }
          case None =>
            if (sym.isGlobal) pprint(sym.desc.name) else pprint(sym)
            out.print(": <?>")
        }
      case UNKNOWN_ROLE | Role.Unrecognized(_) =>
        ()
    }
    buf.result
  }

  private def pprint(tpe: Type): List[String] = {
    val buf = List.newBuilder[String]
    def ref(sym: String): Unit = {
      val syms = pprint(sym, REFERENCE)
      syms.foreach(buf.+=)
    }
    def defn(sym: String): Unit = {
      val syms = pprint(sym, DEFINITION)
      syms.foreach(buf.+=)
    }
    def prefix(tpe: Type): Unit = {
      tpe.tag match {
        case TYPE_REF =>
          val Some(TypeRef(pre, sym, args)) = tpe.typeRef
          pre match {
            case Some(pre) if pre.tag.isSingletonType =>
              prefix(pre)
              out.print(".")
            case Some(pre) =>
              prefix(pre)
{'fraction_non_alphanumeric': 0.1351845085860431, 'fraction_numerical': 0.003069053708439898, 'mean_word_length': 2.0928813559322035, 'pattern_counts': {'":': 8, '<': 13, '<?xml version=': 0, '>': 77, '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': '6036973', 'n_tokens_mistral': 4358, 'n_tokens_neox': 4252, 'n_words': 813}