Repository: joernio/joern
Pull request #767 (2021-11-19 12:49:21)

use newc frontend instead of oldc in CQueryTestSuite
Fix for #758

raymontag: I noticed, that for the failing tests a `.whereNot(_.name("<global>"))` in the query does fix it but I guess it would be better to modify the test cases?
max-leuthaeuser: > I noticed, that for the failing tests a `.whereNot(_.name("<global>"))` in the query does fix it but I guess it would be better to modify the test cases?

I guess a `.nameNot("<global>")` is ok. Lets wait for @fabsx00 answer.
fabsx00: Yes, that should be ok, please go ahead.
raymontag: I added a fix in the PR

Patch:
diff --git a/.gitignore b/.gitignore
index 91286cc37..dba4d2a5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ target
 tests/smoke-test-repos
 tests/**/node_modules
 tests/**/package-lock.json
+tests/**/package.json
 joern-cli/frontends/js2cpg
 joern-cli.zip
 joern-server.zip
diff --git a/build.sbt b/build.sbt
index c4beb7e44..af173a9bd 100644
--- a/build.sbt
+++ b/build.sbt
@@ -2,7 +2,7 @@ name := "joern"
 ThisBuild / organization := "io.joern"
 ThisBuild / scalaVersion := "2.13.7"
 
-val cpgVersion = "1.3.438"
+val cpgVersion = "1.3.447"
 val js2cpgVersion = "0.2.28"
 
 lazy val joerncli = Projects.joerncli
