private def createClass()

in scala/conversion/src/org/jetbrains/plugins/scala/conversion/JavaToScala.scala [699:912]


  private def createClass(
    inClass: PsiClass,
    externalProperties: ExternalProperties
  )(implicit conversionContext: ConversionContext): IntermediateNode = {
    val context = this.context.value

    def extendList: Seq[(PsiClassType, PsiJavaCodeReferenceElement)] = {
      val types = Seq.newBuilder[(PsiClassType, PsiJavaCodeReferenceElement)]
      if (inClass.getExtendsList != null) types ++= inClass.getExtendsList.getReferencedTypes.zip(inClass.getExtendsList.getReferenceElements)
      if (inClass.getImplementsList != null) types ++= inClass.getImplementsList.getReferencedTypes.zip(inClass.getImplementsList.getReferenceElements)
      types.result()
    }

    def collectClassObjectMembers(): (Seq[PsiMember], Seq[PsiMember]) = {
      val forClassBuilder = ArraySeq.newBuilder[PsiMember]
      val forObjectBuilder = ArraySeq.newBuilder[PsiMember]
      for (method <- inClass.getMethods if PsiTreeUtil.isAncestor(inClass, method, true)) {
        if (method.hasModifierProperty("static") || inClass.isEnum) forObjectBuilder += method else forClassBuilder += method
      }

      val serialVersionUID = serialVersion(inClass)
      for (field <- inClass.getFields if !serialVersionUID.contains(field)) {
        if (field.hasModifierProperty("static") || inClass.isEnum) forObjectBuilder += field else forClassBuilder += field
      }

      for (clazz <- inClass.getInnerClasses) {
        if (clazz.hasModifierProperty("static") || inClass.isEnum) forObjectBuilder += clazz else forClassBuilder += clazz
      }

      val forClass = forClassBuilder.result().sortBy(_.getTextOffset)
      val forObject = forObjectBuilder.result().sortBy(_.getTextOffset)
      (forClass, forObject)
    }

    val name = convertToIdentifier(inClass.getNameIdentifier)

    def handleObject(objectMembers: Seq[PsiMember]): IntermediateNode = {
      def handleAsEnum(modifiers: ModifiersConstruction): IntermediateNode = {
        Enum(name, modifiers, objectMembers.map(m => convertPsiToIntermediate(m, externalProperties)))
      }

      def handleAsObject(modifiers: ModifiersConstruction): IntermediateNode = {
        val membersOut = objectMembers.filter(!_.isInstanceOf[PsiEnumConstant]).map(convertPsiToIntermediate(_, externalProperties))
        val initializers = inClass.getInitializers.map((x: PsiClassInitializer) => convertPsiToIntermediate(x.getBody, externalProperties))
        val primaryConstructor = None
        val typeParams = None
        val companionObject = EmptyConstruction()
        ClassConstruction(
          name,
          primaryConstructor,
          membersOut,
          modifiers,
          typeParams,
          Some(initializers.toIndexedSeq),
          OBJECT,
          companionObject,
          None
        )
      }

      if (objectMembers.nonEmpty && !inClass.isInstanceOf[PsiAnonymousClass]) {
        context.push((true, inClass.qualifiedName))
        try {
          val modifiers = handleModifierList(inClass)
          val updatedModifiers = modifiers.without(ModifierType.ABSTRACT)
          if (inClass.isEnum) handleAsEnum(updatedModifiers) else handleAsObject(updatedModifiers)
        } finally {
          context.pop()
        }
      } else {
        EmptyConstruction()
      }
    }

    def couldFindInstancesForClass: Boolean = {
      def isParentValid(ref: PsiReference): Boolean =
        Option(ref.getElement).flatMap(element => Option(PsiTreeUtil.getParentOfType(element, classOf[PsiNewExpression], classOf[ScConstructorInvocation]))).exists {
          case n: PsiNewExpression if Option(n.getClassReference).contains(ref) => true
          case e: ScConstructorInvocation if e.reference.contains(ref) => true
          case _ => false
        }

      def withInstances = {
        ReferencesSearch
          .search(inClass, GlobalSearchScope.projectScope(inClass.getProject))
          .findAll()
          .asScala
          .exists(isParentValid)
      }

      if (conversionContext.textMode) {
        val p = Pattern.compile("new\\s+" + inClass.getName)
        p.matcher(inClass.getContainingFile.getText).find()
      }
      else withInstances
    }

    def handleAsClass(classMembers: Seq[PsiMember], objectMembers: Seq[PsiMember],
                      companionObject: IntermediateNode, extendList: Seq[(PsiClassType, PsiJavaCodeReferenceElement)]): IntermediateNode = {

      def handleAnonymousClass(clazz: PsiAnonymousClass): IntermediateNode = {
        val tp = convertTypePsiToIntermediate(clazz.getBaseClassType, clazz.getBaseClassReference, clazz.getProject)
        val argList = convertPsiToIntermediate(clazz.getArgumentList, externalProperties)
        val classMembersNodes = classMembers.map(convertPsiToIntermediate(_, externalProperties))
        val objectMembersNodes = objectMembers.map { m =>
          val node = convertPsiToIntermediate(m, externalProperties)
          //NOTE: for non-anonymous classes we would move static members to the companion object
          // However in Scala anonymous classes can't have companion object so we can't move them there
          node.comments.beforeComments.append(LiteralExpression("//TODO: 'static' modifier is not supported\n"))
          node
        }
        val members = classMembersNodes ++ objectMembersNodes
        AnonymousClass(
          tp,
          argList,
          members,
          extendList.map(el => convertTypePsiToIntermediate(el._1, el._2, clazz.getProject))
        )
      }

      def sortMembers(): Seq[PsiMember] = {
        def isConstructor(member: PsiMember): Boolean =
          member match {
            case Constructor(_) => true
            case _ => false
          }

        def sort(targetMap: mutable.HashMap[PsiMethod, PsiMethod]): Seq[PsiMember] = {
          def compareAsConstructors(left: PsiMethod, right: PsiMethod) = {
            val rightFromMap = targetMap.get(left)
            if (rightFromMap.isDefined && rightFromMap.get == right) {
              false // right constructor must be upper then left
            } else {
              val leftFromMap = targetMap.get(right)
              if (leftFromMap.isDefined && leftFromMap.get == left) {
                true
              } else {
                compareByOrder(right, left)
              }
            }
          }

          def compareByOrder(left: PsiMember, right: PsiMember): Boolean =
            classMembers.indexOf(left) > classMembers.indexOf(right)


          if (targetMap.isEmpty)
            classMembers
          else classMembers.sortWith {
            (left, right) =>
              if (isConstructor(left) && isConstructor(right)) {
                compareAsConstructors(left.asInstanceOf[PsiMethod], right.asInstanceOf[PsiMethod])
              } else {
                compareByOrder(right, left)
              }
          }
        }

        val constructorsCallMap = buildConstructorTargetMap(inClass.getConstructors.sortBy(_.getTextOffset).toIndexedSeq)
        sort(constructorsCallMap)
      }

      def updateMembersAndConvert(dropMembers: Option[Seq[PsiMember]]): Seq[IntermediateNode] = {
        val sortedMembers = sortMembers()
        val updatedMembers = dropMembers.map(el => sortedMembers.filter(!el.contains(_))).getOrElse(sortedMembers)
        updatedMembers.map(convertPsiToIntermediate(_, externalProperties))
      }

      def convertExtendList(): Seq[IntermediateNode] =
        extendList.map { case (a, b) =>
          convertTypePsiToIntermediate(a, b, inClass.getProject)
        }

      val condition = classMembers.nonEmpty ||
        (objectMembers.isEmpty || inClass.is[PsiAnonymousClass]) ||
        extendList.nonEmpty ||
        couldFindInstancesForClass

      if (condition) {
        context.push((false, inClass.qualifiedName))
        try {
          inClass match {
            case clazz: PsiAnonymousClass => handleAnonymousClass(clazz)
            case _ =>
              val typeParams = inClass.getTypeParameters.map(convertToTypeParameterConstruction(_, externalProperties))
              val modifiers = handleModifierList(inClass)
              val dropMembersAndPrimaryConstructor = handlePrimaryConstructor(inClass.getConstructors.toIndexedSeq)
              val classType = if (inClass.isInterface) INTERFACE else CLASS
              val members = updateMembersAndConvert(dropMembersAndPrimaryConstructor.map(_._1))

              ClassConstruction(
                name,
                dropMembersAndPrimaryConstructor.map(_._2),
                members,
                modifiers,
                Some(typeParams.toSeq),
                None,
                classType,
                companionObject,
                Some(convertExtendList())
              )
          }
        } finally {
          context.pop()
        }
      } else {
        companionObject
      }
    }

    val (classMembers, objectMembers) = collectClassObjectMembers()
    val companionObject = handleObject(objectMembers)
    handleAsClass(classMembers, objectMembers, companionObject, extendList)
  }