Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.nawforce.pkgforce.parsers.ApexClassVisitor.scala Maven / Gradle / Ivy
/*
Copyright (c) 2020 Kevin Jones, All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/
package com.nawforce.pkgforce.parsers
import com.nawforce.pkgforce.modifiers._
import com.nawforce.pkgforce.names.Name
import com.nawforce.runtime.parsers.CodeParser.ParserRuleContext
import com.nawforce.runtime.parsers.{CodeParser, TreeVisitor}
import io.github.apexdevtools.apexparser.ApexParser._
import scala.collection.immutable.ArraySeq
import scala.collection.mutable
class ApexClassVisitor(parser: CodeParser) extends TreeVisitor[ApexNode] {
private val ownerNatureStack = mutable.Stack[MethodOwnerNature]()
def typeWrap[T](ownerNature: MethodOwnerNature)(op: => T): T = {
ownerNatureStack.push(ownerNature)
try {
op
} finally {
ownerNatureStack.pop()
}
}
override def classDeclaration(
ctx: ClassDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val isOuter = ownerNatureStack.isEmpty
val modifierContext = getModifierContext(parentContext(ctx))
val classModifiers =
ApexModifiers.classModifiers(parser, modifierContext.modifiers, isOuter, ctx.id())
val extendsType = CodeParser
.toScala(ctx.typeRef())
.map(typeRef =>
ExtendsType(Name(CodeParser.getText(typeRef)), parser.getPathLocation(typeRef).location)
)
typeWrap(classModifiers.methodOwnerNature) {
ArraySeq(
new ApexLightNode(
parser.getPathLocation(parentContext(ctx)),
CLASS_NATURE,
Name(CodeParser.getText(ctx.id())),
parser.getPathLocation(ctx.id()).location,
extendsType,
visitChildren(ctx),
classModifiers.modifiers,
s"${classModifiers.modifiers.mkString(" ")} class ${CodeParser.getText(ctx.id())}",
classModifiers.modifiers.mkString(" "),
classModifiers.issues
)
)
}
}
override def triggerDeclaration(
ctx: TriggerUnitContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val ids = CodeParser.toScala(ctx.id())
ArraySeq(
new ApexLightNode(
parser.getPathLocation(ctx),
TRIGGER_NATURE,
Name(CodeParser.getText(ids.head)),
parser.getPathLocation(ids.head).location,
None,
visitChildren(ctx),
ArraySeq(),
s"trigger ${CodeParser.getText(ids.head)} on ${CodeParser.getText(ids.tail.head)}",
"",
ArraySeq()
)
)
}
override def interfaceDeclaration(
ctx: InterfaceDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val isOuter = ownerNatureStack.isEmpty
typeWrap(INTERFACE_METHOD_NATURE) {
val modifierContext = getModifierContext(parentContext(ctx))
val modifiers =
ApexModifiers.interfaceModifiers(parser, modifierContext.modifiers, isOuter, ctx.id())
ArraySeq(
new ApexLightNode(
parser.getPathLocation(parentContext(ctx)),
INTERFACE_NATURE,
Name(CodeParser.getText(ctx.id())),
parser.getPathLocation(ctx.id()).location,
None,
visitChildren(ctx),
modifiers.modifiers,
s"${modifiers.modifiers.mkString(" ")} interface ${CodeParser.getText(ctx.id())}",
modifiers.modifiers.mkString(" "),
modifiers.issues
)
)
}
}
override def enumDeclaration(
ctx: EnumDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val isOuter = ownerNatureStack.isEmpty
typeWrap(ENUM_METHOD_NATURE) {
val modifierContext = getModifierContext(parentContext(ctx))
val modifiers =
ApexModifiers.enumModifiers(parser, modifierContext.modifiers, isOuter, ctx.id())
ArraySeq(
new ApexLightNode(
parser.getPathLocation(parentContext(ctx)),
ENUM_NATURE,
Name(CodeParser.getText(ctx.id())),
parser.getPathLocation(ctx.id()).location,
None,
visitChildren(ctx),
modifiers.modifiers,
s"${modifiers.modifiers.mkString(" ")} enum ${CodeParser.getText(ctx.id())}",
modifiers.modifiers.mkString(" "),
modifiers.issues
)
)
}
}
override def constructorDeclaration(
ctx: ConstructorDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val modifierContext = classBodyModifierContext(parentContext(parentContext(ctx)))
val modifiers =
ApexModifiers.constructorModifiers(parser, modifierContext.modifiers, ctx.qualifiedName())
ArraySeq(
ApexConstructorNode(
parser.getPathLocation(parentContext(parentContext(ctx))),
Name(CodeParser.getText(ctx.qualifiedName())),
parser.getPathLocation(ctx.qualifiedName()).location,
ArraySeq(),
modifiers.modifiers,
modifiers.issues,
formatFormalParameters(ctx.formalParameters())
)
)
}
override def methodDeclaration(
ctx: MethodDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val modifierContext = classBodyModifierContext(parentContext(parentContext(ctx)))
val modifiers = MethodModifiers.classMethodModifiers(
parser,
modifierContext.modifiers,
ctx.id(),
ownerNatureStack.head,
ownerNatureStack.size == 1
)
ArraySeq(
ApexMethodNode(
parser.getPathLocation(parentContext(parentContext(ctx))),
Name(CodeParser.getText(ctx.id())),
parser.getPathLocation(ctx.id()).location,
ArraySeq(),
modifiers.modifiers,
modifiers.issues,
CodeParser.toScala(ctx.typeRef()).map(CodeParser.getText).getOrElse("void"),
formatFormalParameters(ctx.formalParameters())
)
)
}
override def interfaceMethodDeclaration(
ctx: InterfaceMethodDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val modifiers =
MethodModifiers.interfaceMethodModifiers(
parser,
ArraySeq.from(CodeParser.toScala(ctx.modifier())),
ctx.id(),
ownerNatureStack.size == 1
)
ArraySeq(
ApexMethodNode(
parser.getPathLocation(ctx),
Name(CodeParser.getText(ctx.id())),
parser.getPathLocation(ctx.id()).location,
ArraySeq(),
modifiers.modifiers,
modifiers.issues,
CodeParser.toScala(ctx.typeRef()).map(CodeParser.getText).getOrElse("void"),
formatFormalParameters(ctx.formalParameters())
)
)
}
private def formatFormalParameters(
ctx: FormalParametersContext
): ArraySeq[ApexFormalParameter] = {
val params = CodeParser
.toScala(ctx.formalParameterList())
.toSeq
.flatMap(f => CodeParser.toScala(f.formalParameter()))
ArraySeq.unsafeWrapArray(
params
.map(fp => {
val modifiers = ApexModifiers.parameterModifiers(
parser,
ArraySeq.unsafeWrapArray(CodeParser.toScala(fp.modifier()).toArray),
fp
)
ApexFormalParameter(
modifiers.modifiers,
CodeParser.getText(fp.typeRef()),
CodeParser.getText(fp.id()),
modifiers.issues
)
})
.toArray
)
}
override def fieldDeclaration(
ctx: FieldDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val modifierContext = classBodyModifierContext(parentContext(parentContext(ctx)))
val fieldType = CodeParser.getText(ctx.typeRef())
val variableDeclarators = CodeParser.toScala(ctx.variableDeclarators().variableDeclarator())
val modifiers = FieldModifiers.fieldModifiers(
parser,
modifierContext.modifiers,
ownerNatureStack.size == 1,
variableDeclarators.head.id()
)
if (variableDeclarators.size == 1) {
val vd = variableDeclarators.head
ArraySeq(
new ApexLightNode(
parser.getPathLocation(modifierContext.enclosing),
FIELD_NATURE,
Name(CodeParser.getText(vd.id())),
parser.getPathLocation(vd.id()).location,
None,
ArraySeq(),
modifiers.modifiers,
s"${appendSpace(modifiers.modifiers.mkString(" "))}$fieldType ${CodeParser
.getText(vd.id())}",
s"$fieldType ${modifiers.modifiers.mkString(" ")}",
modifiers.issues
)
)
} else {
ArraySeq.from(variableDeclarators.map(vd => {
new ApexLightNode(
parser.getPathLocation(vd),
FIELD_NATURE,
Name(CodeParser.getText(vd.id())),
parser.getPathLocation(vd.id()).location,
None,
ArraySeq(),
modifiers.modifiers,
s"${appendSpace(modifiers.modifiers.mkString(" "))}$fieldType ${CodeParser
.getText(vd.id())}",
s"$fieldType ${modifiers.modifiers.mkString(" ")}",
modifiers.issues
)
}))
}
}
override def propertyDeclaration(
ctx: PropertyDeclarationContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
val modifierContext = classBodyModifierContext(parentContext(parentContext(ctx)))
val modifiers =
FieldModifiers.fieldModifiers(
parser,
modifierContext.modifiers,
ownerNatureStack.size == 1,
ctx.id()
)
val fieldType = CodeParser.getText(ctx.typeRef())
ArraySeq(
new ApexLightNode(
parser.getPathLocation(modifierContext.enclosing),
PROPERTY_NATURE,
Name(CodeParser.getText(ctx.id())),
parser.getPathLocation(ctx.id()).location,
None,
ArraySeq(),
modifiers.modifiers,
s"${appendSpace(modifiers.modifiers.mkString(" "))}$fieldType ${CodeParser
.getText(ctx.id())}",
s"$fieldType ${modifiers.modifiers.mkString(" ")}",
modifiers.issues
)
)
}
override def enumConstants(
ctx: EnumConstantsContext,
visitChildren: VisitChildren
): ArraySeq[ApexNode] = {
ArraySeq.from(
CodeParser
.toScala(ctx.id())
.map(id => {
val constantName = CodeParser.getText(id)
new ApexLightNode(
parser.getPathLocation(id),
ENUM_CONSTANT_NATURE,
Name(CodeParser.getText(id)),
parser.getPathLocation(id).location,
None,
ArraySeq.empty,
ArraySeq.empty,
constantName,
constantName,
ArraySeq.empty
)
})
)
}
private def parentContext[T](ctx: ParserRuleContext): T = {
ctx.parent.asInstanceOf[T]
}
case class ModifierContextDetails(
enclosing: ParserRuleContext,
modifiers: ArraySeq[ModifierContext]
)
private def getModifierContext(ctx: ParserRuleContext): ModifierContextDetails = {
ctx match {
case td: TypeDeclarationContext =>
ModifierContextDetails(td, ArraySeq.from(CodeParser.toScala(td.modifier())))
case _ =>
classBodyModifierContext(parentContext(ctx))
}
}
private def classBodyModifierContext(ctx: ClassBodyDeclarationContext): ModifierContextDetails = {
ModifierContextDetails(ctx, ArraySeq.from(CodeParser.toScala(ctx.modifier())))
}
private def appendSpace(str: String): String = {
if (str.nonEmpty)
str + " "
else
str
}
}