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

io.joern.php2cpg.parser.ClassParser.scala Maven / Gradle / Ivy

There is a newer version: 4.0.131
Show newest version
package io.joern.php2cpg.parser
import better.files.File
import io.joern.x2cpg.utils.ExternalCommand
import org.slf4j.LoggerFactory

import scala.collection.immutable.LazyList.from
import scala.io.Source
import scala.util.{Failure, Success, Try, Using}
import upickle.default.*

import scala.collection.mutable

/** Parses the high-level symbol information of a project.
  */
class ClassParser(targetDir: File) {

  import ClassParser.*

  private val logger = LoggerFactory.getLogger(this.getClass)

  private lazy val classParserScript = {
    val f = File.newTemporaryFile("ClassParser", ".php").deleteOnExit(swallowIOExceptions = true)
    Using(Source.fromResource("ClassParser.php")) { br =>
      f.writeText(br.getLines().mkString("\n"))
    }
    f
  }

  private lazy val phpClassParseCommand: String = s"php ${classParserScript.pathAsString} ${targetDir.pathAsString}"

  def parse(): Try[List[ClassParserClass]] = Try {
    val inputDirectory = targetDir.parent.canonicalPath
    ExternalCommand.run(phpClassParseCommand, inputDirectory).map(_.reverse) match {
      case Success(output) =>
        read[List[ClassParserClass]](output.mkString("\n"))
      case Failure(exception) =>
        logger.error(s"Failure running `ClassParser.php` with $phpClassParseCommand", exception.getMessage)
        throw exception
    }
  }

}

object ClassParser {

  implicit val classParserClassRw: ReadWriter[ClassParserClass] = readwriter[ujson.Value].bimap[ClassParserClass](
    x => ujson.Null, // no serialization
    json =>
      ClassParserClass(
        name = json("name").str,
        namespace = json("namespace").str,
        relativeFile = json("file").str,
        modifiers = json.obj.get("modifiers").map(read[List[String]](_)).getOrElse(Nil),
        functions = json.obj.get("functions") match {
          case Some(jsonFuncs) =>
            val functionMap = read[mutable.Map[String, ClassParserFunction]](jsonFuncs)
            if (!functionMap.contains("__construct")) {
              functionMap.put("__construct", ClassParserFunction("", "public" :: Nil))
            }
            functionMap.map { case (name, func) =>
              func.copy(name = name)
            }.toList
          case None => Nil
        }
      )
  )

  case class ClassParserClass(
    name: String,
    namespace: String,
    relativeFile: String,
    modifiers: List[String],
    functions: List[ClassParserFunction]
  )

  case class ClassParserFunction(name: String = "", modifiers: List[String]) derives ReadWriter

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy