in scala/uast/src/org/jetbrains/plugins/scala/lang/psi/uast/converter/Scala2UastConverter.scala [76:337]
private def makeUParentAndPin[U <: UElement](sourcePsi: PsiElement,
converted: Free[U]): U =
converted.pinTo(
LazyUElement.fromThunk(() => makeUParent(sourcePsi, converted).orNull)
)
private def convertToFree[U <: UElement: ClassTag: NotNothing](
sourcePsi: PsiElement,
convertLambdas: Boolean = true
): Option[Free[U]] = {
import ConverterUtils._
val requiredType = implicitly[ClassTag[U]].runtimeClass.asInstanceOf[Class[U]]
//performance optimization
if (!isUnitTestMode && !isPossibleToConvert(requiredType, sourcePsi)) {
return None
}
//noinspection GetOrElseNull,ConvertibleToMethodValue
val elementOpt: Option[Free[UElement]] =
Option((sourcePsi match {
// ========================= DECLARATIONS ===============================
case file: ScalaFile =>
(_: LazyUElement) =>
new ScUFile(
file,
UastFacade.INSTANCE.findPlugin(file).asInstanceOf[ScalaUastLanguagePlugin]
)
case e: ScImportStmt => new ScUImportStatement(e, _)
case e: ScTypeDefinition => new ScUClass(e, _)
case ScUVariable(parent2UField) => parent2UField(_)
case e: ScMethodLike if !e.isLocal => new ScUMethod(e, _)
case e: ScPrimaryConstructorWrapper => new ScUMethod(e.delegate, _)
case e: ScFunctionWrapper => new ScUMethod(e.delegate, _)
case e: ScParameter => new ScUParameter(e, _)
case e: ScValueOrVariable => new ScUValOrVarDeclarationsExpression(e, _)
case e: ScFunctionDefinition if e.isLocal =>
new ScULocalFunctionDeclarationExpression(e, _)
//Handle case with anonymous class: new SomeClass() { ... }
//NOTE: we attach `ScUAnonymousClass` UAST element to `ScExtendsBlock` PSI element and not to `ScTemplateBody` because here:
//com.intellij.codeInspection.NonExtendableApiUsageInspection.NonExtendableApiUsageProcessor.processReference
//it's assumed that `USimpleNameReferenceExpression` (representing `SomeClass` identifier) will have UClass as it's parent
case eb: ScExtendsBlock if eb.isAnonymousClass =>
//noinspection ScalaUnusedSymbol
(for {
nt @ (td: ScNewTemplateDefinition) <- Option(eb.getParent)
} yield new ScUAnonymousClass(nt, eb, _: LazyUElement)).orNull
case e: ScNewTemplateDefinition if e.extendsBlock.isAnonymousClass =>
new ScUObjectLiteralExpression(e, _)
case constructorInvocation: ScConstructorInvocation =>
val isAnnotationConstructorCall = constructorInvocation.getParent.is[ScAnnotationExpr]
if (isAnnotationConstructorCall)
null
else
new ScUConstructorCallExpression(constructorInvocation, _)
case e: ScAnnotation =>
new ScUAnnotation(e, _)
// ========================= LAMBDAS ====================================
case lambdaExpr: ScFunctionExpr =>
new ScULambdaExpression(lambdaExpr, _)
case block: ScBlock if block.isPartialFunction =>
new ScUPartialLambdaExpression(block, _)
case us: ScUnderscoreSection if us.bindingExpr.collect {
case ScReference(_: PsiMethod) =>
}.isDefined =>
us.bindingExpr match {
case Some(binding: ScReference) =>
new ScUCallableReferenceExpression(binding, _)
case _ => null
}
case us: ScExpression if isUnderscoreFunction(us) && convertLambdas =>
new ScUUnderscoreLambdaExpression(us, _)
case mv: ScExpression if isMethodValue(mv, convertLambdas) =>
mv match {
case ref: ScReference =>
new ScUCallableReferenceExpression(ref, _)
case _ => new ScUMethodValueLambdaExpression(mv, _)
}
// ========================= CONTROL STRUCTURES =========================
case e: ScIf => new ScUIfExpression(e, _)
case e: ScWhile => new ScUWhileExpression(e, _)
case e: ScDo => new ScUDoWhileExpression(e, _)
case e: ScTry => new ScUTryExpression(e, _)
case e: ScThrow => new ScUThrowExpression(e, _)
case e: ScReturn => new ScUReturnExpression(e, _)
case e: ScMatch => new ScUSwitchExpression(e, _)
case e: ScCaseClauses =>
e.getParent match {
case bl: ScBlock if bl.isInCatchBlock => null
case _ => new ScUCaseClausesList(e, _)
}
case e: ScCaseClause =>
if (isInsideCatchBlock(e)) new ScUCatchExpression(e, _)
else new ScUCaseClause(e, _)
case e: ScBlock if e.getParent.is[ScCaseClause] =>
e.getParent match {
case clause: ScCaseClause if !isInsideCatchBlock(clause) =>
new ScUCaseClauseBodyList(e, _)
case _ => new ScUBlockExpression(e, _)
}
// ========================= EXPRESSION GROUPS ==========================
case e: ScInfixExpr if requiredType != classOf[UCallExpression] => new ScUBinaryExpression(e, _)
case e: ScPostfixExpr if requiredType != classOf[UCallExpression] => new ScUPostfixExpression(e, _)
case e: ScBlock => new ScUBlockExpression(e, _)
case e: ScTypedExpression => new ScUBinaryExpressionWithType(e, _)
case e: ScPrefixExpr => new ScUPrefixExpression(e, _)
case e: ScParenthesisedExpr => new ScUParenthesizedExpression(e, _)
case e: ScAssignment =>
if (e.isNamedParameter) new ScUNamedExpression(e, _)
else new ScUAssignment(e, _)
// ======================== CALLS =======================================
//region Special section that converts PSI call elements to
// UAST call expressions if the required type is a call expression.
// Otherwise PSI visitor won't be able to find some UAST calls
// because they will be converted to UQualifiedExpression's
case e: ScMethodCall if requiredType == classOf[UCallExpression] =>
new ScUMethodCallExpression(e, _)
case e: ScGenericCall
if !e.getParent.is[ScMethodCall] &&
requiredType == classOf[UCallExpression] =>
new ScUGenericCallExpression(e, _)
case p@ScPostfixExpr(_, ref@ScReferenceExpression(_: PsiMethod | _: ScSyntheticFunction)) if ref.qualifier.isEmpty && requiredType == classOf[UCallExpression] =>
new ScUPostfixExpressionCall(p, _)
case i@ScInfixExpr(_, ref@ScReferenceExpression(_: PsiMethod | _: ScSyntheticFunction), _) if ref.qualifier.isEmpty && requiredType == classOf[UCallExpression] =>
new ScUBinaryExpressionCall(i, _)
case funRef: ScReferenceExpression
if !funRef.getParent.is[ScMethodCall, ScGenericCall] &&
requiredType == classOf[UCallExpression] &&
funRef.resolve().is[PsiMethod, ScSyntheticFunction] =>
functionReferenceCall(funRef, _)
//endregion
case e: ScNewTemplateDefinition =>
//noinspection ScalaUnnecessaryParentheses
e.firstConstructorInvocation
.map(c => new ScUConstructorCallExpression(c, _: LazyUElement))
.getOrElse(null)
case e: ScMethodCall =>
/** NOTE: see related code in [[org.jetbrains.plugins.scala.lang.psi.uast.expressions.ScUQualifiedReferenceExpression.getExpressionType]] */
e.getInvokedExpr match {
case ref: ScReferenceExpression if ref.isQualified =>
new ScUQualifiedReferenceExpression(ref, sourcePsi = e, _)
case gc: ScGenericCall =>
gc.referencedExpr match {
case ref: ScReferenceExpression if ref.isQualified =>
new ScUQualifiedReferenceExpression(ref, sourcePsi = e, _)
case _ =>
new ScUMethodCallExpression(e, _)
}
case _ => new ScUMethodCallExpression(e, _)
}
case e: ScGenericCall if !e.getParent.is[ScMethodCall] =>
e.referencedExpr match {
case ref: ScReferenceExpression if ref.isQualified =>
new ScUQualifiedReferenceExpression(ref, sourcePsi = e, _)
case _ =>
new ScUGenericCallExpression(e, _)
}
// ========================= REFERENCES =================================
case e: ScReferenceExpression if e.isQualified =>
e.getParent match {
case mc: ScMethodCall =>
new ScUQualifiedReferenceExpression(e, sourcePsi = mc, _)
case gc: ScGenericCall =>
gc.getParent match {
case mc: ScMethodCall =>
new ScUQualifiedReferenceExpression(e, sourcePsi = mc, _)
case _ =>
new ScUQualifiedReferenceExpression(e, sourcePsi = gc, _)
}
case _ =>
new ScUQualifiedReferenceExpression(e, _)
}
case funRef: ScReferenceExpression
if !funRef.getParent.is[ScMethodCall, ScGenericCall, ScUnderscoreSection] &&
funRef.resolve().is[PsiMethod, ScSyntheticFunction] =>
functionReferenceCall(funRef, _)
case ref @ ScUReferenceExpression(parent2ScURef) if !ref.isInstanceOf[ScTypeElement] =>
parent2ScURef(_)
case e: ScExistentialTypeElement =>
// Unsupported element type.
// Needs to be ordered before ScTypeElement because ScExistentialTypeElement <: ScTypeElement.
new UnknownScalaElement(e, _)
case e: ScTypeElement if e.getFirstChild.is[ScReference] =>
new ScUTypeReferenceExpression(
e.getFirstChild.asInstanceOf[ScReference],
typeProvider = Some(e),
sourcePsi = e,
_
)
case e: ScThisReference => new ScUThisExpression(e, _)
case e: ScSuperReference => new ScUSuperExpression(e, _)
// ========================= LEAF ELEMENTS ==============================
case e: ScLiteral => ScULiteral(e, _)
case e: ScUnderscoreSection if e.bindingExpr.isEmpty =>
new ScUUnderscoreExpression(e, _)
/**
* Some 3-rd party UAST based inspections try to
* convert [[LeafPsiElement]] representing identifier to [[UIdentifier]]
*/
case e: LeafPsiElement
if e.getElementType == ScalaTokenTypes.tIDENTIFIER =>
(_: LazyUElement) =>
new LazyAnyUParentUIdentifier(e)
// ========================= UNSUPPORTED ================================
case e: ScFor => new ScUEmptyExpressionWithGivenType(e, _)
case _ => null
}): LazyUElement => UElement)
.map(Free.fromLazyConstructor[UElement](_))
elementOpt.flatMap { element =>
element.standalone match {
case standalone: U =>
if (isUnitTestMode && !possibleSourceTypesCheckIsActive && !isPossibleToConvert(requiredType, sourcePsi)) {
throw new AssertionError(s"${requiredType.getName} is not expected from ${sourcePsi.getClass.getName}, got ${standalone.getClass.getName}")
}
Some(element.asInstanceOf[Free[U]])
case _ => None
}
}
}