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

io.joern.rubysrc2cpg.deprecated.passes.RubyImportResolverPass.scala Maven / Gradle / Ivy

package io.joern.rubysrc2cpg.deprecated.passes

import better.files.File
import io.joern.rubysrc2cpg.deprecated.utils.PackageTable
import io.joern.x2cpg.Defines as XDefines
import io.shiftleft.semanticcpg.language.importresolver.*
import io.joern.x2cpg.passes.frontend.XImportResolverPass
import io.shiftleft.codepropertygraph.generated.Cpg
import io.shiftleft.codepropertygraph.generated.nodes.Call
import io.shiftleft.semanticcpg.language.*

import java.io.File as JFile
import java.util.regex.{Matcher, Pattern}
class RubyImportResolverPass(cpg: Cpg, packageTableInfo: PackageTable) extends XImportResolverPass(cpg) {

  private val pathPattern = Pattern.compile("[\"']([\\w/.]+)[\"']")

  override protected def optionalResolveImport(
    fileName: String,
    importCall: Call,
    importedEntity: String,
    importedAs: String,
    diffGraph: DiffGraphBuilder
  ): Unit = {

    resolveEntities(importedEntity, importCall, fileName).foreach(x => evaluatedImportToTag(x, importCall, diffGraph))
  }

  private def resolveEntities(expEntity: String, importCall: Call, fileName: String): Set[EvaluatedImport] = {

    // TODO
    /* Currently we are considering only case where exposed module are Classes,
    and the only way to consume them is by creating a new object as we encounter more cases,
     This needs to be handled accordingly
     */

    val expResolvedPath =
      if (packageTableInfo.getModule(expEntity).nonEmpty || packageTableInfo.getTypeDecl(expEntity).nonEmpty)
        expEntity
      else if (expEntity.contains("."))
        getResolvedPath(expEntity, fileName)
      else if (cpg.file.name(s".*$expEntity.rb").nonEmpty)
        getResolvedPath(s"$expEntity.rb", fileName)
      else
        expEntity

    // TODO Limited ResolvedMethod exposure for now, will open up after looking at more concrete examples
    val finalResolved = {
      if (
        packageTableInfo.getModule(expResolvedPath).nonEmpty || packageTableInfo.getTypeDecl(expResolvedPath).nonEmpty
      ) {
        val importNodesFromTypeDecl = packageTableInfo
          .getTypeDecl(expEntity)
          .flatMap { typeDeclModel =>
            Seq(
              ResolvedMethod(s"${typeDeclModel.fullName}.${XDefines.ConstructorMethodName}", "new"),
              ResolvedTypeDecl(typeDeclModel.fullName)
            )
          }
          .distinct

        val importNodesFromModule = packageTableInfo.getModule(expEntity).flatMap { moduleModel =>
          Seq(ResolvedTypeDecl(moduleModel.fullName))
        }
        (importNodesFromTypeDecl ++ importNodesFromModule).toSet
      } else {
        val filePattern = s"${Pattern.quote(expResolvedPath)}\\.?.*"
        val resolvedTypeDecls = cpg.typeDecl
          .where(_.file.name(filePattern))
          .fullName
          .flatMap(fullName =>
            Seq(ResolvedTypeDecl(fullName), ResolvedMethod(s"$fullName.${XDefines.ConstructorMethodName}", "new"))
          )
          .toSet

        val resolvedModules = cpg.namespaceBlock
          .whereNot(_.nameExact(""))
          .where(_.file.name(filePattern))
          .flatMap(module => Seq(ResolvedTypeDecl(module.fullName)))
          .toSet

        // Expose methods which are directly present in a file, without any module, TypeDecl
        val resolvedMethods = cpg.method
          .where(_.file.name(filePattern))
          .where(_.nameExact(":program"))
          .astChildren
          .astChildren
          .isMethod
          .flatMap(method => Seq(ResolvedMethod(method.fullName, method.name)))
          .toSet
        resolvedTypeDecls ++ resolvedModules ++ resolvedMethods
      }
    }.collectAll[EvaluatedImport].toSet

    finalResolved
  }

  def getResolvedPath(expEntity: String, fileName: String) = {
    val rawEntity   = expEntity.stripPrefix("./")
    val matcher     = pathPattern.matcher(rawEntity)
    val sep         = Matcher.quoteReplacement(JFile.separator)
    val root        = s"$codeRootDir${JFile.separator}"
    val currentFile = s"$root$fileName"
    val entity      = if (matcher.find()) matcher.group(1) else rawEntity
    val resolvedPath = better.files
      .File(
        currentFile.stripSuffix(currentFile.split(sep).lastOption.getOrElse("")),
        entity.split("\\.").headOption.getOrElse(entity)
      )
      .pathAsString match {
      case resPath if entity.endsWith(".rb") => s"$resPath.rb"
      case resPath                           => resPath
    }
    resolvedPath.stripPrefix(root)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy