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)
}