diff --git a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt index 16c7a90760..42faf11189 100644 --- a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt +++ b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt @@ -287,7 +287,18 @@ class GoLanguageFrontend(language: Language, ctx: Translatio desc } - objectType(parts.joinToString("; ", "struct{", "}")) + val name = parts.joinToString("; ", "struct{", "}") + + // Create an anonymous struct, this will add it to the scope manager. This is + // somewhat duplicate, but the easiest for now. We need to create it in the + // global + // scope to avoid namespace issues + var record = + scopeManager.withScope(scopeManager.globalScope) { + specificationHandler.buildRecordDeclaration(type, name) + } + + record.toType() } is GoStandardLibrary.Ast.InterfaceType -> { // Go allows to use anonymous interface as type. This is something we cannot diff --git a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/SpecificationHandler.kt b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/SpecificationHandler.kt index 0b0efae169..6f33ac1965 100644 --- a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/SpecificationHandler.kt +++ b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/SpecificationHandler.kt @@ -92,11 +92,21 @@ class SpecificationHandler(frontend: GoLanguageFrontend) : typeSpec: GoStandardLibrary.Ast.TypeSpec, structType: GoStandardLibrary.Ast.StructType ): RecordDeclaration { - val record = newRecordDeclaration(typeSpec.name.name, "struct", rawNode = typeSpec) + val record = buildRecordDeclaration(structType, typeSpec.name.name, typeSpec) // Make sure to register the type frontend.typeManager.registerType(record.toType()) + return record + } + + fun buildRecordDeclaration( + structType: GoStandardLibrary.Ast.StructType, + name: CharSequence, + typeSpec: GoStandardLibrary.Ast.TypeSpec? = null, + ): RecordDeclaration { + val record = newRecordDeclaration(name, "struct", rawNode = typeSpec) + frontend.scopeManager.enterScope(record) if (!structType.incomplete) { @@ -106,7 +116,7 @@ class SpecificationHandler(frontend: GoLanguageFrontend) : // A field can also have no name, which means that it is embedded. In this case, it // can be accessed by the local name of its type and therefore we name the field // accordingly - val name = + val fieldName = if (field.names.isEmpty()) { // Retrieve the root type local name type.root.name.localName @@ -114,7 +124,7 @@ class SpecificationHandler(frontend: GoLanguageFrontend) : field.names[0].name } - val decl = newFieldDeclaration(name, type, rawNode = field) + val decl = newFieldDeclaration(fieldName, type, rawNode = field) frontend.scopeManager.addDeclaration(decl) } } diff --git a/cpg-language-go/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/DeclarationTest.kt b/cpg-language-go/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/DeclarationTest.kt index eba1ce533c..e4f8f2de51 100644 --- a/cpg-language-go/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/DeclarationTest.kt +++ b/cpg-language-go/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/DeclarationTest.kt @@ -36,10 +36,8 @@ import de.fraunhofer.aisec.cpg.graph.byNameOrNull import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.statements.CompoundStatement import de.fraunhofer.aisec.cpg.graph.statements.ReturnStatement -import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression -import de.fraunhofer.aisec.cpg.graph.statements.expressions.DeclaredReferenceExpression -import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberExpression -import de.fraunhofer.aisec.cpg.graph.statements.expressions.UnaryOperator +import de.fraunhofer.aisec.cpg.graph.statements.expressions.* +import de.fraunhofer.aisec.cpg.graph.types.ObjectType import de.fraunhofer.aisec.cpg.graph.variables import java.nio.file.Path import kotlin.test.* @@ -150,16 +148,32 @@ class DeclarationTest { assertNotNull(newMyStruct) val body = newMyStruct.body as? CompoundStatement - assertNotNull(body) val `return` = body.statements.first() as? ReturnStatement - assertNotNull(`return`) val returnValue = `return`.returnValue as? UnaryOperator - assertNotNull(returnValue) + + val s = p.variables["p.s"] + assertNotNull(s) + + val type = s.type + assertIs(type) + + val record = type.recordDeclaration + assertNotNull(record) + + val init = (s.initializer as? ConstructExpression)?.arguments?.firstOrNull() + assertIs(init) + + val keyValue = init.initializers(0) + assertNotNull(keyValue) + + val key = keyValue.key + assertNotNull(key) + assertRefersTo(key, record.fields["field"]) } @Test diff --git a/cpg-language-go/src/test/resources/golang/struct.go b/cpg-language-go/src/test/resources/golang/struct.go index 5f0ee4296d..921fdf3644 100644 --- a/cpg-language-go/src/test/resources/golang/struct.go +++ b/cpg-language-go/src/test/resources/golang/struct.go @@ -33,3 +33,9 @@ func (s MyStruct) myOtherFunc() string { func NewMyStruct() *MyStruct { return &MyStruct{} } + +var s = struct { + field int +}{ + field: 1, +}