Skip to content

Commit

Permalink
[ruby] Move Post-Processing to x2cpg (#4851)
Browse files Browse the repository at this point in the history
Following the other frontends, migrates the non-deprecated post-processing passes to `x2cpg`
  • Loading branch information
DavidBakerEffendi authored Aug 15, 2024
1 parent ca4c172 commit e967d4c
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import io.joern.rubysrc2cpg.passes.{
AstCreationPass,
ConfigFileCreationPass,
DependencyPass,
DependencySummarySolverPass,
DependencySummarySolverPass
}
import io.joern.rubysrc2cpg.utils.DependencyDownloader
import io.joern.x2cpg.X2Cpg.withNewEmptyCpg
import io.joern.x2cpg.frontendspecific.rubysrc2cpg.{
ImplicitRequirePass,
ImportsPass,
RubyImportResolverPass,
RubyTypeHintCallLinker
RubyTypeHintCallLinker,
RubyTypeRecoveryPassGenerator
}
import io.joern.rubysrc2cpg.utils.DependencyDownloader
import io.joern.x2cpg.X2Cpg.withNewEmptyCpg
import io.joern.x2cpg.passes.base.AstLinkerPass
import io.joern.x2cpg.passes.callgraph.NaiveCallLinker
import io.joern.x2cpg.passes.frontend.{MetaDataPass, TypeNodePass, XTypeRecoveryConfig}
Expand Down Expand Up @@ -175,7 +178,7 @@ object RubySrc2Cpg {
} else {
val implicitRequirePass = if (cpg.dependency.name.contains("zeitwerk")) ImplicitRequirePass(cpg) :: Nil else Nil
implicitRequirePass ++ List(ImportsPass(cpg), RubyImportResolverPass(cpg)) ++
new passes.RubyTypeRecoveryPassGenerator(cpg, config = XTypeRecoveryConfig(iterations = 4))
new RubyTypeRecoveryPassGenerator(cpg, config = XTypeRecoveryConfig(iterations = 4))
.generate() ++ List(new RubyTypeHintCallLinker(cpg), new NaiveCallLinker(cpg), new AstLinkerPass(cpg))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package io.joern.x2cpg.frontendspecific.rubysrc2cpg

object Constants {

val builtinPrefix = "__core"
val kernelPrefix = s"$builtinPrefix.Kernel"
val Initialize = "initialize"
val Main = "<main>"

/* Source: https://ruby-doc.org/3.2.2/Kernel.html
*
* We comment-out methods that require an explicit "receiver" (target of member access.)
*/
val kernelFunctions: Set[String] = Set(
"Array",
"Complex",
"Float",
"Hash",
"Integer",
"Rational",
"String",
"__callee__",
"__dir__",
"__method__",
"abort",
"at_exit",
"autoload",
"autoload?",
"binding",
"block_given?",
"callcc",
"caller",
"caller_locations",
"catch",
"chomp",
"chomp!",
"chop",
"chop!",
// "class",
// "clone",
"eval",
"exec",
"exit",
"exit!",
"fail",
"fork",
"format",
// "frozen?",
"gets",
"global_variables",
"gsub",
"gsub!",
"iterator?",
"lambda",
"load",
"local_variables",
"loop",
"open",
"p",
"print",
"printf",
"proc",
"putc",
"puts",
"raise",
"rand",
"readline",
"readlines",
"require",
"require_all",
"require_relative",
"select",
"set_trace_func",
"sleep",
"spawn",
"sprintf",
"srand",
"sub",
"sub!",
"syscall",
"system",
"tap",
"test",
// "then",
"throw",
"trace_var",
// "trap",
"untrace_var",
"warn"
// "yield_self",
)

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.joern.rubysrc2cpg.passes
package io.joern.x2cpg.frontendspecific.rubysrc2cpg

import io.joern.rubysrc2cpg.passes.GlobalTypes.{builtinPrefix, kernelPrefix}
import io.joern.x2cpg.Defines
import io.joern.x2cpg.frontendspecific.rubysrc2cpg.Constants.*
import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.codepropertygraph.generated.{Cpg, DispatchTypes, EdgeTypes, Operators}
import io.shiftleft.passes.ForkJoinParallelCpgPass
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.joern.rubysrc2cpg.passes
package io.joern.x2cpg.frontendspecific.rubysrc2cpg

import io.joern.x2cpg.Imports.createImportNodeAndLink
import io.joern.x2cpg.X2Cpg.stripQuotes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package io.joern.rubysrc2cpg.passes
package io.joern.x2cpg.frontendspecific.rubysrc2cpg

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.frontendspecific.rubysrc2cpg.Constants.*
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 io.joern.rubysrc2cpg.passes.Defines as RDefines
import io.shiftleft.semanticcpg.language.importresolver.*
import io.shiftleft.semanticcpg.language.types.structure.NamespaceTraversal

import java.io.File as JFile
Expand Down Expand Up @@ -47,7 +45,7 @@ class RubyImportResolverPass(cpg: Cpg) extends XImportResolverPass(cpg) {
.flatMap(fullName =>
Seq(
ResolvedTypeDecl(fullName),
ResolvedMethod(s"$fullName.${Defines.Initialize}", "new", fullName.split("[.]").lastOption)
ResolvedMethod(s"$fullName.${Initialize}", "new", fullName.split("[.]").lastOption)
)
)
.toSet
Expand All @@ -61,7 +59,7 @@ class RubyImportResolverPass(cpg: Cpg) extends XImportResolverPass(cpg) {
// Expose methods which are directly present in a file, without any module, TypeDecl
val resolvedMethods = cpg.method
.where(_.file.name(filePattern))
.where(_.nameExact(RDefines.Main))
.where(_.nameExact(Main))
.astChildren
.astChildren
.isMethod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.joern.rubysrc2cpg.passes
package io.joern.x2cpg.frontendspecific.rubysrc2cpg

import io.joern.x2cpg.passes.frontend.XTypeHintCallLinker
import io.joern.x2cpg.frontendspecific.rubysrc2cpg.Constants.*
import io.shiftleft.codepropertygraph.generated.Cpg
import io.shiftleft.codepropertygraph.generated.nodes.{Call, NewMethod}
import io.shiftleft.semanticcpg.language.*
Expand All @@ -26,8 +27,8 @@ class RubyTypeHintCallLinker(cpg: Cpg) extends XTypeHintCallLinker(cpg) {
}
val name =
if (methodName.contains(pathSep) && methodName.length > methodName.lastIndexOf(pathSep) + 1)
val strippedMethod = methodName.stripPrefix(s"${GlobalTypes.kernelPrefix}.")
if GlobalTypes.kernelFunctions.contains(strippedMethod) then strippedMethod
val strippedMethod = methodName.stripPrefix(s"$kernelPrefix.")
if kernelFunctions.contains(strippedMethod) then strippedMethod
else methodName.substring(methodName.lastIndexOf(pathSep) + pathSep.length)
else methodName
createMethodStub(name, methodName, call.argumentOut.size, isExternal, builder)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package io.joern.rubysrc2cpg.passes
package io.joern.x2cpg.frontendspecific.rubysrc2cpg

import io.joern.x2cpg.Defines as XDefines
import io.joern.x2cpg.frontendspecific.rubysrc2cpg.Constants.*
import io.joern.x2cpg.passes.frontend.*
import io.joern.x2cpg.passes.frontend.XTypeRecovery.AllNodeTypesFromNodeExt
import io.shiftleft.codepropertygraph.generated.{Cpg, Operators, PropertyNames}
import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.semanticcpg.language.operatorextension.OpNodes.FieldAccess
import io.shiftleft.codepropertygraph.generated.{Cpg, DiffGraphBuilder, Operators, PropertyNames}
import io.shiftleft.semanticcpg.language.*
import io.shiftleft.codepropertygraph.generated.DiffGraphBuilder
import io.shiftleft.semanticcpg.language.operatorextension.OpNodes.FieldAccess

class RubyTypeRecoveryPassGenerator(cpg: Cpg, config: XTypeRecoveryConfig = XTypeRecoveryConfig())
extends XTypeRecoveryPassGenerator[File](cpg, config) {
Expand Down Expand Up @@ -40,7 +40,7 @@ private class RecoverForRubyFile(cpg: Cpg, cu: File, builder: DiffGraphBuilder,
/** A heuristic method to determine if a call name is a constructor or not.
*/
override protected def isConstructor(name: String): Boolean =
!name.isBlank && (name == "new" || name == Defines.Initialize)
!name.isBlank && (name == "new" || name == Initialize)

override protected def hasTypes(node: AstNode): Boolean = node match {
case x: Call if !x.methodFullName.startsWith("<operator>") =>
Expand Down

0 comments on commit e967d4c

Please sign in to comment.