Skip to content

Commit

Permalink
[c2cpg] Enable file content and content for method and type decl (#4195)
Browse files Browse the repository at this point in the history
  • Loading branch information
max-leuthaeuser authored Feb 19, 2024
1 parent 339a0c7 commit b4ff8b3
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ class AstCreator(
protected val methodAstParentStack: Stack[NewNode] = new Stack()

def createAst(): DiffGraphBuilder = {
val ast = astForTranslationUnit(cdtAst)
val fileContent = if (!config.disableFileContent) Option(cdtAst.getRawSignature) else None
val fileNode = NewFile().name(fileName(cdtAst)).order(1)
fileContent.foreach(fileNode.content(_))
val ast = Ast(fileNode).withChild(astForTranslationUnit(cdtAst))
Ast.storeInDiffGraph(ast, diffGraph)
diffGraph
}
Expand Down Expand Up @@ -89,4 +92,42 @@ class AstCreator(
methodAst(fakeGlobalMethod, Seq.empty, blockAst(blockNode_, declsAsts), methodReturn)
)
}

override protected def code(node: IASTNode): String = shortenCode(nodeSignature(node))

override protected def line(node: IASTNode): Option[Integer] = {
nullSafeFileLocation(node).map(_.getStartingLineNumber)
}

override protected def lineEnd(node: IASTNode): Option[Integer] = {
nullSafeFileLocation(node).map(_.getEndingLineNumber)
}

protected def column(node: IASTNode): Option[Integer] = {
nodeOffsets(node).map { case (startOffset, _) =>
offsetToColumn(node, startOffset)
}
}

protected def columnEnd(node: IASTNode): Option[Integer] = {
nodeOffsets(node).map { case (_, endOffset) =>
offsetToColumn(node, endOffset - 1)
}
}

private def nodeOffsets(node: IASTNode): Option[(Int, Int)] = {
for {
startOffset <- nullSafeFileLocation(node).map(l => l.getNodeOffset)
endOffset <- nullSafeFileLocation(node).map(l => l.getNodeOffset + l.getNodeLength)
} yield (startOffset, endOffset)
}

override protected def offset(node: IASTNode): Option[(Int, Int)] = {
Option
.when(!config.disableFileContent) {
nodeOffsets(node)
}
.flatten
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,15 @@ trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: As
offsets.toArray
}

private def nullSafeFileLocation(node: IASTNode): Option[IASTFileLocation] =
protected def nullSafeFileLocation(node: IASTNode): Option[IASTFileLocation] =
Option(cdtAst.flattenLocationsToFile(node.getNodeLocations)).map(_.asFileLocation())

private def nullSafeFileLocationLast(node: IASTNode): Option[IASTFileLocation] =
Option(cdtAst.flattenLocationsToFile(node.getNodeLocations.lastOption.toArray)).map(_.asFileLocation())

protected def fileName(node: IASTNode): String = {
val path = nullSafeFileLocation(node).map(_.getFileName).getOrElse(filename)
SourceFiles.toRelativePath(path, config.inputPath)
}

protected def code(node: IASTNode): String = shortenCode(nodeSignature(node))

protected def line(node: IASTNode): Option[Integer] = {
nullSafeFileLocation(node).map(_.getStartingLineNumber)
}

protected def lineEnd(node: IASTNode): Option[Integer] = {
nullSafeFileLocationLast(node).map(_.getEndingLineNumber)
}

private def offsetToColumn(node: IASTNode, offset: Int): Int = {
protected def offsetToColumn(node: IASTNode, offset: Int): Int = {
val table = fileOffsetTable(node)
val index = java.util.Arrays.binarySearch(table, offset)
val tableIndex = if (index < 0) -(index + 1) else index + 1
Expand All @@ -106,20 +93,6 @@ trait AstCreatorHelper(implicit withSchemaValidation: ValidationMode) { this: As
column
}

protected def column(node: IASTNode): Option[Integer] = {
val loc = nullSafeFileLocation(node)
loc.map { x =>
offsetToColumn(node, x.getNodeOffset)
}
}

protected def columnEnd(node: IASTNode): Option[Integer] = {
val loc = nullSafeFileLocation(node)
loc.map { x =>
offsetToColumn(node, x.getNodeOffset + x.getNodeLength - 1)
}
}

protected def registerType(typeName: String): String = {
val fixedTypeName = fixQualifiedName(StringUtils.normalizeSpace(typeName))
global.usedTypes.putIfAbsent(fixedTypeName, true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package io.joern.c2cpg.io

import io.joern.c2cpg.testfixtures.CCodeToCpgSuite
import io.joern.c2cpg.Config
import io.shiftleft.semanticcpg.language.*

class CodeDumperFromContentTest extends CCodeToCpgSuite {

private implicit val finder: NodeExtensionFinder = DefaultNodeExtensionFinder

"dumping code from content" should {
val cpg = code("""
|// A comment
|int my_func(int param1)
|{
| int x = foo(param1);
|}
|""".stripMargin).withConfig(Config().withDisableFileContent(false))

"allow one to dump a method node's source code from `File.contents`" in {
inside(cpg.method.nameExact("my_func").dumpRaw.l) {
case content :: Nil =>
content.linesIterator.map(_.strip).l shouldBe List(
"int my_func(int param1) /* <=== my_func */",
"{",
"int x = foo(param1);",
"}"
)
case content => fail(s"Expected exactly 1 content dump, but got: $content")
}
}
}

"code from method content" should {
val myFuncContent =
"""int my_func(int param1)
|{
| int x = foo(param1);
|}""".stripMargin

val cpg = code(s"""
|// A comment
|$myFuncContent;
|""".stripMargin).withConfig(Config().withDisableFileContent(false))

"allow one to dump a method node's source code from `Method.content`" in {
val List(content) = cpg.method.nameExact("my_func").content.l
content shouldBe myFuncContent
}
}

"code from typedecl content" should {
val myClassContent =
"""class Foo {
| public:
| int a;
| string b;
|}""".stripMargin

val cpg = code(
s"""
|// A comment
|$myClassContent;
|""".stripMargin,
"Foo.cpp"
).withConfig(Config().withDisableFileContent(false))

"allow one to dump a method node's source code from `TypeDecl.content`" in {
val List(content) = cpg.typeDecl.nameExact("Foo").content.l
content shouldBe myClassContent
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import io.shiftleft.semanticcpg.language._

import java.util.regex.Pattern

class CodeDumperTests extends CCodeToCpgSuite {
class CodeDumperFromFileTests extends CCodeToCpgSuite {

implicit val finder: NodeExtensionFinder = DefaultNodeExtensionFinder

Expand Down Expand Up @@ -54,9 +54,7 @@ class CodeDumperTests extends CCodeToCpgSuite {
val code = cpg.call.name("foo").dumpRaw.mkString("\n")
code should (
startWith("int")
and include regex (".*" + "int x = foo" + ".*" + Pattern.quote(
CodeDumper.arrow(Option("my_func")).toString
) + ".*")
and include regex (s".*int x = foo.*${Pattern.quote(CodeDumper.arrow(Option("my_func")).toString)}.*")
and endWith("}")
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ class FileTests extends CCodeToCpgSuite {
| struct my_struct { int x; };
|""".stripMargin)

"should contain two file nodes in total, both with order=0" in {
cpg.file.nameNot("<includes>").order.l shouldBe List(0, 0)
cpg.file.name(FileTraversal.UNKNOWN).size shouldBe 1
cpg.file.nameNot(FileTraversal.UNKNOWN, "<includes>").size shouldBe 1
"should contain the correct file nodes" in {
val List(fileTest, fileUnknown) = cpg.file.nameNot("<includes>").l
fileTest.name shouldBe "Test0.c"
fileTest.order shouldBe 1
fileUnknown.name shouldBe FileTraversal.UNKNOWN
fileUnknown.order shouldBe 0
}

"should contain exactly one placeholder file node with `name=\"<unknown>\"/order=0`" in {
Expand Down Expand Up @@ -50,12 +52,12 @@ class FileTests extends CCodeToCpgSuite {

"should allow traversing to namespaces" in {
val List(ns1, ns2, ns3) = cpg.file.namespaceBlock.l
ns1.filename shouldBe "<includes>"
ns1.fullName shouldBe "<includes>:<global>"
ns2.filename shouldBe "<unknown>"
ns2.fullName shouldBe "<global>"
ns3.filename shouldBe "Test0.c"
ns3.fullName shouldBe "Test0.c:<global>"
ns1.filename shouldBe "Test0.c"
ns1.fullName shouldBe "Test0.c:<global>"
ns2.filename shouldBe "<includes>"
ns2.fullName shouldBe "<includes>:<global>"
ns3.filename shouldBe "<unknown>"
ns3.fullName shouldBe "<global>"
cpg.file.namespace.name(NamespaceTraversal.globalNamespaceName).l.size shouldBe 3
}

Expand Down

0 comments on commit b4ff8b3

Please sign in to comment.