Skip to content

Commit

Permalink
Resolving anonymous structs
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Aug 27, 2023
1 parent 489913f commit c78a2ec
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,18 @@ class GoLanguageFrontend(language: Language<GoLanguageFrontend>, 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -106,15 +116,15 @@ 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
} else {
field.names[0].name
}

val decl = newFieldDeclaration(name, type, rawNode = field)
val decl = newFieldDeclaration(fieldName, type, rawNode = field)
frontend.scopeManager.addDeclaration(decl)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -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<ObjectType>(type)

val record = type.recordDeclaration
assertNotNull(record)

val init = (s.initializer as? ConstructExpression)?.arguments?.firstOrNull()
assertIs<InitializerListExpression>(init)

val keyValue = init.initializers<KeyValueExpression>(0)
assertNotNull(keyValue)

val key = keyValue.key
assertNotNull(key)
assertRefersTo(key, record.fields["field"])
}

@Test
Expand Down
6 changes: 6 additions & 0 deletions cpg-language-go/src/test/resources/golang/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ func (s MyStruct) myOtherFunc() string {
func NewMyStruct() *MyStruct {
return &MyStruct{}
}

var s = struct {
field int
}{
field: 1,
}

0 comments on commit c78a2ec

Please sign in to comment.