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

io.joern.x2cpg.frontendspecific.php2cpg.ComposerAutoloadPass.scala Maven / Gradle / Ivy

There is a newer version: 4.0.131
Show newest version
package io.joern.x2cpg.frontendspecific.php2cpg

import io.joern.x2cpg.{Defines, X2Cpg}
import io.shiftleft.codepropertygraph.generated.{Cpg, PropertyNames}
import io.shiftleft.codepropertygraph.generated.nodes.{Call, Identifier, Method, TypeDecl}
import io.shiftleft.passes.ForkJoinParallelCpgPass
import io.shiftleft.semanticcpg.language.*

import scala.collection.mutable

/** Composer's autoload feature implicitly brings in dependencies into a file. This pass will detect such imports and
  * fully qualify type names referencing non-stub types. This pass also considers types brought in by the dependency
  * downloader.
  */
class ComposerAutoloadPass(cpg: Cpg) extends ForkJoinParallelCpgPass[Method](cpg) {

  private val typeMap   = mutable.Map.empty[String, String]
  private val methodMap = mutable.Map.empty[String, String]

  override def init(): Unit = {
    cpg.typeDecl.filter(x => x.name != x.fullName && x.isExternal).foreach { t =>
      typeMap.put(t.name, t.fullName)
      t.method.foreach { m =>
        methodMap.put(s"${t.name}->${m.name}", m.fullName)
      }
    }
  }

  private def isAutoloaded(method: Method) = method._containsOut
    .collect { case x: Call if x.name == "require" => x }
    .flatMap(_.argument.code)
    .map(X2Cpg.stripQuotes)
    .contains("vendor/autoload.php")

  /** Collects methods within a module.
    */
  private def findMethods(module: Method): Iterator[Method] = {
    Iterator(module) ++ module.containsOut.flatMap {
      case x: TypeDecl => x.method.flatMap(findMethods)
      case x: Method   => Iterator(x) ++ x.containsOut.collectAll[Method].flatMap(findMethods)
      case _           => Iterator.empty
    }
  }

  override def generateParts(): Array[Method] =
    cpg.method.isModule.filter(isAutoloaded).flatMap(findMethods).toArray

  override def runOnPart(builder: DiffGraphBuilder, part: Method): Unit = {
    part._containsOut.foreach {
      case call: Call             => fullyQualifyCall(call, builder)
      case identifier: Identifier => fullyQualifyIdentifier(identifier, builder)
      case _                      =>
    }
  }

  private def fullyQualifyCall(call: Call, builder: DiffGraphBuilder): Unit = {
    if (call.typeFullName != Defines.Any) {
      typeMap.get(call.typeFullName).foreach(builder.setNodeProperty(call, PropertyNames.TYPE_FULL_NAME, _))
    }
    methodMap.get(call.methodFullName).foreach(builder.setNodeProperty(call, PropertyNames.METHOD_FULL_NAME, _))
  }

  private def fullyQualifyIdentifier(identifier: Identifier, builder: DiffGraphBuilder): Unit = {
    if (identifier.typeFullName != Defines.Any) {
      typeMap.get(identifier.typeFullName).foreach(builder.setNodeProperty(identifier, PropertyNames.TYPE_FULL_NAME, _))
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy