Repository: joernio/joern
Pull request #794 (2021-11-30 13:28:37)

default install dir for root: /opt/joern
fixes https://github.com/joernio/joern/issues/779


Patch:
diff --git a/console/src/main/scala/io/joern/console/Console.scala b/console/src/main/scala/io/joern/console/Console.scala
index 37c2d4e38..b889ec4fc 100644
--- a/console/src/main/scala/io/joern/console/Console.scala
+++ b/console/src/main/scala/io/joern/console/Console.scala
@@ -14,6 +14,7 @@ import io.shiftleft.semanticcpg.layers.{Base, CallGraph, ControlFlow, LayerCreat
 import overflowdb.traversal.help.Doc
 
 import scala.sys.process.Process
+import scala.util.control.NoStackTrace
 import scala.util.{Failure, Success, Try}
 
 class Console[T <: Project](executor: AmmoniteExecutor,
@@ -487,5 +488,11 @@ object Console {
       name
     }
   }
+}
 
+class ConsoleException(message: String, cause: Option[Throwable])
+    extends RuntimeException(message, cause.orNull)
+    with NoStackTrace {
+  def this(message: String) = this(message, None)
+  def this(message: String, cause: Throwable) = this(message, Option(cause))
 }
diff --git a/console/src/main/scala/io/joern/console/cpgcreation/ImportCode.scala b/console/src/main/scala/io/joern/console/cpgcreation/ImportCode.scala
index 24d906f71..8973b2722 100644
--- a/console/src/main/scala/io/joern/console/cpgcreation/ImportCode.scala
+++ b/console/src/main/scala/io/joern/console/cpgcreation/ImportCode.scala
@@ -1,14 +1,14 @@
 package io.joern.console.cpgcreation
 
 import better.files.File
-import io.joern.console.FrontendConfig
+import io.joern.console.{ConsoleException, FrontendConfig}
 import io.shiftleft.codepropertygraph.Cpg
 import io.shiftleft.codepropertygraph.generated.Languages
 import io.joern.console.workspacehandling.Project
 import overflowdb.traversal.help.Table
 
 import java.nio.file.Path