diff --git a/console/src/main/scala/io/joern/console/Console.scala b/console/src/main/scala/io/joern/console/Console.scala
index 37c2d4e38..94aca43dc 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,
@@ -35,10 +36,17 @@ class Console[T <: Project](executor: AmmoniteExecutor,
 
   implicit object ConsoleImageViewer extends ImageViewer {
     def view(imagePathStr: String): Try[String] = {
+      // We need to copy the file as the original one is only temporary
+      // and gets removed immediately after running this viewer instance asynchronously via .run().
+      val tmpFile = File(imagePathStr).copyTo(File.newTemporaryFile(suffix = ".svg"), overwrite = true)
+      tmpFile.deleteOnExit(swallowIOExceptions = true)
       Try {
-        Process(Seq(config.tools.imageViewer, imagePathStr)).!!
+        Process(Seq(config.tools.imageViewer, tmpFile.path.toAbsolutePath.toString)).run()
       } match {
-        case Success(v) => Success(v)
+        case Success(_) =>
+          // We never handle the actual result anywhere.
+          // Hence, we just pass a success message.
+          Success(s"Running viewer for '$tmpFile' finished.")
         case Failure(exc) =>
           System.err.println("Executing image viewer failed. Is it installed? ")
           System.err.println(exc)
@@ -48,8 +56,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "Access to the workspace directory",
-    """
+    info = "Access to the workspace directory",
+    longInfo = """
       |All auditing projects are stored in a workspace directory, and `workspace`
       |provides programmatic access to this directory. Entering `workspace` provides
       |a list of all projects, indicating which code the project makes accessible,
@@ -77,21 +85,21 @@ class Console[T <: Project](executor: AmmoniteExecutor,
       |* workspace.reset: create a fresh workspace directory, deleting the current
       |workspace directory
       |
-      |""".stripMargin,
-    "workspace"
+      |""",
+    example = "workspace"
   )
   def workspace: WorkspaceManager[T] = workspaceManager
 
   @Doc(
-    "Close current workspace and open a different one",
-    """ | By default, the workspace in $INSTALL_DIR/workspace is used.
+    info = "Close current workspace and open a different one",
+    longInfo = """ | By default, the workspace in $INSTALL_DIR/workspace is used.
       | This method allows specifying a different workspace directory
       | via the `pathName` parameter.
       | Before changing the workspace, the current workspace will be
       | closed, saving any unsaved changes.
       | If `pathName` points to a non-existing directory, then a new
       | workspace is first created.
-      |""".stripMargin
+      |"""
   )
   def switchWorkspace(pathName: String): Unit = {
     if (workspaceManager != null) {
@@ -103,13 +111,13 @@ class Console[T <: Project](executor: AmmoniteExecutor,
     workspaceManager = new WorkspaceManager[T](pathName, loader)
   }
 
-  @Doc("Currently active project", "", "project")
+  @Doc(info = "Currently active project", example = "project")
   def project: T =
     workspace.projectByCpg(cpg).getOrElse(throw new RuntimeException("No active project"))
 
   @Doc(
-    "CPG of the active project",
-    """
+    info = "CPG of the active project",
+    longInfo = """
       |Upon importing code, a project is created that holds
       |an intermediate representation called `Code Property Graph`. This
       |graph is a composition of low-level program representations such
@@ -122,8 +130,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
       |query language constructs can be invoked starting from `cpg`. For example,
       |`cpg.method.l` lists all methods, while `cpg.finding.l` lists all findings
       |of potentially vulnerable code.
-      |""".stripMargin,
-    "cpg.method.l"
+      |""",
+    example = "cpg.method.l"
   )
   implicit def cpg: Cpg = workspace.cpg
 
@@ -149,8 +157,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "Open project by name",
-    """
+    info = "Open project by name",
+    longInfo = """
       |open([projectName])
       |
       |Opens the project named `name` and make it the active project.
@@ -161,8 +169,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
       |Upon completion of this operation, the CPG stored in this project
       |can be queried via `cpg`. Returns an optional reference to the
       |project, which is empty on error.
-      |""".stripMargin,
-    """open("projectName")"""
+      |""",
+    example = """open("projectName")"""
   )
   def open(name: String): Option[Project] = {
     val projectName = fixProjectNameAndComplainOnFix(name)
@@ -172,8 +180,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "Open project for input path",
-    """
+    info = "Open project for input path",
+    longInfo = """
       |openForInputPath([input-path])
       |
       |Opens the project of the CPG generated for the input path `input-path`.
@@ -181,7 +189,7 @@ class Console[T <: Project](executor: AmmoniteExecutor,
       |Upon completion of this operation, the CPG stored in this project
       |can be queried via `cpg`. Returns an optional reference to the
       |project, which is empty on error.
-      |""".stripMargin
+      |"""
   )
   def openForInputPath(inputPath: String): Option[Project] = {
     val absInputPath = File(inputPath).path.toAbsolutePath.toString
@@ -208,7 +216,7 @@ class Console[T <: Project](executor: AmmoniteExecutor,
     * project.
     * @param name the name of the project
     * */
-  @Doc("Close and remove project from disk", "", "delete(projectName)")
+  @Doc(info = "Close and remove project from disk", example = "delete(projectName)")
   def delete(name: String): Option[Unit] = {
     defaultProjectNameIfEmpty(name).flatMap(workspace.deleteProject)
   }
@@ -231,11 +239,11 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "undo effects of analyzer",
-    """|Undo the last change, that is, unapply the last
+    info = "undo effects of analyzer",
+    longInfo = """|Undo the last change, that is, unapply the last
        |overlay applied to the active project.
-       |""".stripMargin,
-    "undo"
+       |""",
+    example = "undo"
   )
   def undo: File = {
     project.overlayDirs.lastOption
@@ -263,14 +271,14 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "Write all changes to disk",
-    """
+    info = "Write all changes to disk",
+    longInfo = """
       |Close and reopen all loaded CPGs. This ensures
       |that changes have been flushed to disk.
       |
       |Returns list of affected projects
-      |""".stripMargin,
-    "save"
+      |""",
+    example = "save"
   )
   def save: List[Project] = {
     report("Saving graphs on disk. This may take a while.")
@@ -282,8 +290,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "Create new project from code",
-    """
+    info = "Create new project from code",
+    longInfo = """
       |importCode(<inputPath>, [projectName], [namespaces], [language])
       |
       |Type `importCode` alone to get a list of all supported languages
@@ -319,14 +327,14 @@ class Console[T <: Project](executor: AmmoniteExecutor,
       |If `language` is empty, the language used is guessed by inspecting
       |the filename found and possibly by looking into the file/directory.
       |
-      |""".stripMargin,
-    """importCode("example.jar")"""
+      |""",
+    example = """importCode("example.jar")"""
   )
   def importCode = new ImportCode(this)
 
   @Doc(
-    "Create new project from existing CPG",
-    """
+    info = "Create new project from existing CPG",
+    longInfo = """
       |importCpg(<inputPath>, [projectName])
       |
       |Import an existing CPG. The CPG is stored as part
@@ -341,8 +349,8 @@ class Console[T <: Project](executor: AmmoniteExecutor,
       |
       |projectName: name of the new project. If this parameter
       |is omitted, the path is derived from `inputPath`
-      |""".stripMargin,
-    """importCpg("cpg.bin.zip")"""
+      |""",
+    example = """importCpg("cpg.bin.zip")"""
   )
   def importCpg(inputPath: String, projectName: String = ""): Option[Cpg] = {
     val name =
@@ -392,12 +400,12 @@ class Console[T <: Project](executor: AmmoniteExecutor,
   }
 
   @Doc(
-    "Close project by name",
-    """|Close project. Resources are freed but the project remains on disk.
+    info = "Close project by name",
+    longInfo = """|Close project. Resources are freed but the project remains on disk.
        |The project remains active, that is, calling `cpg` now raises an
        |exception. A different project can now be activated using `open`.
-       |""".stripMargin,
-    "close(projectName)"
+       |""",
+    example = "close(projectName)"
   )
   def close(name: String): Option[Project] = {
     defaultProjectNameIfEmpty(name).flatMap(workspace.closeProject)
@@ -487,5 +495,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/Help.scala b/console/src/main/scala/io/joern/console/Help.scala
index 3d25749c5..ac8d7b270 100644
--- a/console/src/main/scala/io/joern/console/Help.scala
+++ b/console/src/main/scala/io/joern/console/Help.scala
@@ -1,20 +1,19 @@
 package io.joern.console
 
 import org.apache.commons.lang.WordUtils
-import overflowdb.traversal.help.{Doc, Table}
-
-import scala.reflect.runtime.universe.{TypeTag, typeOf}
+import overflowdb.traversal.help.DocFinder._
+import overflowdb.traversal.help.{Table, DocFinder}
 
 object Help {
 
   private val width = 80
 
-  def overview[C: TypeTag]: String = {
+  def overview(clazz: Class[_]): String = {
     val columnNames = List("command", "description", "example")
-    val rows = Doc
-      .docByMethodName(typeOf[C])
+    val rows = DocFinder
+      .findDocumentedMethodsOf(clazz)
       .map {
-        case (name, doc) => List(name, doc.short, doc.example)
+        case StepDoc(_, funcName, doc) => List(funcName, doc.info, doc.example)
       }
       .toList ++ List(runRow)
 
@@ -58,16 +57,16 @@ object Help {
         |""".stripMargin
     )
 
-  def codeForHelpCommand[C: TypeTag]: String = {
-    val membersCode = Doc
-      .docByMethodName(typeOf[C])
+  def codeForHelpCommand(clazz: Class[_]): String = {
+    val membersCode = DocFinder
+      .findDocumentedMethodsOf(clazz)
       .map {
-        case (funcName, doc) =>
-          s"val $funcName : String = ${Help.format(doc.long)}"
+        case StepDoc(_, funcName, doc) =>
+          s"val $funcName : String = ${Help.format(doc.longInfo)}"
       }
       .mkString("\n")
 
-    val overview = Help.overview[C]
+    val overview = Help.overview(clazz)
     s"""
        | class Helper() {
        |
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/console/src/main/scala/io/joern/console/cpgcreation/package.scala b/console/src/main/scala/io/joern/console/cpgcreation/package.scala
index 600c91423..c8a47f770 100644
--- a/console/src/main/scala/io/joern/console/cpgcreation/package.scala
+++ b/console/src/main/scala/io/joern/console/cpgcreation/package.scala
@@ -79,9 +79,16 @@ package object cpgcreation {
       case f if f.endsWith(".php")                       => Some(Languages.PHP)
       case f if f.endsWith(".py")                        => Some(Languages.FUZZY_TEST_LANG)
       case f if f.endsWith(".bc") || f.endsWith(".ll")   => Some(Languages.LLVM)
-      case f if f.endsWith(".c") || f.endsWith(".h")     => Some(Languages.NEWC)
+      case f if isCFile(f)                               => Some(Languages.NEWC)
       case _                                             => None
     }
   }
 
+  /**
+    * check if given filename looks like it might be a C/CPP source or header file
+    * mostly copied from io.joern.c2cpg.parser.FileDefaults
+    *  */
+  private def isCFile(filename: String): Boolean =
+    Seq(".c", ".cc", ".cpp", ".h", ".hpp", ".hh").exists(filename.endsWith)
+
 }
diff --git a/dataflowengineoss/build.sbt b/dataflowengineoss/build.sbt
index 045c613ba..887876771 100644
--- a/dataflowengineoss/build.sbt
+++ b/dataflowengineoss/build.sbt
@@ -12,3 +12,7 @@ Antlr4 / antlr4PackageName := Some("io.joern.dataflowengineoss")
 Antlr4 / antlr4Version := Versions.antlr
 Antlr4 / javaSource := (Compile / sourceManaged).value
 Compile/doc/sources ~= (_ filter (_ => false))
+
+// we want to consume this from a java8 build
+compile / javacOptions ++= Seq("--release", "8")
+scalacOptions += "-target:jvm-1.8"
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-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/DefaultDefines.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/DefaultDefines.scala
new file mode 100644
index 000000000..a8e39bca3
--- /dev/null
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/DefaultDefines.scala
@@ -0,0 +1,9 @@
+package io.joern.c2cpg.parser
+
+object DefaultDefines {
+  val DEFAULT_CALL_CONVENTIONS = Map(
+    "__fastcall" -> "__attribute((fastcall))",
+    "__cdecl" -> "__attribute((cdecl))",
+    "__pascal" -> "__attribute((pascal))"
+  )
+}
diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/FileDefaults.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/FileDefaults.scala
index 1e60eaa82..52dbabae5 100644
--- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/FileDefaults.scala
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/FileDefaults.scala
@@ -13,7 +13,7 @@ object FileDefaults {
 
   val HEADER_FILE_EXTENSIONS = Set(C_HEADER_EXT, CPP_HEADER_EXT, OTHER_HEADER_EXT)
 
-  private val CPP_FILE_EXTENSIONS = Set(CPP_EXT, CPP_HEADER_EXT)
+  private val CPP_FILE_EXTENSIONS = Set(CC_EXT, CPP_EXT, CPP_HEADER_EXT)
 
   def isHeaderFile(filePath: String): Boolean =
     HEADER_FILE_EXTENSIONS.exists(filePath.endsWith)
diff --git a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/ParserConfig.scala b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/ParserConfig.scala
index f61c2372d..bae22f6c7 100644
--- a/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/ParserConfig.scala
+++ b/joern-cli/frontends/c2cpg/src/main/scala/io/joern/c2cpg/parser/ParserConfig.scala
@@ -16,7 +16,7 @@ object ParserConfig {
         val s = define.split("=")
         s.head -> s(1)
       case define => define -> "true"
-    }.toMap,
+    }.toMap ++ DefaultDefines.DEFAULT_CALL_CONVENTIONS,
     config.logProblems,
     config.logPreprocessor
   )
diff --git a/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/Ghidra2Cpg.scala b/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/Ghidra2Cpg.scala
index 3526fd7c5..7073a883a 100644
--- a/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/Ghidra2Cpg.scala
+++ b/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/Ghidra2Cpg.scala
@@ -149,7 +149,7 @@ class Ghidra2Cpg() {
           ).createAndApply()
           new LoHiPass(cpg).createAndApply()
         }
-      case "AARCH64" =>
+      case "AARCH64" | "ARM" =>
         functions.foreach { function =>
           new ArmFunctionPass(
             program,
diff --git a/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/passes/mips/MipsReturnEdgesPass.scala b/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/passes/mips/MipsReturnEdgesPass.scala
new file mode 100644
index 000000000..25ee84d54
--- /dev/null
+++ b/joern-cli/frontends/ghidra2cpg/src/main/scala/io/joern/ghidra2cpg/passes/mips/MipsReturnEdgesPass.scala
@@ -0,0 +1,26 @@
+package io.joern.ghidra2cpg.passes.mips
+
+import io.shiftleft.codepropertygraph.Cpg
+import io.shiftleft.codepropertygraph.generated.{EdgeTypes, PropertyNames}
+import io.shiftleft.passes.{CpgPass, DiffGraph}
+import io.shiftleft.semanticcpg.language._
+import org.slf4j.{Logger, LoggerFactory}
+
+class MipsReturnEdgesPass(cpg: Cpg) extends CpgPass(cpg) {
+  private val logger: Logger = LoggerFactory.getLogger(this.getClass)
+
+  override def run(): Iterator[DiffGraph] = {
+    logger.info("Running ReturnEdgesPass")
+    implicit val diffGraph: DiffGraph.Builder = DiffGraph.newBuilder
+    cpg.call.nameNot("<operator>.*").foreach { from =>
+      // We expect v1|v0 as return
+      // Note: this is not sufficient but a first approach without using data flow
+      //        the first .cfgNext is skipping a _nop instruction after the call
+      val to = from.cfgNext.cfgNext.isCall.argument.code("v(0|1)").headOption
+      if (to.nonEmpty) {
+        diffGraph.addEdge(from, to.get, EdgeTypes.REACHING_DEF, Seq((PropertyNames.VARIABLE, from.code)))
+      }
+    }
+    Iterator(diffGraph.build())
+  }
+}
diff --git a/joern-cli/src/main/scala/io/joern/console/Predefined.scala b/joern-cli/src/main/scala/io/joern/console/Predefined.scala
index 1ec9e8903..bb05cab95 100644
--- a/joern-cli/src/main/scala/io/joern/console/Predefined.scala
+++ b/joern-cli/src/main/scala/io/joern/console/Predefined.scala
@@ -38,7 +38,7 @@ object Predefined {
 
   def dynamicPredef(): String = {
     Run.codeForRunCommand() +
-      Help.codeForHelpCommand[io.joern.console.JoernConsole]
+      Help.codeForHelpCommand(classOf[io.joern.console.JoernConsole])
   }
 
 }
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
diff --git a/querydb/src/main/scala/io/joern/scanners/c/Metrics.scala b/querydb/src/main/scala/io/joern/scanners/c/Metrics.scala
index 1e9bad126..fdf5c1a01 100644
--- a/querydb/src/main/scala/io/joern/scanners/c/Metrics.scala
+++ b/querydb/src/main/scala/io/joern/scanners/c/Metrics.scala
@@ -47,7 +47,7 @@ object Metrics extends QueryBundle {
       description = s"This query identifies functions with a cyclomatic complexity higher than $n",
       score = 1.0,
       withStrRep({ cpg =>
-        cpg.method.internal.filter(_.controlStructure.size > n)
+        cpg.method.internal.filter(_.controlStructure.size > n).nameNot("<global>")
       }),
       tags = List(QueryTags.metrics),
       codeExamples = CodeExamples(
@@ -128,7 +128,7 @@ object Metrics extends QueryBundle {
       description = "This query identifies functions with more than one return",
       score = 1.0,
       withStrRep({ cpg =>
-        cpg.method.internal.filter(_.ast.isReturn.l.size > 1)
+        cpg.method.internal.filter(_.ast.isReturn.l.size > 1).nameNot("<global>")
       }),
       tags = List(QueryTags.metrics),
       codeExamples = CodeExamples(
@@ -167,6 +167,7 @@ object Metrics extends QueryBundle {
             _.ast.isControlStructure
               .controlStructureType("(FOR|DO|WHILE)")
               .size > n)
+          .nameNot("<global>")
       }),
       tags = List(QueryTags.metrics),
       codeExamples = CodeExamples(
@@ -202,7 +203,7 @@ object Metrics extends QueryBundle {
       description = s"This query identifies functions with a nesting level higher than $n",
       score = 1.0,
       withStrRep({ cpg =>
-        cpg.method.internal.filter(_.depth(_.isControlStructure) > n)
+        cpg.method.internal.filter(_.depth(_.isControlStructure) > n).nameNot("<global>")
       }),
       tags = List(QueryTags.metrics),
       codeExamples = CodeExamples(


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/console/src/test/scala/io/joern/console/HelpTests.scala b/console/src/test/scala/io/joern/console/HelpTests.scala
index e55ba4433..299e56e81 100644
--- a/console/src/test/scala/io/joern/console/HelpTests.scala
+++ b/console/src/test/scala/io/joern/console/HelpTests.scala
@@ -8,7 +8,7 @@ class HelpTests extends AnyWordSpec with Matchers {
 
   "Help" should {
     "provide overview of commands as table" in {
-      Help.overview[io.joern.console.Console[Project]].contains("| CPG") shouldBe true
+      Help.overview(classOf[io.joern.console.Console[Project]]).contains("| CPG") shouldBe true
     }
   }
 
diff --git a/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/CallConventionsTests.scala b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/CallConventionsTests.scala
new file mode 100644
index 000000000..6b92c3866
--- /dev/null
+++ b/joern-cli/frontends/c2cpg/src/test/scala/io/joern/c2cpg/CallConventionsTests.scala
@@ -0,0 +1,45 @@
+package io.joern.c2cpg
+
+import io.joern.c2cpg.fixtures.TestAstOnlyFixture
+import io.shiftleft.semanticcpg.language._
+import org.scalatest.Inside
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+
+class CallConventionsTests extends AnyWordSpec with Matchers with Inside with TestAstOnlyFixture {
+
+  "Using calling conventions" should {
+
+    "be correct for methods" in TestAstOnlyFixture("""
+        |int __stdcall foo1() {
+        |	strstr(a, "a");
+        |}
+        |
+        |int __cdecl foo2() {
+        |	strstr(a, "a");
+        |}
+        |
+        |int __fastcall foo3() {
+        |	strstr(a, "a");
+        |}
+        |
+        |int __pascal foo4() {
+        |	strstr(a, "a");
+        |}
+        |""".stripMargin) { cpg =>
+      inside(cpg.method.nameNot("<global>").l) {
+        case List(foo1, foo2, foo3, foo4) =>
+          foo1.name shouldBe "foo1"
+          foo1.ast.isCall.name.l shouldBe List("strstr")
+          foo2.name shouldBe "foo2"
+          foo2.ast.isCall.name.l shouldBe List("strstr")
+          foo3.name shouldBe "foo3"
+          foo3.ast.isCall.name.l shouldBe List("strstr")
+          foo4.name shouldBe "foo4"
+          foo4.ast.isCall.name.l shouldBe List("strstr")
+      }
+    }
+
+  }
+
+}
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,
diff --git a/querydb/src/test/scala/io/joern/suites/CQueryTestSuite.scala b/querydb/src/test/scala/io/joern/suites/CQueryTestSuite.scala
index 41ff04350..368e1e21e 100644
--- a/querydb/src/test/scala/io/joern/suites/CQueryTestSuite.scala
+++ b/querydb/src/test/scala/io/joern/suites/CQueryTestSuite.scala
@@ -6,7 +6,7 @@ import io.shiftleft.codepropertygraph.generated.nodes
 import io.joern.console.scan._
 import io.joern.console.{QueryBundle, QueryDatabase}
 import io.joern.console.Query
-import io.joern.fuzzyc2cpg.testfixtures.DataFlowCodeToCpgSuite
+import io.joern.c2cpg.testfixtures.DataFlowCodeToCpgSuite
 import io.shiftleft.semanticcpg.language._
 
 class CQueryTestSuite extends DataFlowCodeToCpgSuite {