<commit_before>package dotty.tools
package dotc
package core
package pickling

import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._
import SymDenotations._, UnPickler._, Constants._, Trees._, Annotations._, Positions._
import java.io.{ File, IOException }
import java.lang.Integer.toHexString
import scala.collection.{ mutable, immutable }
import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
import scala.annotation.switch
import io.AbstractFile

class ClassfileParser(
    classfile: AbstractFile,
    classRoot: LazyClassDenotation,
    moduleRoot: LazyClassDenotation)(implicit cctx: CondensedContext) {

  import ClassfileConstants._
  import cctx.debuglog
  import cctx.base.{settings, loaders, definitions => defn}

  protected val in = new AbstractFileReader(classfile)

  protected val staticModule: Symbol = moduleRoot.sourceModule

  protected val instanceScope: Scope = newScope     // the scope of all instance definitions
  protected val staticScope: Scope = newScope       // the scope of all static definitions
  protected var pool: ConstantPool = _              // the classfile's constant pool

  protected var currentClassName: Name = _      // JVM name of the current class
  protected var classTParams = Map[Name,Symbol]()
  protected var srcfile0 : Option[AbstractFile] = None //needs fleshing out

  def srcfile = srcfile0

  private def currentIsTopLevel = !(classRoot.name contains '$')
  private val mk = makeTypedTree

  private def mismatchError(c: Symbol) = {
    throw new IOException("class file '%s' has location not matching its contents: contains ".format(in.file) + c)
  }

  def run(): Unit = try {
    debuglog("[class] >> " + classRoot.fullName)
    parseHeader
    this.pool = new ConstantPool
    parseClass()
  } catch {
    case e: RuntimeException =>
      if (settings.debug.value) e.printStackTrace()
      throw new IOException(
        s"""class file $classfile is broken, reading aborted with $e.getClass
           |${Option(e.getMessage).getOrElse("")}""".stripMargin)
  }

  private def parseHeader() {
    val magic = in.nextInt
    if (magic != JAVA_MAGIC)
      throw new IOException("class file '" + in.file + "' "
                            + "has wrong magic number 0x" + toHexString(magic)
                            + ", should be 0x" + toHexString(JAVA_MAGIC))
    val minorVersion = in.nextChar.toInt
    val majorVersion = in.nextChar.toInt
    if ((majorVersion < JAVA_MAJOR_VERSION) ||
        ((majorVersion == JAVA_MAJOR_VERSION) &&
         (minorVersion < JAVA_MINOR_VERSION)))
      throw new IOException("class file '" + in.file + "' "
                            + "has unknown version "
                            + majorVersion + "." + minorVersion
                            + ", should be at least "
                            + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION)
  }

  /** Return the class symbol of the given name. */
  def classNameToSymbol(name: Name): Symbol = innerClasses.get(name) match {
    case Some(entry) => innerClasses.classSymbol(entry.externalName)
    case None => cctx.requiredClass(name)
  }

  var sawPrivateConstructor = false

  def parseClass() {
    val jflags       = in.nextChar
    val isAnnotation = hasAnnotation(jflags)
    val sflags       = FlagTranslation.classFlags(jflags)
    val nameIdx      = in.nextChar
    currentClassName = pool.getClassName(nameIdx)

    if (currentIsTopLevel) {
      val c = pool.getClassSymbol(nameIdx)
      if (c != classRoot.symbol) mismatchError(c)
    }

    addEnclosingTParams

    if (unpickleOrParseInnerClasses()) return

    /** Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled.
     *  Updates the read pointer of 'in'. */
    def parseParents: List[Type] = {
      val superType = if (isAnnotation) { in.nextChar; defn.AnnotationClass.typeConstructor }
                      else pool.getSuperClass(in.nextChar).typeConstructor
      val ifaceCount = in.nextChar
      var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(in.nextChar).typeConstructor
      if (isAnnotation) ifaces = defn.ClassfileAnnotationClass.typeConstructor :: ifaces
      superType :: ifaces
    }

    var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol) // might be overridden by later parseAttributes
    val staticInfo = TempClassInfoType(List(), staticScope, moduleRoot.symbol)

    enterOwnInnerClasses

    classRoot.flags = sflags
    moduleRoot.flags = Flags.JavaDefined
    setPrivateWithin(classRoot, jflags)
    setPrivateWithin(moduleRoot, jflags)

    for (i <- 0 until in.nextChar) parseMember(method = false)
    for (i <- 0 until in.nextChar) parseMember(method = true)

    val needsConstructor =
      instanceScope.lookup(nme.CONSTRUCTOR) == NoSymbol && !(sflags is Flags.Interface)

    if (needsConstructor)
      instanceScope enter
        cctx.newSymbol(
            classRoot.symbol,
            nme.CONSTRUCTOR, Flags.EmptyFlags,
            MethodType(Nil, Nil)(_ => classRoot.typeConstructor))

    classInfo = parseAttributes(classRoot.symbol, classInfo)
    assignClassFields(classRoot, classInfo, classRoot.typeConstructor)
    assignClassFields(moduleRoot, staticInfo, moduleRoot.typeConstructor)
  }

  /** Add type parameters of enclosing classes */
  def addEnclosingTParams {
    var sym = classRoot.owner
    while (sym.isClass && !sym.isModuleClass) {
      for (tparam <- sym.typeParams) {
        classTParams = classTParams.updated(tparam.name, tparam)
      }
      sym = sym.owner
    }
  }

  def parseMember(method: Boolean) = {
    val start = new Offset(in.bp)
    val jflags = in.nextChar
    val sflags =
      if (method) FlagTranslation.methodFlags(jflags)
      else FlagTranslation.fieldFlags(jflags)
    val name = pool.getName(in.nextChar)
    cctx.newLazySymbol(getOwner(jflags), name, sflags, memberCompleter, start).entered
  }

  object memberCompleter extends SymCompleter {
    def complete(denot: LazySymDenotation) = {
      val oldbp = in.bp
      try {
        in.bp = denot.symbol.offset.value
        val sym = denot.symbol
        val jflags = in.nextChar
        val isEnum  = (jflags & JAVA_ACC_ENUM) != 0
        val name = pool.getName(in.nextChar)
        val info = pool.getType(in.nextChar)

        denot.info = if (isEnum) ConstantType(Constant(sym)) else info
        if (name == nme.CONSTRUCTOR)
          // if this is a non-static inner class, remove the explicit outer parameter
          innerClasses.get(currentClassName) match {
            case Some(entry) if !isStatic(entry.jflags) =>
              val mt @ MethodType(paramnames, paramtypes) = info<commit_msg>Optimization: don't generate member symbols for private members in a Java classfile.<commit_after>package dotty.tools
package dotc
package core
package pickling

import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._
import SymDenotations._, UnPickler._, Constants._, Trees._, Annotations._, Positions._
import java.io.{ File, IOException }
import java.lang.Integer.toHexString
import scala.collection.{ mutable, immutable }
import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
import scala.annotation.switch
import io.AbstractFile

class ClassfileParser(
    classfile: AbstractFile,
    classRoot: LazyClassDenotation,
    moduleRoot: LazyClassDenotation)(implicit cctx: CondensedContext) {

  import ClassfileConstants._
  import cctx.debuglog
  import cctx.base.{settings, loaders, definitions => defn}

  protected val in = new AbstractFileReader(classfile)

  protected val staticModule: Symbol = moduleRoot.sourceModule

  protected val instanceScope: Scope = newScope     // the scope of all instance definitions
  protected val staticScope: Scope = newScope       // the scope of all static definitions
  protected var pool: ConstantPool = _              // the classfile's constant pool

  protected var currentClassName: Name = _      // JVM name of the current class
  protected var classTParams = Map[Name,Symbol]()
  protected var srcfile0 : Option[AbstractFile] = None //needs fleshing out

  def srcfile = srcfile0

  private def currentIsTopLevel = !(classRoot.name contains '$')
  private val mk = makeTypedTree

  private def mismatchError(c: Symbol) = {
    throw new IOException("class file '%s' has location not matching its contents: contains ".format(in.file) + c)
  }

  def run(): Unit = try {
    debuglog("[class] >> " + classRoot.fullName)
    parseHeader
    this.pool = new ConstantPool
    parseClass()
  } catch {
    case e: RuntimeException =>
      if (settings.debug.value) e.printStackTrace()
      throw new IOException(
        s"""class file $classfile is broken, reading aborted with $e.getClass
           |${Option(e.getMessage).getOrElse("")}""".stripMargin)
  }

  private def parseHeader() {
    val magic = in.nextInt
    if (magic != JAVA_MAGIC)
      throw new IOException("class file '" + in.file + "' "
                            + "has wrong magic number 0x" + toHexString(magic)
                            + ", should be 0x" + toHexString(JAVA_MAGIC))
    val minorVersion = in.nextChar.toInt
    val majorVersion = in.nextChar.toInt
    if ((majorVersion < JAVA_MAJOR_VERSION) ||
        ((majorVersion == JAVA_MAJOR_VERSION) &&
         (minorVersion < JAVA_MINOR_VERSION)))
      throw new IOException("class file '" + in.file + "' "
                            + "has unknown version "
                            + majorVersion + "." + minorVersion
                            + ", should be at least "
                            + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION)
  }

  /** Return the class symbol of the given name. */
  def classNameToSymbol(name: Name): Symbol = innerClasses.get(name) match {
    case Some(entry) => innerClasses.classSymbol(entry.externalName)
    case None => cctx.requiredClass(name)
  }

  var sawPrivateConstructor = false

  def parseClass() {
    val jflags       = in.nextChar
    val isAnnotation = hasAnnotation(jflags)
    val sflags       = FlagTranslation.classFlags(jflags)
    val nameIdx      = in.nextChar
    currentClassName = pool.getClassName(nameIdx)

    if (currentIsTopLevel) {
      val c = pool.getClassSymbol(nameIdx)
      if (c != classRoot.symbol) mismatchError(c)
    }

    addEnclosingTParams

    if (unpickleOrParseInnerClasses()) return

    /** Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled.
     *  Updates the read pointer of 'in'. */
    def parseParents: List[Type] = {
      val superType = if (isAnnotation) { in.nextChar; defn.AnnotationClass.typeConstructor }
                      else pool.getSuperClass(in.nextChar).typeConstructor
      val ifaceCount = in.nextChar
      var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(in.nextChar).typeConstructor
      if (isAnnotation) ifaces = defn.ClassfileAnnotationClass.typeConstructor :: ifaces
      superType :: ifaces
    }

    var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol) // might be overridden by later parseAttributes
    val staticInfo = TempClassInfoType(List(), staticScope, moduleRoot.symbol)

    enterOwnInnerClasses

    classRoot.flags = sflags
    moduleRoot.flags = Flags.JavaDefined
    setPrivateWithin(classRoot, jflags)
    setPrivateWithin(moduleRoot, jflags)

    for (i <- 0 until in.nextChar) parseMember(method = false)
    for (i <- 0 until in.nextChar) parseMember(method = true)

    val needsConstructor =
      instanceScope.lookup(nme.CONSTRUCTOR) == NoSymbol && !(sflags is Flags.Interface)

    if (needsConstructor)
      instanceScope enter
        cctx.newSymbol(
            classRoot.symbol,
            nme.CONSTRUCTOR, Flags.EmptyFlags,
            MethodType(Nil, Nil)(_ => classRoot.typeConstructor))

    classInfo = parseAttributes(classRoot.symbol, classInfo)
    assignClassFields(classRoot, classInfo, classRoot.typeConstructor)
    assignClassFields(moduleRoot, staticInfo, moduleRoot.typeConstructor)
  }

  /** Add type parameters of enclosing classes */
  def addEnclosingTParams {
    var sym = classRoot.owner
    while (sym.isClass && !sym.isModuleClass) {
      for (tparam <- sym.typeParams) {
        classTParams = classTParams.updated(tparam.name, tparam)
      }
      sym = sym.owner
    }
  }

  def parseMember(method: Boolean): Unit = {
    val start = new Offset(in.bp)
    val jflags = in.nextChar
    val sflags =
      if (method) FlagTranslation.methodFlags(jflags)
      else FlagTranslation.fieldFlags(jflags)
    val name = pool.getName(in.nextChar)
    if (!(sflags is Flags.Private) || name == nme.CONSTRUCTOR || settings.optimise.value)
      cctx.newLazySymbol(getOwner(jflags), name, sflags, memberCompleter, start).entered
  }

  object memberCompleter extends SymCompleter {
    def complete(denot: LazySymDenotation) = {
      val oldbp = in.bp
      try {
        in.bp = denot.symbol.offset.value
        val sym = denot.symbol
        val jflags = in.nextChar
        val isEnum  = (jflags & JAVA_ACC_ENUM) != 0
        val name = pool.getName(in.nextChar)
        val info = pool.getType(in.nextChar)

        denot.info = if (isEnum) ConstantType(Constant(sym)) else info
        if (name == nme.CONSTRUCTOR)
          // if this is a non-static inner class, remove the explicit outer parameter
          innerClasses.get(currentClassName) match {
            case Some(entry) if !isStatic(entry.jflags) =>
              val mt @ MethodType(paramnames, paramtypes) = info
{'fraction_non_alphanumeric': 0.09451643604949118, 'fraction_numerical': 0.0011713888278790541, 'mean_word_length': 2.9918176504967855, 'pattern_counts': {'":': 0, '<': 15, '<?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': '413475', 'n_tokens_mistral': 4010, 'n_tokens_neox': 3895, 'n_words': 1050}