All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.shiftleft.semanticcpg.language.LocationCreator.scala Maven / Gradle / Ivy

package io.shiftleft.semanticcpg.language

import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.semanticcpg.language.*
import org.slf4j.{Logger, LoggerFactory}

import scala.annotation.tailrec

/* TODO MP: this should be part of the normal steps, rather than matching on the type at runtime
 * all (and only) steps extending DataFlowObject should/must have `newSink`, `newSource` and `newLocation` */
object LocationCreator {

  private val logger: Logger = LoggerFactory.getLogger(getClass)

  def apply(node: StoredNode)(implicit finder: NodeExtensionFinder): NewLocation = {
    try {
      location(node)
    } catch {
      case exc @ (_: NoSuchElementException | _: ClassCastException) =>
        logger.error(s"Cannot determine location for ${node.label} due to broken CPG", exc)
        emptyLocation(node.label, Some(node))
    }
  }

  private def location(node: StoredNode)(implicit finder: NodeExtensionFinder): NewLocation = {
    finder(node) match {
      case Some(n: HasLocation) => n.location
      case _                    => LocationCreator.emptyLocation("", None)
    }
  }

  def apply(node: StoredNode, symbol: String, label: String, lineNumber: Option[Int], method: Method): NewLocation = {

    if (method == null) {
      NewLocation().node(node)
    } else {
      val typeOption    = methodToTypeDecl(method)
      val typeName      = typeOption.map(_.fullName).getOrElse("")
      val typeShortName = typeOption.map(_.name).getOrElse("")

      val namespaceOption = for {
        tpe            <- typeOption
        namespaceBlock <- tpe.namespaceBlock
        namespace      <- namespaceBlock._namespaceViaRefOut.nextOption()
      } yield namespace.name
      val namespaceName = namespaceOption.getOrElse("")

      NewLocation()
        .symbol(symbol)
        .methodFullName(method.fullName)
        .methodShortName(method.name)
        .packageName(namespaceName)
        .lineNumber(lineNumber)
        .className(typeName)
        .classShortName(typeShortName)
        .nodeLabel(label)
        .filename(if (method.filename.isEmpty) "N/A" else method.filename)
        .node(node)
    }
  }

  private def methodToTypeDecl(method: Method): Option[TypeDecl] =
    findVertex(method, _.isInstanceOf[TypeDecl]).map(_.asInstanceOf[TypeDecl])

  @tailrec
  private def findVertex(node: StoredNode, instanceCheck: StoredNode => Boolean): Option[StoredNode] =
    node._astIn.iterator.nextOption() match {
      case Some(head) if instanceCheck(head) => Some(head)
      case Some(head)                        => findVertex(head, instanceCheck)
      case None                              => None
    }

  def emptyLocation(label: String, node: Option[StoredNode]): NewLocation =
    NewLocation().nodeLabel(label).node(node)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy