in scala/conversion/src/org/jetbrains/plugins/scala/conversion/JavaToScala.scala [146:618]
private def convertPsiToIntermediate(
element: PsiElement,
externalProperties: ExternalProperties
)(implicit conversionContext: ConversionContext): IntermediateNode = {
if (element == null || conversionContext.dropElements.contains(element))
return EmptyConstruction()
if (element.getLanguage != JavaLanguage.INSTANCE)
return EmptyConstruction()
//NOTE: we need to calculate the comments before calculating IntermediateNode result
//because some comments can be attached to different nodes and we would like them to occur in the most top-level parent nodes
val comments = CommentsCollector.allCommentsForElement(element)(conversionContext.usedComments)
val result: IntermediateNode = element match {
case f: PsiFile =>
val children = f.getChildren.map(convertPsiToIntermediate(_, externalProperties)).toSeq
MainConstruction(children)
case unnamedClass: PsiImplicitClass =>
val children = unnamedClass.getChildren.map(convertPsiToIntermediate(_, externalProperties)).toSeq
MainConstruction(children)
case e: PsiExpressionStatement => convertPsiToIntermediate(e.getExpression, externalProperties)
case l: PsiLiteralExpression => LiteralExpression(l.getText)
case n: PsiIdentifier =>
convertToIdentifier(n)
case t: PsiTypeElement =>
convertTypePsiToIntermediate(t)
case w: PsiWhiteSpace => LiteralExpression(w.getText)
case r: PsiReturnStatement => ReturnStatement(convertPsiToIntermediate(r.getReturnValue, externalProperties))
case t: PsiThrowStatement => ThrowStatement(convertPsiToIntermediate(t.getException, externalProperties))
case i: PsiImportStatement => handleImport(i)
case i: PsiImportStaticStatement => handleImport(i)
case i: PsiImportList => ImportStatementList(i.getAllImportStatements.map(handleImport).distinct.toIndexedSeq)
case a: PsiAssignmentExpression =>
BinaryExpressionConstruction(convertPsiToIntermediate(a.getLExpression, externalProperties),
convertPsiToIntermediate(a.getRExpression, externalProperties), a.getOperationSign.getText, inExpression = false)
case e: PsiExpressionListStatement =>
ExpressionListStatement(e.getExpressionList.getExpressions.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq)
case d: PsiDeclarationStatement => ExpressionListStatement(d.getDeclaredElements.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq)
case b: PsiBlockStatement =>
convertToBlockConstruction(b.getCodeBlock, externalProperties)
case s: PsiSynchronizedStatement =>
val lock = Option(s.getLockExpression).map(convertPsiToIntermediate(_, externalProperties))
val body = Option(s.getBody).map(convertPsiToIntermediate(_, externalProperties))
SynchronizedStatement(lock, body)
case b: PsiCodeBlock =>
convertToBlockConstruction(b, externalProperties)
case t: PsiTypeParameter =>
convertToTypeParameterConstruction(t, externalProperties)
case i: PsiIfStatement =>
val condition = Option(i.getCondition).map(convertPsiToIntermediate(_, externalProperties))
val thenBranch = Option(i.getThenBranch).map(convertPsiToIntermediate(_, externalProperties))
val elseBranch = Option(i.getElseBranch).map(convertPsiToIntermediate(_, externalProperties))
IfStatement(condition, thenBranch, elseBranch)
case c: PsiConditionalExpression =>
val condition = Option(c.getCondition).map(convertPsiToIntermediate(_, externalProperties))
val thenBranch = Option(c.getThenExpression).map(convertPsiToIntermediate(_, externalProperties))
val elseBranch = Option(c.getElseExpression).map(convertPsiToIntermediate(_, externalProperties))
IfStatement(condition, thenBranch, elseBranch)
case w: PsiWhileStatement =>
//noinspection DuplicatedCode
val condition = Option(w.getCondition).map(convertPsiToIntermediate(_, externalProperties))
val body = Option(w.getBody).map(convertPsiToIntermediate(_, externalProperties))
WhileStatement(None, condition, body, None, WhileStatement.PRE_TEST_LOOP)
case w: PsiDoWhileStatement =>
//noinspection DuplicatedCode
val condition = Option(w.getCondition).map(convertPsiToIntermediate(_, externalProperties))
val body = Option(w.getBody).map(convertPsiToIntermediate(_, externalProperties))
WhileStatement(None, condition, body, None, WhileStatement.POST_TEST_LOOP)
case f: PsiForStatement =>
val countingLoop = CountingLoop.from(f)
val body = Option(f.getBody).map(convertPsiToIntermediate(_, externalProperties))
if (countingLoop != null) {
val name = convertPsiToIntermediate(countingLoop.getCounter.getNameIdentifier, externalProperties)
val iteratedValue = RangeExpression(
convertPsiToIntermediate(countingLoop.getInitializer, externalProperties),
convertPsiToIntermediate(countingLoop.getBound, externalProperties),
countingLoop.isIncluding, countingLoop.isDescending)
ForeachStatement(name, Some(iteratedValue), body, isJavaCollection = false)
} else {
val initialization = Option(f.getInitialization).map(convertPsiToIntermediate(_, externalProperties))
val condition = Some(f.getCondition match {
case _: PsiEmptyStatement => LiteralExpression("true")
case null => LiteralExpression("true")
case _ => convertPsiToIntermediate(f.getCondition, externalProperties)
})
val update = Option(f.getUpdate).map(convertPsiToIntermediate(_, externalProperties))
WhileStatement(initialization, condition, body, update, WhileStatement.PRE_TEST_LOOP)
}
case a: PsiAssertStatement =>
val condition = Option(a.getAssertCondition).map(convertPsiToIntermediate(_, externalProperties))
val description = Option(a.getAssertDescription).map(convertPsiToIntermediate(_, externalProperties))
AssertStatement(condition, description)
case s: PsiSwitchLabelStatementBase =>
val caseValues = if (s.isDefaultCase)
Seq(LiteralExpression("_"))
else
Option(s.getCaseLabelElementList)
.map(it => it.getElements.iterator.map(convertPsiToIntermediate(_, externalProperties)).toSeq)
.getOrElse(Seq.empty)
val body : Option[PsiStatement] = s match {
case rs: PsiSwitchLabeledRuleStatement => Option(rs.getBody)
case _ => None
}
val guardExpression = s.getGuardExpression.toOption
SwitchLabelStatement(
caseValues,
guardExpression.map(convertPsiToIntermediate(_, externalProperties)),
ScalaPsiUtil.functionArrow(s.getProject),
body.map(convertPsiToIntermediate(_, externalProperties))
)
case s: PsiSwitchBlock =>
val statements: Option[Array[PsiStatement]] =
Option(s.getBody).map(_.getStatements)
def defaultStatement: SwitchLabelStatement =
SwitchLabelStatement(Seq(LiteralExpression("_")), None, ScalaPsiUtil.functionArrow(s.getProject))
val expr = Option(s.getExpression).map(convertPsiToIntermediate(_, externalProperties))
val body = Option(s.getBody).map(convertPsiToIntermediate(_, externalProperties))
val hasEmptyStatement = statements.exists(_.isEmpty)
val body2 = if (hasEmptyStatement) Some(defaultStatement) else body
SwitchBlock(expr, body2)
case p: PsiPackageStatement => PackageStatement(convertPsiToIntermediate(p.getPackageReference, externalProperties))
case f: PsiForeachStatementBase =>
val tp = Option(f.getIteratedValue).flatMap((e: PsiExpression) => Option(e.getType))
val isJavaCollection = if (tp.isEmpty) true else !tp.get.isInstanceOf[PsiArrayType]
val iteratedValue = Option(f.getIteratedValue).map(convertPsiToIntermediate(_, externalProperties))
val body = Option(f.getBody).map(convertPsiToIntermediate(_, externalProperties))
val nameIdentifier = f match {
case statement: PsiForeachStatement => statement.getIterationParameter.getNameIdentifier
case patternStatement: PsiForeachPatternStatement =>
val pattern = patternStatement.getIterationPattern
val variable = JavaPsiPatternUtil.getPatternVariable(pattern)
if (variable != null) variable.getNameIdentifier else null
case _ => null
}
val name = convertPsiToIntermediate(nameIdentifier, externalProperties)
ForeachStatement(name, iteratedValue, body, isJavaCollection)
case r: PsiReferenceExpression =>
val args = Option(r.getParameterList).map(convertPsiToIntermediate(_, externalProperties))
val refName: Option[String] = {
val nameWithPrefix: String = if (conversionContext.textMode && r.getQualifier == null) r.resolve() match {
case clazz: PsiClass => ScalaPsiUtil.nameWithPrefixIfNeeded(clazz)
case _ => r.getReferenceName
} else r.getReferenceName
val name: String = if (externalProperties.isInstanceOf[WithReferenceExpression]) {
fieldParameterMap.getOrElse(r.getReferenceName, nameWithPrefix)
} else {
nameWithPrefix
}
Option(name)
}
var iResult = JavaCodeReferenceStatement(None, args, refName)
if (r.getQualifierExpression != null) {
val t = Option(r.getQualifierExpression).map(convertPsiToIntermediate(_, externalProperties))
iResult = JavaCodeReferenceStatement(t, args, refName)
} else {
r.resolve() match {
case f: PsiMember
if f.hasModifierProperty("static") =>
val clazz = f.containingClass
if (clazz != null && context.value.contains((false, clazz.qualifiedName))) {
val name = Option(clazz.getNameIdentifier).map(convertPsiToIntermediate(_, externalProperties))
iResult = JavaCodeReferenceStatement(name, args, refName)
}
case _ =>
}
}
handleAssociations(r, iResult)
iResult
case p: PsiJavaCodeReferenceElement =>
val qualifier = Option(p.getQualifier).map(convertPsiToIntermediate(_, externalProperties))
val args = Option(p.getParameterList).map(convertPsiToIntermediate(_, externalProperties))
JavaCodeReferenceStatement(qualifier, args, Option(p.getReferenceName))
case be: PsiBinaryExpression =>
def isOk: Boolean = {
if (be.getLOperand.getType.isInstanceOf[PsiPrimitiveType]) return false
be.getROperand match {
case l: PsiLiteralExpression if l.textMatches("null") => return false
case _ =>
}
true
}
def inExpression: Boolean = Option(be.getParent) match {
case Some(_: PsiExpression) => true
case _ => false
}
val operation = be.getOperationSign.getText match {
case "==" if isOk => "eq"
case "!=" if isOk => "ne"
case x => x
}
BinaryExpressionConstruction(
convertPsiToIntermediate(be.getLOperand, externalProperties),
convertPsiToIntermediate(be.getROperand, externalProperties),
operation, inExpression)
case c: PsiTypeCastExpression =>
ClassCast(
convertPsiToIntermediate(c.getOperand, externalProperties),
convertTypePsiToIntermediate(c.getCastType),
isPrimitive = c.getCastType.getType.isInstanceOf[PsiPrimitiveType] && c.getOperand.getType.isInstanceOf[PsiPrimitiveType]
)
case a: PsiArrayAccessExpression =>
ArrayAccess(
convertPsiToIntermediate(a.getArrayExpression, externalProperties),
convertPsiToIntermediate(a.getIndexExpression, externalProperties))
case a: PsiArrayInitializerExpression =>
ArrayInitializer(a.getInitializers.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq)
case c: PsiClassObjectAccessExpression => ClassObjectAccess(convertPsiToIntermediate(c.getOperand, externalProperties))
case typeTest: PsiTypeTestPattern =>
//TODO support Java pattern matching truly, see SCL-21510
LiteralExpression(typeTest.getText)
case i: PsiInstanceOfExpression =>
val checkType = i.getCheckType match {
case null =>
//type can be null since Java 15/16 when there is a variable: `obj instanceof String str`
//NOTE: this is a fast workaround just to avoid NPE (see SCL-21509)
//TODO support Java pattern matching truly, see SCL-21510
i.getPattern match {
case typeTest: PsiTypeTestPattern => typeTest.getCheckType
case _ => null
}
case t => t
}
val checkTypeNode = if (checkType != null) convertTypePsiToIntermediate(checkType) else EmptyTypeNode()
InstanceOfConstruction(
convertPsiToIntermediate(i.getOperand, externalProperties),
checkTypeNode
)
case m: PsiMethodCallExpression =>
def isSuper: Boolean = m.getMethodExpression.getQualifierExpression.isInstanceOf[PsiSuperExpression]
m.getMethodExpression.resolve() match {
case method: PsiMethod if method.getName == "parseInt" && m.getArgumentList.getExpressions.length == 1 &&
method.getContainingClass != null && method.getContainingClass.qualifiedName == "java.lang.Integer" =>
ClassCast(convertPsiToIntermediate(m.getArgumentList.getExpressions.apply(0), externalProperties),
TypeConstruction("Int"), isPrimitive = true)
case method: PsiMethod if method.getName == "parseDouble" && m.getArgumentList.getExpressions.length == 1 &&
method.getContainingClass != null && method.getContainingClass.qualifiedName == "java.lang.Double" =>
ClassCast(convertPsiToIntermediate(m.getArgumentList.getExpressions.apply(0), externalProperties),
TypeConstruction("Double"), isPrimitive = true)
case method: PsiMethod if method.getName == "round" && m.getArgumentList.getExpressions.length == 1 &&
method.getContainingClass != null && method.getContainingClass.qualifiedName == "java.lang.Math" =>
MethodCallExpression.build(
convertPsiToIntermediate(m.getArgumentList.getExpressions.apply(0), externalProperties), ".round", null)
case method: PsiMethod if method.getName == "equals" && m.getTypeArguments.isEmpty && !isSuper
&& m.getArgumentList.getExpressions.length == 1 =>
val receiver = Option(m.getMethodExpression.getQualifierExpression).map(convertPsiToIntermediate(_, externalProperties)).getOrElse(LiteralExpression("this"))
MethodCallExpression.build(
receiver,
" == ",
ExpressionList(Seq(convertPsiToIntermediate(m.getArgumentList.getExpressions.apply(0), externalProperties)))
)
case _ =>
MethodCallExpression(
convertPsiToIntermediate(m.getMethodExpression, externalProperties),
convertToExpressionList(m.getArgumentList, externalProperties),
(m.getType == PsiTypeConstants.Void) && m.getArgumentList.getExpressions.isEmpty
)
}
case t: PsiThisExpression =>
ThisExpression(Option(t.getQualifier).map(convertPsiToIntermediate(_, externalProperties)))
case s: PsiSuperExpression =>
SuperExpression(Option(s.getQualifier).map(convertPsiToIntermediate(_, externalProperties)))
case e: PsiExpressionList =>
convertToExpressionList(e, externalProperties)
case lambda: PsiLambdaExpression =>
FunctionalExpression(
convertToParameterListConstruction(lambda.getParameterList),
convertPsiToIntermediate(lambda.getBody, externalProperties)
)
case l: PsiLocalVariable =>
val parent = Option(PsiTreeUtil.getParentOfType(l, classOf[PsiCodeBlock], classOf[PsiBlockStatement]))
val needVar = if (parent.isEmpty) false else isVar(l, parent)
val initializer = Option(l.getInitializer).map(convertPsiToIntermediate(_, externalProperties))
val name = convertToIdentifier(l.getNameIdentifier)
LocalVariable(
handleModifierList(l),
name,
convertTypePsiToIntermediate(l.getType, l.getTypeElement, l.getProject),
needVar,
initializer
)
case enumConstant: PsiEnumConstant =>
EnumConstruction(convertToIdentifier(enumConstant.getNameIdentifier))
case f: PsiField =>
val modifiers = handleModifierList(f)
val needVar = isVar(f, Option(f.getContainingClass))
val initializer = Option(f.getInitializer).map(convertPsiToIntermediate(_, externalProperties))
val name = convertToIdentifier(f.getNameIdentifier)
FieldConstruction(
modifiers,
name,
convertTypePsiToIntermediate(f.getType, f.getTypeElement, f.getProject),
needVar,
initializer
)
case p: PsiParameterList =>
convertToParameterListConstruction(p)
case m: PsiMethod =>
def body: Option[IntermediateNode] = {
if (m.isConstructor) {
getFirstStatement(m).map(_.getExpression).flatMap {
case mc: PsiMethodCallExpression if mc.getMethodExpression.getQualifiedName == "this" =>
Some(convertPsiToIntermediate(m.getBody, externalProperties))
case _ =>
getStatements(m).map(statements => {
val statementsUpdated = LiteralExpression("this()") +: statements.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq
BlockConstruction(statementsUpdated)
})
}
} else {
Option(m.getBody).map(convertPsiToIntermediate(_, externalProperties))
}
}
def convertMethodReturnType: Option[TypeNode] =
if (m.getReturnType != PsiTypeConstants.Void || ScalaCodeStyleSettings.getInstance(m.getProject).ENFORCE_FUNCTIONAL_SYNTAX_FOR_UNIT)
Some(convertTypePsiToIntermediate(m.getReturnTypeElement))
else None
if (m.isConstructor) {
ConstructorSimply(
handleModifierList(m),
m.getTypeParameters.map(convertToTypeParameterConstruction(_, externalProperties)).toIndexedSeq,
m.parameters.map(convertToParameterConstruction),
body
)
} else {
val name = convertToIdentifier(m.getNameIdentifier)
MethodConstruction(
handleModifierList(m),
name,
m.getTypeParameters.map(convertToTypeParameterConstruction(_, externalProperties)).toIndexedSeq,
m.parameters.map(convertToParameterConstruction),
body,
convertMethodReturnType
)
}
case c: PsiClass =>
createClass(c, externalProperties)
case p: PsiParenthesizedExpression =>
val expr = Option(p.getExpression).map(convertPsiToIntermediate(_, externalProperties))
ParenthesizedExpression(expr)
case v: PsiArrayInitializerMemberValue =>
ArrayInitializer(v.getInitializers.map(convertPsiToIntermediate(_, externalProperties)).toSeq)
case annot: PsiAnnotation =>
def isArrayAnnotationParameter(pair: PsiNameValuePair): Boolean = {
AnnotationUtil.getAnnotationMethod(pair) match {
case method: PsiMethod =>
val returnType = method.getReturnType
returnType != null && returnType.isInstanceOf[PsiArrayType]
case _ => false
}
}
val attributes = annot.getParameterList.getAttributes
val attrResult = mutable.ArrayBuffer[(Option[IntermediateNode], Option[IntermediateNode])]()
for (attribute <- attributes) {
val value = Option(attribute.getValue) match {
case Some(v: PsiAnnotationMemberValue) if isArrayAnnotationParameter(attribute) =>
ArrayInitializer(Seq(convertPsiToIntermediate(v, externalProperties)))
case Some(_) => convertPsiToIntermediate(attribute.getValue, externalProperties)
case _ => null
}
attrResult += ((Option(attribute.getNameIdentifier).map(convertPsiToIntermediate(_, externalProperties)), Option(value)))
}
val inAnnotation = PsiTreeUtil.getParentOfType(annot, classOf[PsiAnnotation]) != null
val name = Option(annot.getNameReferenceElement).map(convertPsiToIntermediate(_, externalProperties))
AnnotationConstruction(inAnnotation, attrResult.toSeq, name)
case p: PsiParameter =>
convertToParameterConstruction(p)
case n: PsiNewExpression =>
val anonymousClass = n.getAnonymousClass
if (anonymousClass != null) {
val node = convertPsiToIntermediate(anonymousClass, externalProperties)
node match {
case ac: AnonymousClass =>
return AnonymousClassExpression(ac)
case other =>
return other
}
}
val iType = convertTypePsiToIntermediate(n.getType, n.getClassReference, n.getProject)
val withArrayInitializer = n.getArrayInitializer != null
val argList: Seq[IntermediateNode] =
if (n.getArrayInitializer != null)
n.getArrayInitializer.getInitializers.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq
else if (n.getArrayDimensions.nonEmpty)
n.getArrayDimensions.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq
else if (n.getArgumentList != null) {
if (n.getArgumentList.getExpressions.isEmpty)
n.getParent match {
case r: PsiJavaCodeReferenceElement if n == r.getQualifier =>
Seq(LiteralExpression("()"))
case _ => null
}
else
Seq(convertPsiToIntermediate(n.getArgumentList, externalProperties))
}
else null
NewExpression(iType, argList, withArrayInitializer)
case t: PsiTryStatement =>
val resourcesVariables = mutable.ArrayBuffer[(String, IntermediateNode)]()
Option(t.getResourceList).foreach { resourceList =>
val it = resourceList.iterator
while (it.hasNext) {
val next = it.next()
next match {
case variable: PsiResourceVariable =>
resourcesVariables += ((variable.getName, convertPsiToIntermediate(variable, externalProperties)))
case _ =>
}
}
}
val tryBlock = Option(t.getTryBlock).map(convertToBlockConstruction(_, externalProperties))
val catches: Seq[(ParameterConstruction, IntermediateNode)] = t.getCatchSections.map { (cb: PsiCatchSection) =>
(convertToParameterConstruction(cb.getParameter),
convertPsiToIntermediate(cb.getCatchBlock, externalProperties))
}.toIndexedSeq
val finallyBlockStatements = Option(t.getFinallyBlock).map(_.getStatements.map(convertPsiToIntermediate(_, externalProperties)).toSeq)
TryCatchStatement(resourcesVariables.toSeq, tryBlock, catches, finallyBlockStatements, ScalaPsiUtil.functionArrow(t.getProject))
case p: PsiPrefixExpression =>
PrefixExpression(convertPsiToIntermediate(p.getOperand, externalProperties), p.getOperationSign.getText, ExpressionUtils.isVoidContext(p))
case p: PsiPostfixExpression =>
PostfixExpression(convertPsiToIntermediate(p.getOperand, externalProperties), p.getOperationSign.getText, ExpressionUtils.isVoidContext(p))
case p: PsiPolyadicExpression =>
val tokenValue = if (p.getOperands.nonEmpty) {
p.getTokenBeforeOperand(p.getOperands.apply(1)).getText
} else ""
PolyadicExpression(p.getOperands.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq, tokenValue)
case r: PsiReferenceParameterList => TypeParameters(r.getTypeParameterElements.map(convertPsiToIntermediate(_, externalProperties)).toIndexedSeq)
case b: PsiBreakStatement =>
if (isBreakRemovable(b)) EmptyConstruction()
else if (b.getLabelIdentifier != null)
NotSupported(None, "break " + b.getLabelIdentifier.getText + "// todo: label break is not supported")
else NotSupported(None, "break //todo: break is not supported")
case y: PsiYieldStatement =>
if (isYieldRemovable(y)) convertPsiToIntermediate(y.getExpression, externalProperties)
else NotSupported(None, "`yield` " + Option(y.getExpression).map(_.getText).mkString + "// todo: Java's yield is not supported")
case c: PsiContinueStatement =>
if (c.getLabelIdentifier != null)
NotSupported(None, "continue " + c.getLabelIdentifier.getText + " //todo: continue is not supported")
else NotSupported(None, "continue //todo: continue is not supported")
case s: PsiLabeledStatement =>
val statements = Option(s.getStatement).map(convertPsiToIntermediate(_, externalProperties))
NotSupported(statements, s.getLabelIdentifier.getText + " //todo: labels are not supported")
case _: PsiEmptyStatement => EmptyConstruction()
case _: PsiErrorElement => EmptyConstruction()
case c: PsiComment if conversionContext.usedComments.contains(c) =>
EmptyConstruction()
case e =>
LiteralExpression(e.getText)
}
result.setComments(comments)
result
}