Repository: joernio/joern (scala)

Issue:
jimple2cpg: Add LineNumberEnd to Method Nodes
Simply use the length of the Jimple method body for this.

Pull request description:
- `java.lang.Object` only added if supers list is empty
- Added `lineNumberEnd` to `Method` nodes

Resolves #1149

Patch:
diff --git a/joern-cli/frontends/jimple2cpg/src/main/scala/io/joern/jimple2cpg/passes/AstCreator.scala b/joern-cli/frontends/jimple2cpg/src/main/scala/io/joern/jimple2cpg/passes/AstCreator.scala
index 257116fa15ed..403c4debaac5 100644
--- a/joern-cli/frontends/jimple2cpg/src/main/scala/io/joern/jimple2cpg/passes/AstCreator.scala
+++ b/joern-cli/frontends/jimple2cpg/src/main/scala/io/joern/jimple2cpg/passes/AstCreator.scala
@@ -73,12 +73,17 @@ class AstCreator(filename: String, diffGraph: DiffGraphBuilder, global: Global)
         if (!relatedClass.getSuperclass.isApplicationClass)
           registerType(relatedClass.getSuperclass.getType.toQuotedString)
         List(relatedClass.getSuperclass.toString)
-      } else List(registerType("java.lang.Object"))
+      } else List()
     val implementsTypeFullName = relatedClass.getInterfaces.asScala.map { (i: SootClass) =>
       if (!i.isApplicationClass)
         registerType(i.getType.toQuotedString)
       i.getType.toQuotedString
     }.toList
+    val allSupers =
+      if (inheritsFromTypeFullName.isEmpty && implementsTypeFullName.isEmpty)
+        List(registerType("java.lang.Object"))
+      else
+        inheritsFromTypeFullName ++ implementsTypeFullName
 
     val typeDecl = NewTypeDecl()
       .name(shortName)
@@ -86,7 +91,7 @@ class AstCreator(filename: String, diffGraph: DiffGraphBuilder, global: Global)
       .order(1) // Jimple always has 1 class per file
       .filename(filename)
       .code(shortName)
-      .inheritsFromTypeFullName(inheritsFromTypeFullName ++ implementsTypeFullName)
+      .inheritsFromTypeFullName(allSupers)
       .astParentType(NodeTypes.NAMESPACE_BLOCK)
       .astParentFullName(namespaceBlockFullName)
     val methodAsts = withOrder(typ.getSootClass.getMethods.asScala.toList.sortWith((x, y) => x.getName > y.getName)) {
@@ -137,8 +142,7 @@ class AstCreator(filename: String, diffGraph: DiffGraphBuilder, global: Global)
             (p, order) =>
               astForParameter(p, order, methodDeclaration)
           }
-
-        Ast(methodNode)
+        Ast(methodNode.lineNumberEnd(methodBody.toString.split('\n').filterNot(_.isBlank).length))
           .withChildren(astsForModifiers(methodDeclaration))
           .withChildren(parameterAsts)
           .withChild(astForMethodBody(methodBody, lastOrder))
@@ -208,7 +212,6 @@ class AstCreator(filename: String, diffGraph: DiffGraphBuilder, global: Global)
   private def astsForStatement(statement: soot.Unit, order: Int): Seq[Ast] = {
     val stmt = statement match {
       case x: AssignStmt       => astsForDefinition(x, order)
-      case _: IdentityStmt     => Seq() // Identity statements redefine parameters as locals
       case x: InvokeStmt       => astsForExpression(x.getInvokeExpr, order, statement)
       case x: ReturnStmt       => astsForReturnNode(x, order)
       case x: ReturnVoidStmt   => astsForReturnVoidNode(x, order)
@@ -218,6 +221,8 @@ class AstCreator(filename: String, diffGraph: DiffGraphBuilder, global: Global)
       case x: TableSwitchStmt  => astsForTableSwitchStmt(x, order)
       case x: ThrowStmt        => Seq(astForUnknownStmt(x, x.getOp, order))
       case x: MonitorStmt      => Seq(astForUnknownStmt(x, x.getOp, order))
+      case _: IdentityStmt     => Seq() // Identity statements redefine parameters as locals
+      case _: NopStmt          => Seq() // Ignore NOP statements
       case x =>
         logger.warn(s"Unhandled soot.Unit type ${x.getClass}")
         Seq()


Test patch:
diff --git a/joern-cli/frontends/jimple2cpg/src/test/scala/io/joern/jimple2cpg/querying/MethodTests.scala b/joern-cli/frontends/jimple2cpg/src/test/scala/io/joern/jimple2cpg/querying/MethodTests.scala
index 9622cf972708..c5594680da3d 100644
--- a/joern-cli/frontends/jimple2cpg/src/test/scala/io/joern/jimple2cpg/querying/MethodTests.scala
+++ b/joern-cli/frontends/jimple2cpg/src/test/scala/io/joern/jimple2cpg/querying/MethodTests.scala
@@ -15,6 +15,18 @@ class MethodTests extends JimpleCodeToCpgFixture {
       | }
       |""".stripMargin
 
+  /* The equivalent Jimple code looks like
+    int foo(int, int)
+    {
+        int param1, param2;
+        Foo this;
+        this := @this: Foo;
+        param1 := @parameter0: int;
+        param2 := @parameter1: int;
+        return 1;
+    }
+   */
+
   "should contain exactly one non-stub method node with correct fields" in {
     val List(x) = cpg.method.nameNot("<init>").isExternal(false).l
     x.name shouldBe "foo"
@@ -32,9 +44,9 @@ class MethodTests extends JimpleCodeToCpgFixture {
     x.columnNumber shouldBe None
   }
 
-//  "should return correct number of lines" in {
-//    cpg.method.name("foo").numberOfLines.l shouldBe List(3)
-//  }
+  "should return correct number of lines" in {
+    cpg.method.name("foo").numberOfLines.l shouldBe List(8)
+  }
 
   "should allow traversing to parameters" in {
     cpg.method.name("foo").parameter.name.toSetMutable shouldBe Set("this", "param1", "param2")