Skip to content

Go: add tests for dataflow relating to type aliasing #17400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package test

import (
"test.com/basename/pkg1"
"test.com/basename/pkg2"
)

// Tests that dataflow behaves as expected when loads and stores from a field traverse embeddings that use different type names.

// pkg2.IntStruct is an alias for pkg1.IntStruct
// Note referring to symbols in different packages is necessary so that Go will assign the fields the same name as well as the same type--
// for example, if we defined two aliases here named 'IntStruct1' and 'IntStruct2' and embedded them into two types,
// the types would be non-identical due to having a field implicitly named IntStruct1 and IntStruct2 respectively,
// even though syntactically it could be addressed without mentioning the field name.

type EmbedsPkg1IntStruct = struct{ pkg1.IntStruct }
type EmbedsPkg2IntStruct = struct{ pkg2.IntStruct }

func FEmbedded() {

x := source()
pkg1Struct := EmbedsPkg1IntStruct{pkg1.IntStruct{x}}

GEmbedded(&pkg1Struct)

}

func GEmbedded(pkg2Struct *EmbedsPkg2IntStruct) {

sink(pkg2Struct.Field) // $ hasValueFlow="selection of Field"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module test.com/basename

go 1.23.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pkg1

type IntStruct struct {
Field int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pkg2

import (
"test.com/basename/pkg1"
)

type IntStruct = pkg1.IntStruct
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package test

// Tests that dataflow behaves as expected when field loads and stores, and pointer accesses, go via
// types which are identical, but which use different aliases.

func source() int { return 0 }
func sink(value int) {}

type IntAlias = int
type IntStruct = struct{ field int }
type IntAliasStruct = struct{ field IntAlias }

func F() {

x := source()
intStruct := IntStruct{x}

G(&intStruct)

}

func G(intAliasStruct *IntAliasStruct) {

sink(intAliasStruct.field) // $ hasValueFlow="selection of field"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import go
import TestUtilities.InlineFlowTest
import DefaultFlowTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import go
import TestUtilities.InlineFlowTest
import DefaultFlowTest
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
callTargets
| test.go:48:2:48:24 | call to ImplementMe | test.go:12:1:12:69 | function declaration | ImplementMe |
| test.go:48:2:48:24 | call to ImplementMe | test.go:17:1:17:64 | function declaration | ImplementMe |
| test.go:48:2:48:24 | call to ImplementMe | test.go:24:1:24:53 | function declaration | ImplementMe |
| test.go:48:2:48:24 | call to ImplementMe | test.go:31:1:31:59 | function declaration | ImplementMe |
| test.go:48:2:48:24 | call to ImplementMe | test.go:38:1:38:71 | function declaration | ImplementMe |
| test.go:48:2:48:24 | call to ImplementMe | test.go:45:1:45:69 | function declaration | ImplementMe |
| test.go:20:70:20:83 | call to sink | test.go:15:1:15:45 | function declaration | sink |
| test.go:25:65:25:78 | call to sink | test.go:15:1:15:45 | function declaration | sink |
| test.go:32:54:32:67 | call to sink | test.go:15:1:15:45 | function declaration | sink |
| test.go:39:60:39:73 | call to sink | test.go:15:1:15:45 | function declaration | sink |
| test.go:46:72:46:85 | call to sink | test.go:15:1:15:45 | function declaration | sink |
| test.go:53:70:53:83 | call to sink | test.go:15:1:15:45 | function declaration | sink |
| test.go:56:14:56:21 | call to source | test.go:14:1:14:57 | function declaration | source |
| test.go:57:2:57:29 | call to ImplementMe | test.go:20:1:20:85 | function declaration | ImplementMe |
| test.go:57:2:57:29 | call to ImplementMe | test.go:25:1:25:80 | function declaration | ImplementMe |
| test.go:57:2:57:29 | call to ImplementMe | test.go:32:1:32:69 | function declaration | ImplementMe |
| test.go:57:2:57:29 | call to ImplementMe | test.go:39:1:39:75 | function declaration | ImplementMe |
| test.go:57:2:57:29 | call to ImplementMe | test.go:46:1:46:87 | function declaration | ImplementMe |
| test.go:57:2:57:29 | call to ImplementMe | test.go:53:1:53:85 | function declaration | ImplementMe |
#select
| file://:0:0:0:0 | basic interface type | file://:0:0:0:0 | basic interface type |
| file://:0:0:0:0 | basic interface type | test.go:10:6:10:10 | Impl1 |
| file://:0:0:0:0 | basic interface type | test.go:15:6:15:10 | Impl2 |
| file://:0:0:0:0 | basic interface type | test.go:20:6:20:10 | Impl3 |
| file://:0:0:0:0 | basic interface type | test.go:27:6:27:10 | Impl4 |
| file://:0:0:0:0 | basic interface type | test.go:34:6:34:10 | Impl5 |
| file://:0:0:0:0 | basic interface type | test.go:41:6:41:10 | Impl6 |
| file://:0:0:0:0 | basic interface type | test.go:18:6:18:10 | Impl1 |
| file://:0:0:0:0 | basic interface type | test.go:23:6:23:10 | Impl2 |
| file://:0:0:0:0 | basic interface type | test.go:28:6:28:10 | Impl3 |
| file://:0:0:0:0 | basic interface type | test.go:35:6:35:10 | Impl4 |
| file://:0:0:0:0 | basic interface type | test.go:42:6:42:10 | Impl5 |
| file://:0:0:0:0 | basic interface type | test.go:49:6:49:10 | Impl6 |
Original file line number Diff line number Diff line change
@@ -1,49 +1,58 @@
package intfs

// Tests that dataflow and interface implementation behave as expected when an interface
// is implemented using an identical type (in the structural sense defined by the go spec)
// where the two types differ at surface level, i.e. aliases must be followed to determine
// that they are identical.

type IntAlias = int

type Target = interface {
ImplementMe(callable func(struct{ x IntAlias }))
}

func source() func(struct{ x IntAlias }) { return nil }
func sink(fptr func(struct{ x IntAlias })) {}

// Simple direct implementation
type Impl1 struct{}

func (recv Impl1) ImplementMe(callable func(struct{ x IntAlias })) {}
func (recv Impl1) ImplementMe(callable func(struct{ x IntAlias })) { sink(callable) } // $ hasValueFlow="callable"

// Implementation via unaliasing
type Impl2 struct{}

func (recv Impl2) ImplementMe(callable func(struct{ x int })) {}
func (recv Impl2) ImplementMe(callable func(struct{ x int })) { sink(callable) } // $ hasValueFlow="callable"

// Implementation via top-level aliasing
type Impl3 struct{}

type Impl3Alias = func(struct{ x IntAlias })

func (recv Impl3) ImplementMe(callable Impl3Alias) {}
func (recv Impl3) ImplementMe(callable Impl3Alias) { sink(callable) } // $ hasValueFlow="callable"

// Implementation via aliasing the struct
type Impl4 struct{}

type Impl4Alias = struct{ x IntAlias }

func (recv Impl4) ImplementMe(callable func(Impl4Alias)) {}
func (recv Impl4) ImplementMe(callable func(Impl4Alias)) { sink(callable) } // $ hasValueFlow="callable"

// Implementation via aliasing the struct member
type Impl5 struct{}

type Impl5Alias = IntAlias

func (recv Impl5) ImplementMe(callable func(struct{ x Impl5Alias })) {}
func (recv Impl5) ImplementMe(callable func(struct{ x Impl5Alias })) { sink(callable) } // $ hasValueFlow="callable"

// Implementation via defining the method on an alias
type Impl6 struct{}

type Impl6Alias = Impl6

func (recv Impl6Alias) ImplementMe(callable func(struct{ x int })) {}
func (recv Impl6Alias) ImplementMe(callable func(struct{ x int })) { sink(callable) } // $ hasValueFlow="callable"

func Caller(target Target) {
target.ImplementMe(nil)
callable := source()
target.ImplementMe(callable)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package aliases

// Tests how interfaces defining identical types are represented in the database.

type IntAlias = int

type S1 = struct{ x int }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
distinctDefinedFs
| 2 |
declaredEntities
| methods.go:3:6:3:13 | IntAlias (1 declaration sites) |
| methods.go:5:6:5:7 | S1 (1 declaration sites) |
| methods.go:5:19:5:19 | x (2 declaration sites) |
| methods.go:6:6:6:7 | S2 (1 declaration sites) |
| methods.go:6:19:6:19 | x (2 declaration sites) |
| methods.go:8:6:8:7 | I1 (1 declaration sites) |
| methods.go:8:22:8:22 | F (2 declaration sites) |
| methods.go:9:6:9:7 | I2 (1 declaration sites) |
| methods.go:9:22:9:22 | F (2 declaration sites) |
| methods.go:10:6:10:7 | I3 (1 declaration sites) |
| methods.go:5:6:5:13 | IntAlias (1 declaration sites) |
| methods.go:7:6:7:7 | S1 (1 declaration sites) |
| methods.go:7:19:7:19 | x (2 declaration sites) |
| methods.go:8:6:8:7 | S2 (1 declaration sites) |
| methods.go:8:19:8:19 | x (2 declaration sites) |
| methods.go:10:6:10:7 | I1 (1 declaration sites) |
| methods.go:10:22:10:22 | F (2 declaration sites) |
| methods.go:11:6:11:7 | I4 (1 declaration sites) |
| methods.go:11:6:11:7 | I2 (1 declaration sites) |
| methods.go:11:22:11:22 | F (2 declaration sites) |
| methods.go:13:6:13:10 | Test1 (1 declaration sites) |
| methods.go:13:12:13:17 | param1 (1 declaration sites) |
| methods.go:13:23:13:28 | param2 (1 declaration sites) |
| methods.go:13:34:13:36 | arg (1 declaration sites) |
| methods.go:12:6:12:7 | I3 (1 declaration sites) |
| methods.go:12:22:12:22 | F (2 declaration sites) |
| methods.go:13:6:13:7 | I4 (1 declaration sites) |
| methods.go:13:22:13:22 | F (2 declaration sites) |
| methods.go:15:6:15:10 | Test1 (1 declaration sites) |
| methods.go:15:12:15:17 | param1 (1 declaration sites) |
| methods.go:15:23:15:28 | param2 (1 declaration sites) |
| methods.go:15:34:15:36 | arg (1 declaration sites) |
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package aliases

// Tests how defs and uses of fields are represented in the database
// when identical types are used.

type IntAlias = int

type S1 = struct{ x int }
Expand Down
52 changes: 26 additions & 26 deletions go/ql/test/library-tests/semmle/go/aliases/defsuses/test.expected
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
lowLevelDefs
| defsuses.go:3:6:3:13 | IntAlias | defsuses.go:3:6:3:13 | IntAlias (1 declaration sites) |
| defsuses.go:5:6:5:7 | S1 | defsuses.go:5:6:5:7 | S1 (1 declaration sites) |
| defsuses.go:5:19:5:19 | x | defsuses.go:5:19:5:19 | x (2 declaration sites) |
| defsuses.go:5:19:5:19 | x | defsuses.go:6:19:6:19 | x (2 declaration sites) |
| defsuses.go:6:6:6:7 | S2 | defsuses.go:6:6:6:7 | S2 (1 declaration sites) |
| defsuses.go:6:19:6:19 | x | defsuses.go:5:19:5:19 | x (2 declaration sites) |
| defsuses.go:6:19:6:19 | x | defsuses.go:6:19:6:19 | x (2 declaration sites) |
| defsuses.go:8:6:8:10 | Test1 | defsuses.go:8:6:8:10 | Test1 (1 declaration sites) |
| defsuses.go:9:2:9:4 | obj | defsuses.go:9:2:9:4 | obj (1 declaration sites) |
| defsuses.go:12:6:12:8 | ptr | defsuses.go:12:6:12:8 | ptr (1 declaration sites) |
| defsuses.go:6:6:6:13 | IntAlias | defsuses.go:6:6:6:13 | IntAlias (1 declaration sites) |
| defsuses.go:8:6:8:7 | S1 | defsuses.go:8:6:8:7 | S1 (1 declaration sites) |
| defsuses.go:8:19:8:19 | x | defsuses.go:8:19:8:19 | x (2 declaration sites) |
| defsuses.go:8:19:8:19 | x | defsuses.go:9:19:9:19 | x (2 declaration sites) |
| defsuses.go:9:6:9:7 | S2 | defsuses.go:9:6:9:7 | S2 (1 declaration sites) |
| defsuses.go:9:19:9:19 | x | defsuses.go:8:19:8:19 | x (2 declaration sites) |
| defsuses.go:9:19:9:19 | x | defsuses.go:9:19:9:19 | x (2 declaration sites) |
| defsuses.go:11:6:11:10 | Test1 | defsuses.go:11:6:11:10 | Test1 (1 declaration sites) |
| defsuses.go:12:2:12:4 | obj | defsuses.go:12:2:12:4 | obj (1 declaration sites) |
| defsuses.go:15:6:15:8 | ptr | defsuses.go:15:6:15:8 | ptr (1 declaration sites) |
lowLevelUses
| defsuses.go:3:17:3:19 | int | file://:0:0:0:0 | int (0 declaration sites) |
| defsuses.go:5:21:5:23 | int | file://:0:0:0:0 | int (0 declaration sites) |
| defsuses.go:6:21:6:28 | IntAlias | defsuses.go:3:6:3:13 | IntAlias (1 declaration sites) |
| defsuses.go:8:14:8:16 | int | file://:0:0:0:0 | int (0 declaration sites) |
| defsuses.go:9:9:9:10 | S1 | defsuses.go:5:6:5:7 | S1 (1 declaration sites) |
| defsuses.go:10:2:10:4 | obj | defsuses.go:9:2:9:4 | obj (1 declaration sites) |
| defsuses.go:10:6:10:6 | x | defsuses.go:5:19:5:19 | x (2 declaration sites) |
| defsuses.go:10:6:10:6 | x | defsuses.go:6:19:6:19 | x (2 declaration sites) |
| defsuses.go:12:11:12:12 | S2 | defsuses.go:6:6:6:7 | S2 (1 declaration sites) |
| defsuses.go:13:2:13:4 | ptr | defsuses.go:12:6:12:8 | ptr (1 declaration sites) |
| defsuses.go:13:9:13:11 | obj | defsuses.go:9:2:9:4 | obj (1 declaration sites) |
| defsuses.go:15:9:15:11 | ptr | defsuses.go:12:6:12:8 | ptr (1 declaration sites) |
| defsuses.go:15:13:15:13 | x | defsuses.go:5:19:5:19 | x (2 declaration sites) |
| defsuses.go:15:13:15:13 | x | defsuses.go:6:19:6:19 | x (2 declaration sites) |
| defsuses.go:6:17:6:19 | int | file://:0:0:0:0 | int (0 declaration sites) |
| defsuses.go:8:21:8:23 | int | file://:0:0:0:0 | int (0 declaration sites) |
| defsuses.go:9:21:9:28 | IntAlias | defsuses.go:6:6:6:13 | IntAlias (1 declaration sites) |
| defsuses.go:11:14:11:16 | int | file://:0:0:0:0 | int (0 declaration sites) |
| defsuses.go:12:9:12:10 | S1 | defsuses.go:8:6:8:7 | S1 (1 declaration sites) |
| defsuses.go:13:2:13:4 | obj | defsuses.go:12:2:12:4 | obj (1 declaration sites) |
| defsuses.go:13:6:13:6 | x | defsuses.go:8:19:8:19 | x (2 declaration sites) |
| defsuses.go:13:6:13:6 | x | defsuses.go:9:19:9:19 | x (2 declaration sites) |
| defsuses.go:15:11:15:12 | S2 | defsuses.go:9:6:9:7 | S2 (1 declaration sites) |
| defsuses.go:16:2:16:4 | ptr | defsuses.go:15:6:15:8 | ptr (1 declaration sites) |
| defsuses.go:16:9:16:11 | obj | defsuses.go:12:2:12:4 | obj (1 declaration sites) |
| defsuses.go:18:9:18:11 | ptr | defsuses.go:15:6:15:8 | ptr (1 declaration sites) |
| defsuses.go:18:13:18:13 | x | defsuses.go:8:19:8:19 | x (2 declaration sites) |
| defsuses.go:18:13:18:13 | x | defsuses.go:9:19:9:19 | x (2 declaration sites) |
distinctDefinedXs
| 1 |
distinctUsedXs
| 1 |
fieldUseUsePairs
| defsuses.go:10:6:10:6 | x | defsuses.go:15:13:15:13 | x |
| defsuses.go:15:13:15:13 | x | defsuses.go:10:6:10:6 | x |
| defsuses.go:13:6:13:6 | x | defsuses.go:18:13:18:13 | x |
| defsuses.go:18:13:18:13 | x | defsuses.go:13:6:13:6 | x |
Loading