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

io.shiftleft.semanticcpg.language.modulevariable.ModuleVariableTraversal.scala Maven / Gradle / Ivy

There is a newer version: 4.0.77
Show newest version
package io.shiftleft.semanticcpg.language.modulevariable

import io.shiftleft.codepropertygraph.generated.help.{Doc, Traversal}
import io.shiftleft.codepropertygraph.generated.Cpg
import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.semanticcpg.language.*
import io.shiftleft.semanticcpg.language.operatorextension.OpNodes.Assignment
import io.shiftleft.codepropertygraph.generated.help.Doc

@Traversal(elementType = classOf[Local])
class ModuleVariableTraversal(traversal: Iterator[OpNodes.ModuleVariable]) extends AnyVal {

  @Doc(info = "All assignments where the module variables in this traversal are the target across the program")
  def definitions: Iterator[Assignment] = traversal.references.flatMap {
    case x: Identifier      => x.start.inAssignment.filter(_.target == x)
    case x: FieldIdentifier => x.inAssignment.filter(_.target.contains(x.inFieldAccess))
  }

  @Doc(info = "Calls this module variable invokes across the program")
  def invokingCalls: Iterator[Call] =
    traversal.references
      .flatMap {
        case x: Identifier      => x :: Nil
        case x: FieldIdentifier => x.fieldAccess
      }
      .argumentIndexLte(1)
      .inCall
      .dedup
      .iterator

  @Doc(info =
    "References of this module variable across the codebase, as either identifiers or field identifiers, depending on" +
      " how the variable was imported"
  )
  def references: Iterator[Identifier | FieldIdentifier] = {
    val variables = traversal.toList
    variables.headOption.map(node => Cpg(node.graph)) match
      case Some(cpg) =>
        val modules       = cpg.method.isModule.l
        val variableNames = variables.name.toSet
        val immediateRef  = variables.referencingIdentifiers
        val externalRefs = modules.call
          .where(_.referencedImports)
          .flatMap { call =>
            val module = call.method
            call.referencedImports
              .flatMap(extractAliasNodePair)
              .filter {
                case (_, node: Member)   => variableNames.contains(node.name)
                case (_, node: TypeDecl) => node.member.name.exists(variableNames.contains)
                case _                   => false
              }
              .flatMap { case (alias, _) =>
                module.local.nameExact(alias).referencingIdentifiers ++
                  module.fieldAccess.fieldIdentifier.canonicalNameExact(alias)
              }
          }
        (immediateRef ++ externalRefs).collectAll[Identifier | FieldIdentifier]
      case None => Iterator.empty
  }

  private def extractAliasNodePair(i: Import): Seq[(String, AstNode)] = {
    i.importedAs
      .map { alias =>
        i.call.tag.resolvedEntity
          .flatMap {
            case m: Member   => (alias -> m) :: Nil
            case t: TypeDecl => (alias -> t) :: Nil
            case m: Method   => (alias -> m) :: Nil
            case _           => Nil
          }
          .distinct
          .toSeq
      }
      .getOrElse(Seq.empty)
  }

  @Doc(info = "The referencing member nodes of these module variables.")
  def referencingMembers: Iterator[Member] = {
    val variables          = traversal.toList
    lazy val moduleNames   = variables.method.isModule.fullName.dedup.toSeq
    lazy val variableNames = variables.name.toSeq
    variables.headOption.map(node => Cpg(node.graph)) match
      case Some(cpg) => cpg.typeDecl.fullNameExact(moduleNames*).member.nameExact(variableNames*)
      case None      => Iterator.empty
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy