private def sinfos()

in rsc/src/main/scala/rsc/classpath/javacp/Javacp.scala [25:243]


  private def sinfos(
      node: ClassNode,
      index: Index,
      access: Int,
      scope: Scope): List[s.SymbolInformation] = {
    val buf = ListBuffer.empty[s.SymbolInformation]
    val decls = ListBuffer.empty[String]

    def addInfo(
        symbol: String,
        kind: s.SymbolInformation.Kind,
        displayName: String,
        sig: s.Signature,
        access: Int): s.SymbolInformation = {
      val info = s.SymbolInformation(
        symbol = symbol,
        language = l.JAVA,
        kind = kind,
        properties = sproperties(access, node),
        displayName = displayName,
        signature = sig,
        annotations = sannotations(access),
        access = saccess(access, symbol, kind)
      )
      buf += info
      info
    }

    if (isAnonymousClass(node)) return Nil
    val classSymbol = ssym(node.name)
    val classDisplayName = sdisplayName(node.name)
    val classAccess = node.access | access
    val hasOuterClassReference = node.fields.asScala.exists(isOuterClassReference)

    val classKind =
      if (classAccess.hasFlag(o.ACC_INTERFACE)) k.INTERFACE
      else k.CLASS

    val isJavaLangObject = node.name == "java/lang/Object"
    val classSignature: ClassSignature =
      if (isJavaLangObject) {
        // java/lang/Object has no super class so node.superName == null.
        // ClassSignature requires a non-null superName so we special-handle java/lang/Object
        // when assigning classParents below.
        ClassSignature.simple("impossible", Nil)
      } else if (node.signature == null) {
        ClassSignature.simple(node.superName, node.interfaces.asScala.toList)
      } else {
        JavaTypeSignature.parse(node.signature, new ClassSignatureVisitor)
      }

    val (classScope: Scope, classTypeParameters) =
      classSignature.typeParameters match {
        case Some(tp) => addTypeParameters(tp, classSymbol, scope)
        case _ => scope -> Nil
      }
    classTypeParameters.foreach(buf += _)

    val classParents =
      if (isJavaLangObject) Nil
      else classSignature.parents.map(_.toSemanticTpe(classScope))

    node.fields.asScala
      .filterNot(_.access.hasFlag(o.ACC_SYNTHETIC))
      .foreach { field: FieldNode =>
        if (isOuterClassReference(field)) {
          // Drop the constructor argument that holds the reference to the outer class.
          ()
        } else {
          val fieldSymbol = Symbols.Global(classSymbol, d.Term(field.name))
          val fieldDisplayName = field.name
          val fieldSignature = JavaTypeSignature.parse(
            if (field.signature == null) field.desc else field.signature,
            new FieldSignatureVisitor
          )
          val fieldInfo = addInfo(
            fieldSymbol,
            k.FIELD,
            fieldDisplayName,
            s.ValueSignature(fieldSignature.toSemanticTpe(classScope)),
            field.access
          )

          decls += fieldInfo.symbol
        }
      }

    val methodSignatures = node.methods.asScala
      .filterNot(_.access.hasFlag(o.ACC_SYNTHETIC))
      .map { method: MethodNode =>
        val signature = JavaTypeSignature.parse(
          if (method.signature == null) method.desc else method.signature,
          new MethodSignatureVisitor
        )
        MethodInfo(method, signature)
      }
      .filterNot(_.signature.params.nonEmpty)

    // NOTE: we sort methods by whether they're static or not in order to compute same method symbols as metac.
    // In scalac, static class members are separated from non-static members, which makes it impossible
    // to recover the original mixed static/non-static member order in the classfile.
    val byStaticAccess = methodSignatures.sortBy(_.node.access.hasFlag(o.ACC_STATIC))

    methodSignatures.foreach {
      case method: MethodInfo if method.node.name == "<clinit>" =>
        ()
      case method: MethodInfo =>
        val isConstructor = method.node.name == "<init>"
        // FIXME: https://github.com/twitter/rsc/issues/229.
        // This is quite incorrect, but quite convenient.
        val methodDescriptor = d.Method(method.node.name, "()")
        val methodSymbol = Symbols.Global(classSymbol, methodDescriptor)

        val (methodScope, methodTypeParameters) = method.signature.typeParameters match {
          case Some(tp: TypeParameters) => addTypeParameters(tp, methodSymbol, classScope)
          case _ => classScope -> Nil
        }
        methodTypeParameters.foreach(buf += _)

        val params =
          if (isConstructor && hasOuterClassReference &&
              // Guard against an empty parameter list, which seems to only happen
              // in the JDK for java/util/regex/Pattern.class
              method.signature.params.nonEmpty) {
            // Drop the constructor argument that holds the reference to the outer class.
            method.signature.params.tail
          } else {
            method.signature.params
          }

        val parameters: List[s.SymbolInformation] = params.zipWithIndex.map {
          case (param: JavaTypeSignature, i) =>
            val paramDisplayName = {
              if (method.node.parameters == null) "param" + i
              else method.node.parameters.get(i).name
            }
            val paramSymbol = Symbols.Global(methodSymbol, d.Parameter(paramDisplayName))
            val isRepeatedType = method.node.access.hasFlag(o.ACC_VARARGS) && i == params.length - 1
            val paramTpe =
              if (isRepeatedType) {
                param.toSemanticTpe(methodScope) match {
                  case s.TypeRef(s.NoType, "scala/Array#", targ :: Nil) =>
                    s.RepeatedType(targ)
                  case tpe =>
                    sys.error(s"expected $paramDisplayName to be a scala/Array#, found $tpe")
                }
              } else {
                param.toSemanticTpe(methodScope)
              }
            addInfo(
              paramSymbol,
              k.PARAMETER,
              paramDisplayName,
              s.ValueSignature(paramTpe),
              o.ACC_PUBLIC
            )
        }

        val returnType = {
          if (isConstructor) s.NoType
          else method.signature.result.toSemanticTpe(methodScope)
        }

        val methodKind = if (isConstructor) k.CONSTRUCTOR else k.METHOD

        val methodDisplayName = method.node.name

        val methodSig = s.MethodSignature(
          typeParameters = Some(s.Scope(methodTypeParameters.map(_.symbol))),
          parameterLists = List(s.Scope(parameters.map(_.symbol))),
          returnType = returnType
        )

        val methodInfo = addInfo(
          methodSymbol,
          methodKind,
          methodDisplayName,
          methodSig,
          method.node.access
        )

        decls += methodInfo.symbol
    }

    // node.innerClasses includes all inner classes, both direct and those nested inside other inner classes.
    val directInnerClasses = node.innerClasses.asScala.filter(_.outerName == node.name)
    directInnerClasses.foreach { ic =>
      val innerClassSymbol = ssym(ic.name)
      decls += innerClassSymbol
      val innerClassNode = {
        val entry = index(ic.name + ".class").asInstanceOf[FileEntry]
        val in = entry.openStream()
        val node = new ClassNode()
        try {
          new ClassReader(in).accept(node, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES)
          node
        } finally {
          in.close()
        }
      }
      buf ++= sinfos(innerClassNode, index, ic.access, classScope)
    }

    val classSig = s.ClassSignature(
      typeParameters = Some(s.Scope(classTypeParameters.map(_.symbol))),
      parents = classParents,
      self = s.NoType,
      declarations = Some(s.Scope(decls))
    )

    addInfo(
      classSymbol,
      classKind,
      classDisplayName,
      classSig,
      classAccess
    )
    buf.result()
  }