-import scala.util.Try
+import scala.util.{Failure, Success, Try}
 
 class ImportCode[T <: Project](console: io.joern.console.Console[T]) {
   import io.joern.console.Console._
@@ -26,25 +26,16 @@ class ImportCode[T <: Project](console: io.joern.console.Console[T]) {
   def apply(inputPath: String,
             projectName: String = "",
             namespaces: List[String] = List(),
-            language: String = ""): Option[Cpg] = {
-
+            language: String = ""): Cpg = {
     if (language != "") {
-      val generator = generatorFactory.forLanguage(language)
-      if (generator.isEmpty) {
-        report("No CPG generator exists for language: " + language)
-        return None
-      }
-      generator.flatMap { frontend =>
-        apply(frontend, inputPath, projectName, namespaces)
+      generatorFactory.forLanguage(language) match {
+        case None           => throw new ConsoleException(s"No CPG generator exists for language: $language")
+        case Some(frontend) => apply(frontend, inputPath, projectName, namespaces)
       }
     } else {
-      val generator = generatorFactory.forCodeAt(inputPath)
-      if (generator.isEmpty) {
-        report("No suitable CPG generator found for: " + inputPath)
-        return None
-      }
-      generator.flatMap { frontend =>
-        apply(frontend, inputPath, projectName, namespaces)
+      generatorFactory.forCodeAt(inputPath) match {
+        case None           => throw new ConsoleException(s"No suitable CPG generator found for: $inputPath")
+        case Some(frontend) => apply(frontend, inputPath, projectName, namespaces)
       }
     }
   }
@@ -73,18 +64,15 @@ class ImportCode[T <: Project](console: io.joern.console.Console[T]) {
                                 args: List[String]): Option[CpgGenerator] =
       io.joern.console.cpgcreation.cpgGeneratorForLanguage(language, config, rootPath, args)
 
-    def isAvailable: Boolean = {
-      cpgGeneratorForLanguage(language, config.frontend, config.install.rootPath.path, args = Nil)
-        .filter(_.isAvailable)
-        .isDefined
-    }
+    def isAvailable: Boolean =
+      cpgGeneratorForLanguage(language, config.frontend, config.install.rootPath.path, args = Nil).exists(_.isAvailable)
 
     def apply(inputPath: String,
               projectName: String = "",
               namespaces: List[String] = List(),
-              args: List[String] = List()): Option[Cpg] = {
+              args: List[String] = List()): Cpg = {
       val frontend = cpgGeneratorForLanguage(language, config.frontend, config.install.rootPath.path, args)
-        .getOrElse(throw new AssertionError(s"no cpg generator for language=$language available!"))
+        .getOrElse(throw new ConsoleException(s"no cpg generator for language=$language available!"))
       new ImportCode(console)(frontend, inputPath, projectName, namespaces)
     }
   }
@@ -94,19 +82,22 @@ class ImportCode[T <: Project](console: io.joern.console.Console[T]) {
                             description: String = "Fuzzy Parser for C/C++",
                             extension: String = "c")
       extends Frontend(name, language, description) {
-    def fromString(str: String): Option[Cpg] = {
+    def fromString(str: String): Cpg = {
       withCodeInTmpFile(str, "tmp." + extension) { dir =>
         apply(dir.path.toString)
+      } match {
+        case Failure(exception) => throw new ConsoleException(s"unable to generate cpg from given String", exception)
+        case Success(value)     => value
       }
     }
   }
 
-  private def withCodeInTmpFile(str: String, filename: String)(f: File => Option[Cpg]): Option[Cpg] = {
+  private def withCodeInTmpFile(str: String, filename: String)(f: File => Cpg): Try[Cpg] = {
     val dir = File.newTemporaryDirectory("console")
     val result = Try {
       (dir / filename).write(str)
       f(dir)
-    }.toOption.flatten
+    }
     dir.delete()
     result
   }
@@ -137,42 +128,21 @@ class ImportCode[T <: Project](console: io.joern.console.Console[T]) {
       "\n" + Table(cols, rows).render
   }
 
-  private def apply(frontend: CpgGenerator,
-                    inputPath: String,
-                    projectName: String,
-                    namespaces: List[String]): Option[Cpg] = {
-    val name =
-      Option(projectName).filter(_.nonEmpty).getOrElse(deriveNameFromInputPath(inputPath, workspace))
+  private def apply(frontend: CpgGenerator, inputPath: String, projectName: String, namespaces: List[String]): Cpg = {
+    val name = Option(projectName).filter(_.nonEmpty).getOrElse(deriveNameFromInputPath(inputPath, workspace))
     report(s"Creating project `$name` for code at `$inputPath`")
-    val pathToProject = workspace.createProject(inputPath, name)
-    val frontendCpgOutFileOpt = pathToProject.map(_.resolve(nameOfLegacyCpgInProject))
 
-    if (frontendCpgOutFileOpt.isEmpty) {
-      report(s"Error creating project for input path: `$inputPath`")
+    val cpgMaybe = for {
+      pathToProject <- workspace.createProject(inputPath, name)
+      frontendCpgOutFile = pathToProject.resolve(nameOfLegacyCpgInProject)
+      _ <- generatorFactory.runGenerator(frontend, inputPath, frontendCpgOutFile.toString, namespaces)
+      cpg <- console.open(name).flatMap(_.cpg)
+    } yield {
+      report("""|Code successfully imported. You can now query it using `cpg`.
+                |For an overview of all imported code, type `workspace`.""".stripMargin)
+      console.applyDefaultOverlays(cpg)
     }
 
-    val result = frontendCpgOutFileOpt.flatMap { frontendCpgOutFile =>
-      Some(frontend).flatMap { frontend =>
-        generatorFactory
-          .runGenerator(
-            frontend,
-            inputPath,
-            frontendCpgOutFile.toString,
-            namespaces
-          )
-          .flatMap(_ => console.open(name).flatMap(_.cpg))
-          .map { c =>
-            console.applyDefaultOverlays(c)
-          }
-      }
-    }
-    if (result.isDefined) {
-      report(
-        """|Code successfully imported. You can now query it using `cpg`.
-           |For an overview of all imported code, type `workspace`.""".stripMargin
-      )
-    }
-    result
+    cpgMaybe.getOrElse(throw new ConsoleException(s"Error creating project for input path: `$inputPath`"))
   }
-
 }
diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala
index 61fa9b0aa..ce5fb7d5e 100644
--- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstCreatorHelper.scala
@@ -141,12 +141,20 @@ trait AstCreatorHelper {
   }
 
   @nowarn
-  protected def typeFor(node: IASTNode): String = node match {
-    case _: IASTIdExpression | _: IASTName | _: IASTArrayDeclarator =>
-      cleanType(ASTTypeUtil.getNodeType(node))
-    case _ =>
-      import org.eclipse.cdt.core.dom.ast.ASTSignatureUtil.getNodeSignature
-      cleanType(getNodeSignature(node))
+  protected def typeFor(node: IASTNode): String = {
+    import org.eclipse.cdt.core.dom.ast.ASTSignatureUtil.getNodeSignature
+    node match {
+      case a: IASTArrayDeclarator if ASTTypeUtil.getNodeType(a).startsWith("? ") =>
+        val tpe = cleanType(getNodeSignature(node)).replace("[]", "")
+        val arr = ASTTypeUtil.getNodeType(node).replace("? ", "")
+        s"$tpe$arr"
+      case _: IASTIdExpression | _: IASTName | _: IASTArrayDeclarator =>
+        cleanType(ASTTypeUtil.getNodeType(node))
+      case d: IASTDeclSpecifier =>
+        cleanType(ASTStringUtil.getReturnTypeString(d, null))
+      case _ =>
+        cleanType(getNodeSignature(node))
+    }
   }
 
   private def notHandledText(node: IASTNode): String =
@@ -279,14 +287,14 @@ trait AstCreatorHelper {
   }
 
   private def pointersAsString(spec: IASTDeclSpecifier, parentDecl: IASTDeclarator): String = {
-    val nodeAsString = ASTStringUtil.getReturnTypeString(spec, null)
+    val tpe = typeFor(spec)
     val pointers = parentDecl.getPointerOperators
     val arr = parentDecl match {
       case p: IASTArrayDeclarator => "[]" * p.getArrayModifiers.length
       case _                      => ""
     }
-    if (pointers.isEmpty) { s"$nodeAsString$arr" } else {
-      s"$nodeAsString$arr${"*" * pointers.size}".strip()
+    if (pointers.isEmpty) { s"$tpe$arr" } else {
+      s"$tpe$arr${"*" * pointers.size}".strip()
     }
   }
 
diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForFunctionsCreator.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForFunctionsCreator.scala
index d3bda1548..8922358ec 100644
--- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForFunctionsCreator.scala
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForFunctionsCreator.scala
@@ -23,7 +23,8 @@ trait AstForFunctionsCreator {
     val parentNode: NewTypeDecl = methodAstParentStack.collectFirst { case t: NewTypeDecl => t }.getOrElse {
       val astParentType = methodAstParentStack.head.label
       val astParentFullName = methodAstParentStack.head.properties("FULL_NAME").toString
-      val newTypeDeclNode = newTypeDecl(methodName, methodFullName, method.filename, astParentType, astParentFullName)
+      val newTypeDeclNode =
+        newTypeDecl(methodName, methodFullName, method.filename, methodName, astParentType, astParentFullName)
       Ast.storeInDiffGraph(Ast(newTypeDeclNode), diffGraph)
       newTypeDeclNode
     }
diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForTypesCreator.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForTypesCreator.scala
index 485a50031..5a4f5d489 100644
--- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForTypesCreator.scala
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstForTypesCreator.scala
@@ -97,11 +97,12 @@ trait AstForTypesCreator {
 
   protected def astForDeclarator(declaration: IASTSimpleDeclaration, declarator: IASTDeclarator, order: Int): Ast = {
     val declTypeName = registerType(typeForDeclSpecifier(declaration.getDeclSpecifier))
+    val tpe = typeFor(declarator)
     val name = declarator.getName.toString
     declaration match {
       case d if isTypeDef(d) =>
         val filename = fileName(declaration)
-        Ast(newTypeDecl(name, registerType(name), filename, alias = Some(declTypeName), order = order))
+        Ast(newTypeDecl(name, registerType(name), filename, s"$tpe $name", alias = Some(declTypeName), order = order))
       case d if parentIsClassDef(d) =>
         Ast(
           NewMember()
@@ -110,20 +111,18 @@ trait AstForTypesCreator {
             .typeFullName(declTypeName)
             .order(order))
       case _ if declarator.isInstanceOf[IASTArrayDeclarator] =>
-        val tpe = registerType(typeFor(declarator))
         val l = NewLocal()
-          .code(name)
+          .code(s"$tpe $name")
           .name(name)
-          .typeFullName(tpe)
+          .typeFullName(registerType(tpe))
           .order(order)
         scope.addToScope(name, (l, tpe))
         Ast(l)
       case _ =>
-        val tpe = registerType(typeFor(declarator))
         val l = NewLocal()
-          .code(name)
+          .code(s"$declTypeName $name")
           .name(name)
-          .typeFullName(tpe)
+          .typeFullName(registerType(tpe))
           .order(order)
         scope.addToScope(name, (l, tpe))
         Ast(l)
@@ -180,13 +179,14 @@ trait AstForTypesCreator {
     val filename = fileName(aliasDeclaration)
 
     val name = aliasDeclaration.getAlias.toString
-    val mappedName = ASTTypeUtil.getType(aliasDeclaration.getMappingTypeId)
+    val mappedName = registerType(typeFor(aliasDeclaration.getMappingTypeId))
     val typeDeclNode =
       newTypeDecl(
         name,
         registerType(name),
         filename,
-        alias = Some(registerType(mappedName)),
+        mappedName,
+        alias = Some(mappedName),
         line = linenumber,
         column = columnnumber,
         order = order
@@ -230,7 +230,7 @@ trait AstForTypesCreator {
           case spec: IASTNamedTypeSpecifier if declaration.getDeclarators.isEmpty =>
             val filename = fileName(spec)
             val name = nodeSignature(spec.getName)
-            Seq(Ast(newTypeDecl(name, registerType(name), filename, alias = Some(name), order = order)))
+            Seq(Ast(newTypeDecl(name, registerType(name), filename, name, alias = Some(name), order = order)))
           case _ if declaration.getDeclarators.nonEmpty =>
             declaration.getDeclarators.toIndexedSeq.map {
               case d: IASTFunctionDeclarator =>
@@ -281,13 +281,13 @@ trait AstForTypesCreator {
                                    decls: List[IASTDeclarator],
                                    order: Int): Seq[Ast] = {
     val filename = fileName(typeSpecifier)
-
     val declAsts = withOrder(decls) { (d, o) =>
       astForDeclarator(typeSpecifier.getParent.asInstanceOf[IASTSimpleDeclaration], d, order + o)
     }
 
     val name = typeSpecifier.getName.toString
-    val fullname = fullName(typeSpecifier)
+    val fullname = registerType(fullName(typeSpecifier))
+    val code = typeFor(typeSpecifier)
     val nameWithTemplateParams = templateParameters(typeSpecifier).map(fullname + _)
 
     val typeDecl = typeSpecifier match {
@@ -295,13 +295,14 @@ trait AstForTypesCreator {
         val baseClassList = cppClass.getBaseSpecifiers.toSeq.map(s => fixQualifiedName(s.getNameSpecifier.toString))
         baseClassList.foreach(registerType)
         newTypeDecl(name,
-                    registerType(fullname),
+                    fullname,
                     filename,
+                    code,
                     inherits = baseClassList,
                     alias = nameWithTemplateParams,
                     order = order)
       case _ =>
-        newTypeDecl(name, registerType(fullname), filename, alias = nameWithTemplateParams, order = order)
+        newTypeDecl(name, fullname, filename, code, alias = nameWithTemplateParams, order = order)
     }
 
     methodAstParentStack.push(typeDecl)
@@ -326,11 +327,11 @@ trait AstForTypesCreator {
     }
 
     val name = typeSpecifier.getName.toString
-    val fullname = fullName(typeSpecifier)
+    val fullname = registerType(fullName(typeSpecifier))
     val nameWithTemplateParams = templateParameters(typeSpecifier).map(fullname + _)
 
     val typeDecl =
-      newTypeDecl(name, registerType(fullname), filename, alias = nameWithTemplateParams, order = order)
+      newTypeDecl(name, fullname, filename, typeFor(typeSpecifier), alias = nameWithTemplateParams, order = order)
 
     Ast(typeDecl) +: declAsts
   }
@@ -364,22 +365,22 @@ trait AstForTypesCreator {
 
   }
 
-  private def astsForEnum(enumSpecifier: IASTEnumerationSpecifier,
+  private def astsForEnum(typeSpecifier: IASTEnumerationSpecifier,
                           decls: List[IASTDeclarator],
                           order: Int): Seq[Ast] = {
-    val filename = fileName(enumSpecifier)
+    val filename = fileName(typeSpecifier)
     val declAsts = withOrder(decls) { (d, o) =>
-      astForDeclarator(enumSpecifier.getParent.asInstanceOf[IASTSimpleDeclaration], d, order + o)
+      astForDeclarator(typeSpecifier.getParent.asInstanceOf[IASTSimpleDeclaration], d, order + o)
     }
 
-    val (name, fullname) = uniqueName("enum", enumSpecifier.getName.toString, fullName(enumSpecifier))
-    val typeDecl = newTypeDecl(name, registerType(fullname), filename, order = order)
+    val (name, fullname) = uniqueName("enum", typeSpecifier.getName.toString, fullName(typeSpecifier))
+    val typeDecl = newTypeDecl(name, registerType(fullname), filename, typeFor(typeSpecifier), order = order)
 
     methodAstParentStack.push(typeDecl)
     scope.pushNewScope(typeDecl)
 
     var currentOrder = 0
-    val member = enumSpecifier.getEnumerators.toIndexedSeq.flatMap { e =>
+    val member = typeSpecifier.getEnumerators.toIndexedSeq.flatMap { e =>
       val eCpg = astsForEnumerator(e, currentOrder)
       currentOrder = eCpg.size + currentOrder
       eCpg
diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstNodeBuilder.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstNodeBuilder.scala
index 7487ea6e4..6111fee37 100644
--- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstNodeBuilder.scala
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/astcreation/AstNodeBuilder.scala
@@ -77,6 +77,7 @@ trait AstNodeBuilder {
   protected def newTypeDecl(name: String,
                             fullname: String,
                             filename: String,
+                            code: String,
                             astParentType: String = "",
                             astParentFullName: String = "",
                             order: Int = -1,
@@ -87,6 +88,7 @@ trait AstNodeBuilder {
     NewTypeDecl()
       .name(name)
       .fullName(fullname)
+      .code(code)
       .isExternal(false)
       .filename(filename)
       .astParentType(astParentType)
diff --git a/joern-install.sh b/joern-install.sh
index 59b693c2c..9d142637b 100755
--- a/joern-install.sh
+++ b/joern-install.sh
@@ -71,7 +71,12 @@ do
     shift
 done
 
-JOERN_DEFAULT_INSTALL_DIR=~/bin/joern
+if [ "$(whoami)" != "root" ]; then
+  JOERN_DEFAULT_INSTALL_DIR=~/bin/joern
+else
+  JOERN_DEFAULT_INSTALL_DIR=/opt/joern
+fi
+
 JOERN_DEFAULT_LINK_DIR="/usr/local/bin"
 JOERN_DEFAULT_VERSION=""
 
@@ -163,8 +168,7 @@ unzip -qo -d "$JOERN_INSTALL_DIR" "$SCRIPT_ABS_DIR"/joern-cli.zip
 
 if [ $INTERACTIVE = false ] && [ "$(whoami)" != "root" ]; then
   echo "==============================================================="
-  echo "WARNING: you are NOT root and you are running non-interactively"
-  echo "Symlinks will not be created"
+  echo "you are not root and you are running non-interactively - will not create system symlinks"
   echo "==============================================================="
 else
     # Link to JOERN_LINK_DIR if desired by the user


Test patch:
diff --git a/console/src/test/scala/io/joern/console/ConsoleTests.scala b/console/src/test/scala/io/joern/console/ConsoleTests.scala
index 1747b438d..e933bba40 100644
--- a/console/src/test/scala/io/joern/console/ConsoleTests.scala
+++ b/console/src/test/scala/io/joern/console/ConsoleTests.scala
@@ -220,7 +220,7 @@ class ConsoleTests extends AnyWordSpec with Matchers {
 
     "remove a project from disk" in ConsoleFixture() { (console, codeDir) =>
       val cpg = console.importCode(codeDir.toString, "foo")
-      val projectDir = console.workspace.projectByCpg(cpg.get).get.path.toFile
+      val projectDir = console.workspace.projectByCpg(cpg).get.path.toFile
       console.delete("foo")
       projectDir.exists shouldBe false
     }
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/EnumTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/EnumTests.scala
index 1c437bf39..53ca54635 100644
--- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/EnumTests.scala
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/EnumTests.scala
@@ -23,6 +23,7 @@ class EnumTests extends AnyWordSpec with Matchers with Inside with CompleteCpgFi
       inside(cpg.typeDecl.internal.l) {
         case List(color) =>
           color.name shouldBe "color"
+          color.code shouldBe "enum color"
           inside(color.member.l) {
             case List(red, yellow, green, blue) =>
               red.name shouldBe "red"
@@ -48,6 +49,7 @@ class EnumTests extends AnyWordSpec with Matchers with Inside with CompleteCpgFi
       inside(cpg.typeDecl.filter(x => !x.isExternal).l) {
         case List(color, c) =>
           color.name shouldBe "color"
+          color.code shouldBe "enum color"
           color.aliasTypeFullName shouldBe None
           c.name shouldBe "C"
           c.aliasTypeFullName shouldBe Some("color")
@@ -74,6 +76,7 @@ class EnumTests extends AnyWordSpec with Matchers with Inside with CompleteCpgFi
       inside(cpg.typeDecl.internal.l) {
         case List(altitude) =>
           altitude.name shouldBe "altitude"
+          altitude.code shouldBe "enum altitude"
           inside(altitude.member.l) {
             case List(high, low) =>
               high.name shouldBe "high"
@@ -99,6 +102,7 @@ class EnumTests extends AnyWordSpec with Matchers with Inside with CompleteCpgFi
       inside(cpg.typeDecl.internal.l) {
         case List(smallenum) =>
           smallenum.name shouldBe "smallenum"
+          smallenum.code shouldBe "enum smallenum"
           inside(smallenum.member.l) {
             case List(a, b, c) =>
               a.name shouldBe "a"
@@ -121,6 +125,7 @@ class EnumTests extends AnyWordSpec with Matchers with Inside with CompleteCpgFi
       inside(cpg.typeDecl.internal.l) {
         case List(anon) =>
           anon.name shouldBe "anonymous_enum_0"
+          anon.code shouldBe "enum"
           inside(anon.member.l) {
             case List(d, e, f) =>
               d.name shouldBe "d"
@@ -141,6 +146,7 @@ class EnumTests extends AnyWordSpec with Matchers with Inside with CompleteCpgFi
       inside(cpg.typeDecl.internal.l) {
         case List(x) =>
           x.name shouldBe "X"
+          x.code shouldBe "enum X"
           inside(x.member.l) {
             case List(a, b) =>
               a.name shouldBe "a"
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/TemplateTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/TemplateTests.scala
index b5ba6a3b0..3f3a597f7 100644
--- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/TemplateTests.scala
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/TemplateTests.scala
@@ -29,7 +29,7 @@ class TemplateTests extends AnyWordSpec with Matchers with Inside with CompleteC
           a.aliasTypeFullName shouldBe Some("X<int>")
           b.name shouldBe "B"
           b.fullName shouldBe "B"
-          b.aliasTypeFullName shouldBe Some("Y<int,char>")
+          b.aliasTypeFullName shouldBe Some("Y<int, char>")
       }
     }
 
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/AstCreationPassTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/AstCreationPassTests.scala
index c3bf6cbff..886edc59b 100644
--- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/AstCreationPassTests.scala
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/AstCreationPassTests.scala
@@ -755,15 +755,17 @@ class AstCreationPassTests
         case List(forStmt) =>
           forStmt.controlStructureType shouldBe ControlStructureTypes.FOR
           inside(forStmt.astChildren.order(1).l) {
-            case List(ident) =>
+            case List(ident: Identifier) =>
               ident.code shouldBe "list"
           }
           inside(forStmt.astChildren.order(2).l) {
-            case List(ident) =>
-              ident.code shouldBe "x"
+            case List(x: Local) =>
+              x.name shouldBe "x"
+              x.typeFullName shouldBe "int"
+              x.code shouldBe "int x"
           }
           inside(forStmt.astChildren.order(3).l) {
-            case List(block) =>
+            case List(block: Block) =>
               block.astChildren.isCall.code.l shouldBe List("z = x")
           }
       }
@@ -1469,7 +1471,7 @@ class AstCreationPassTests
         case List(buf: Local) =>
           buf.typeFullName shouldBe "char[256]"
           buf.name shouldBe "buf"
-          buf.code shouldBe "buf"
+          buf.code shouldBe "char[256] buf"
       }
     }
 
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/TypeNodePassTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/TypeNodePassTests.scala
index abaf824ad..05e896c8f 100644
--- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/TypeNodePassTests.scala
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/passes/TypeNodePassTests.scala
@@ -32,6 +32,35 @@ class TypeNodePassTests extends AnyWordSpec with Matchers with Inside with CpgTy
           }
       }
     }
+
+    "create correct types for structs" in CpgTypeNodeFixture("""
+        |struct test {
+        |  int a;
+        |};
+        |
+        |void free_struct() {
+        |  struct test *ptr;
+        |  ptr = kzalloc(sizeof(struct test), GFP_KERNEL);
+        |  free(ptr);
+        |}
+        |""".stripMargin) { cpg =>
+      inside(cpg.call("free").argument(1).l) {
+        case List(arg) =>
+          arg.evalType.l shouldBe List("test*")
+          arg.code shouldBe "ptr"
+      }
+    }
+
+    "create correct types for arrays" in CpgTypeNodeFixture("""
+        |void bad1(size_t a) {
+        |  uint8_t src[1], dst[1];
+        |  memcpy(dst, src, a);
+        |}
+        |""".stripMargin) { cpg =>
+      inside(cpg.call("memcpy").argument(1).evalType.l) {
+        case List(tpe) => tpe shouldBe "uint8_t[1]"
+      }
+    }
   }
 
 }
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/querying/LocalsTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/querying/LocalsTests.scala
index 2c884b44f..a0159ded7 100644
--- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/querying/LocalsTests.scala
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/querying/LocalsTests.scala
@@ -41,8 +41,15 @@ class LocalsTests extends CCodeToCpgSuite {
   }
 
   "should prove correct (name, type) pairs for locals" in {
-    cpg.method.name("free_list").local.map(l => (l.name, l.typeFullName)).toSet shouldBe
-      Set(("q", "node*"), ("p", "node*"))
+    inside(cpg.method.name("free_list").local.l) {
+      case List(q, p) =>
+        q.name shouldBe "q"
+        q.typeFullName shouldBe "node*"
+        q.code shouldBe "struct node* q"
+        p.name shouldBe "p"
+        p.typeFullName shouldBe "node*"
+        p.code shouldBe "struct node* p"
+    }
   }
 
   "should allow finding filenames by local regex" in {
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/standard/TypeDeclTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/standard/TypeDeclTests.scala
index fb52c6a7b..5b02ba88c 100644
--- a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/standard/TypeDeclTests.scala
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/standard/TypeDeclTests.scala
@@ -35,6 +35,7 @@ class TypeDeclTests extends CCodeToCpgSuite(FileDefaults.CPP_EXT) {
     x.isExternal shouldBe false
     x.inheritsFromTypeFullName shouldBe List()
     x.aliasTypeFullName shouldBe Some("int")
+    x.code shouldBe "typedef int mytype"
     x.order shouldBe 2
     x.filename.startsWith("/") shouldBe true
     x.filename.endsWith(FileDefaults.CPP_EXT) shouldBe true
diff --git a/joern-cli/frontends/javasrc2cpg/src/test/scala/io/joern/javasrc2cpg/querying/SynchronizedTests.scala b/joern-cli/frontends/javasrc2cpg/src/test/scala/io/joern/javasrc2cpg/querying/SynchronizedTests.scala
index 12e7dd310..d22237a42 100644
--- a/joern-cli/frontends/javasrc2cpg/src/test/scala/io/joern/javasrc2cpg/querying/SynchronizedTests.scala
+++ b/joern-cli/frontends/javasrc2cpg/src/test/scala/io/joern/javasrc2cpg/querying/SynchronizedTests.scala
@@ -1,7 +1,15 @@
 package io.joern.javasrc2cpg.querying
 
 import io.joern.javasrc2cpg.testfixtures.JavaSrcCodeToCpgFixture
-import io.shiftleft.codepropertygraph.generated.nodes.{Block, Identifier, Method, MethodParameterIn, MethodReturn, Modifier, Return}
+import io.shiftleft.codepropertygraph.generated.nodes.{
+  Block,
+  Identifier,
+  Method,
+  MethodParameterIn,
+  MethodReturn,
+  Modifier,
+  Return
+}
 import io.shiftleft.semanticcpg.language._
 
 class SynchronizedTests extends JavaSrcCodeToCpgFixture {
diff --git a/querydb/src/test/scala/io/joern/scanners/c/QueryWithReachableBy.scala b/querydb/src/test/scala/io/joern/scanners/c/QueryWithReachableBy.scala
index 18a55a2b8..66aaf64ac 100644
--- a/querydb/src/test/scala/io/joern/scanners/c/QueryWithReachableBy.scala
+++ b/querydb/src/test/scala/io/joern/scanners/c/QueryWithReachableBy.scala
@@ -10,9 +10,8 @@ import io.joern.dataflowengineoss.semanticsloader.Semantics
 import io.shiftleft.codepropertygraph.generated.Operators
 import io.shiftleft.codepropertygraph.generated.nodes._
 
-
 /**
-  * Just to make sure that we support reachableBy queries, 
+  * Just to make sure that we support reachableBy queries,
   * which did not work before https://github.com/joernio/joern/pull/791
   * initially reported in https://github.com/joernio/joern/issues/751
   */
@@ -24,8 +23,7 @@ object QueryWithReachableBy extends QueryBundle {
       name = "test",
       author = "me",
       title = "test",
-      description =
-        """
+      description = """
         |test
         |""".stripMargin,
       score = 2,