diff --git a/ql/src/semmle/go/dataflow/SSA.qll b/ql/src/semmle/go/dataflow/SSA.qll index da3303d24b5..5801dd779f0 100644 --- a/ql/src/semmle/go/dataflow/SSA.qll +++ b/ql/src/semmle/go/dataflow/SSA.qll @@ -10,9 +10,7 @@ private import SsaImpl * declared in file scope. */ class SsaSourceVariable extends LocalVariable { - SsaSourceVariable() { - not getScope() instanceof FileScope - } + SsaSourceVariable() { not getScope() instanceof FileScope } /** * Holds if there may be indirect references of this variable that are not covered by `getAReference()`. @@ -339,6 +337,20 @@ class SsaWithFields extends TSsaWithFields { exists(SsaWithFields base, Field f | this = TStep(base, f) | result = base + "." + f.getName()) } + /** + * Gets the qualified name of the source variable or variable and fields that this represents. + * + * For example, for an SSA variable that represents the field `a.b`, this would get the string + * `"a.b"`. + */ + string getQualifiedName() { + exists(SsaVariable v | this = TRoot(v) and result = v.getSourceVariable().getName()) + or + exists(SsaWithFields base, Field f | this = TStep(base, f) | + result = base.getQualifiedName() + "." + f.getName() + ) + } + /** * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected b/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected index 0ac0dc33fe7..f330cabad50 100644 --- a/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/DefUse.expected @@ -26,5 +26,9 @@ | main.go:82:25:82:25 | implicit read of b | main.go:82:25:82:25 | definition of b | main.go:82:25:82:25 | b | | main.go:84:9:84:9 | x | main.go:83:2:83:2 | definition of x | main.go:83:2:83:2 | x | | main.go:84:15:84:15 | x | main.go:83:2:83:2 | definition of x | main.go:83:2:83:2 | x | -| main.go:94:2:94:8 | wrapper | main.go:92:22:92:28 | definition of wrapper | main.go:92:22:92:28 | wrapper | -| main.go:97:9:97:9 | x | main.go:94:2:96:3 | capture variable x | main.go:93:2:93:2 | x | +| main.go:97:2:97:8 | wrapper | main.go:95:22:95:28 | definition of wrapper | main.go:95:22:95:28 | wrapper | +| main.go:100:9:100:9 | x | main.go:97:2:99:3 | capture variable x | main.go:96:2:96:2 | x | +| main.go:117:2:117:2 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | +| main.go:119:12:119:12 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | +| main.go:119:17:119:17 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | +| main.go:119:24:119:24 | p | main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | main.go:110:6:110:6 | p | diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected b/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected index faca455b364..3be49ec06f7 100644 --- a/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/SsaDefinition.expected @@ -32,7 +32,10 @@ | main.go:82:25:82:25 | definition of b | | main.go:83:2:83:2 | definition of x | | main.go:84:5:84:5 | definition of a | -| main.go:92:22:92:28 | definition of wrapper | -| main.go:93:2:93:2 | definition of x | -| main.go:94:2:96:3 | capture variable x | -| main.go:95:3:95:3 | definition of x | +| main.go:95:22:95:28 | definition of wrapper | +| main.go:96:2:96:2 | definition of x | +| main.go:97:2:99:3 | capture variable x | +| main.go:98:3:98:3 | definition of x | +| main.go:112:3:112:3 | definition of p | +| main.go:114:3:114:3 | definition of p | +| main.go:117:2:117:2 | p = phi(def@112:3, def@114:3) | diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected b/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected new file mode 100644 index 00000000000..bcaf5bd749d --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.expected @@ -0,0 +1,46 @@ +| main.go:13:6:13:6 | (def@13:6) | x | +| main.go:14:2:14:2 | (def@14:2) | y | +| main.go:17:3:17:3 | (def@17:3) | y | +| main.go:19:2:19:2 | (phi@19:2) | y | +| main.go:21:3:21:3 | (def@21:3) | x | +| main.go:23:2:23:2 | (phi@23:2) | x | +| main.go:26:10:26:10 | (def@26:10) | x | +| main.go:27:2:27:2 | (def@27:2) | a | +| main.go:27:5:27:5 | (def@27:5) | b | +| main.go:29:3:29:3 | (def@29:3) | a | +| main.go:29:6:29:6 | (def@29:6) | b | +| main.go:31:9:31:9 | (phi@31:9) | a | +| main.go:31:9:31:9 | (phi@31:9) | b | +| main.go:34:11:34:11 | (def@34:11) | x | +| main.go:39:2:39:2 | (def@39:2) | x | +| main.go:40:2:40:4 | (def@40:2) | ptr | +| main.go:48:2:48:7 | (def@48:2) | result | +| main.go:52:14:52:19 | (def@52:14) | result | +| main.go:57:6:57:6 | (def@57:6) | x | +| main.go:58:6:58:6 | (phi@58:6) | x | +| main.go:59:3:59:3 | (def@59:3) | x | +| main.go:63:2:63:2 | (def@63:2) | y | +| main.go:64:6:64:6 | (def@64:6) | i | +| main.go:64:16:64:18 | (def@64:16) | i | +| main.go:65:6:65:6 | (phi@65:6) | i | +| main.go:65:6:65:6 | (phi@65:6) | y | +| main.go:68:3:68:3 | (def@68:3) | y | +| main.go:73:6:73:6 | (def@73:6) | i | +| main.go:73:16:73:18 | (def@73:16) | i | +| main.go:74:3:74:3 | (def@74:3) | z | +| main.go:74:3:74:3 | (phi@74:3) | i | +| main.go:82:25:82:25 | (def@82:25) | b | +| main.go:83:2:83:2 | (def@83:2) | x | +| main.go:84:5:84:5 | (def@84:5) | a | +| main.go:95:22:95:28 | (def@95:22) | wrapper | +| main.go:95:22:95:28 | (def@95:22).s | wrapper.s | +| main.go:96:2:96:2 | (def@96:2) | x | +| main.go:97:2:99:3 | (capture@97:2) | x | +| main.go:98:3:98:3 | (def@98:3) | x | +| main.go:112:3:112:3 | (def@112:3) | p | +| main.go:114:3:114:3 | (def@114:3) | p | +| main.go:117:2:117:2 | (phi@117:2) | p | +| main.go:117:2:117:2 | (phi@117:2).a | p.a | +| main.go:117:2:117:2 | (phi@117:2).b | p.b | +| main.go:117:2:117:2 | (phi@117:2).b.a | p.b.a | +| main.go:117:2:117:2 | (phi@117:2).c | p.c | diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.ql b/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.ql new file mode 100644 index 00000000000..a2862a72697 --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/SsaWithFields.ql @@ -0,0 +1,4 @@ +import go + +from SsaWithFields v +select v, v.getQualifiedName() diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected b/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected index aa083e6740e..edc2e5cc22d 100644 --- a/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected @@ -28,7 +28,20 @@ | main.go:83:2:83:2 | assignment to x | main.go:83:2:83:2 | x | main.go:83:7:83:8 | 23 | | main.go:84:2:84:2 | assignment to x | main.go:83:2:83:2 | x | main.go:84:9:84:12 | ...+... | | main.go:84:5:84:5 | assignment to a | main.go:82:18:82:18 | a | main.go:84:15:84:15 | x | -| main.go:90:15:90:16 | initialization of cb | main.go:90:15:90:16 | cb | main.go:90:15:90:16 | argument corresponding to cb | -| main.go:92:22:92:28 | initialization of wrapper | main.go:92:22:92:28 | wrapper | main.go:92:22:92:28 | argument corresponding to wrapper | -| main.go:93:2:93:2 | assignment to x | main.go:93:2:93:2 | x | main.go:93:7:93:7 | 0 | -| main.go:95:3:95:3 | assignment to x | main.go:93:2:93:2 | x | main.go:95:7:95:7 | 1 | +| main.go:93:15:93:16 | initialization of cb | main.go:93:15:93:16 | cb | main.go:93:15:93:16 | argument corresponding to cb | +| main.go:95:22:95:28 | initialization of wrapper | main.go:95:22:95:28 | wrapper | main.go:95:22:95:28 | argument corresponding to wrapper | +| main.go:96:2:96:2 | assignment to x | main.go:96:2:96:2 | x | main.go:96:7:96:7 | 0 | +| main.go:98:3:98:3 | assignment to x | main.go:96:2:96:2 | x | main.go:98:7:98:7 | 1 | +| main.go:110:6:110:6 | assignment to p | main.go:110:6:110:6 | p | main.go:110:6:110:6 | zero value for p | +| main.go:112:3:112:3 | assignment to p | main.go:110:6:110:6 | p | main.go:112:7:112:24 | composite literal | +| main.go:112:9:112:9 | init of 2 | main.go:104:2:104:2 | a | main.go:112:9:112:9 | 2 | +| main.go:112:12:112:18 | init of composite literal | main.go:105:2:105:2 | b | main.go:112:12:112:18 | composite literal | +| main.go:112:14:112:14 | init of 1 | main.go:89:2:89:2 | a | main.go:112:14:112:14 | 1 | +| main.go:112:17:112:17 | init of 5 | main.go:90:2:90:2 | b | main.go:112:17:112:17 | 5 | +| main.go:112:21:112:23 | init of 'n' | main.go:106:2:106:2 | c | main.go:112:21:112:23 | 'n' | +| main.go:114:3:114:3 | assignment to p | main.go:110:6:110:6 | p | main.go:114:7:114:24 | composite literal | +| main.go:114:9:114:9 | init of 3 | main.go:104:2:104:2 | a | main.go:114:9:114:9 | 3 | +| main.go:114:12:114:18 | init of composite literal | main.go:105:2:105:2 | b | main.go:114:12:114:18 | composite literal | +| main.go:114:14:114:14 | init of 4 | main.go:89:2:89:2 | a | main.go:114:14:114:14 | 4 | +| main.go:114:17:114:17 | init of 5 | main.go:90:2:90:2 | b | main.go:114:17:114:17 | 5 | +| main.go:114:21:114:23 | init of '2' | main.go:106:2:106:2 | c | main.go:114:21:114:23 | '2' | diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected b/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected index e38be3b04e4..332f859f051 100644 --- a/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/VarUses.expected @@ -26,6 +26,15 @@ | main.go:82:25:82:25 | implicit read of b | main.go:82:25:82:25 | b | | main.go:84:9:84:9 | x | main.go:83:2:83:2 | x | | main.go:84:15:84:15 | x | main.go:83:2:83:2 | x | -| main.go:94:2:94:8 | wrapper | main.go:92:22:92:28 | wrapper | -| main.go:94:2:94:10 | selection of s | main.go:92:38:92:38 | s | -| main.go:97:9:97:9 | x | main.go:93:2:93:2 | x | +| main.go:97:2:97:8 | wrapper | main.go:95:22:95:28 | wrapper | +| main.go:97:2:97:10 | selection of s | main.go:95:38:95:38 | s | +| main.go:100:9:100:9 | x | main.go:96:2:96:2 | x | +| main.go:117:2:117:2 | p | main.go:110:6:110:6 | p | +| main.go:117:2:117:4 | selection of b | main.go:105:2:105:2 | b | +| main.go:119:12:119:12 | p | main.go:110:6:110:6 | p | +| main.go:119:12:119:14 | selection of a | main.go:104:2:104:2 | a | +| main.go:119:17:119:17 | p | main.go:110:6:110:6 | p | +| main.go:119:17:119:19 | selection of b | main.go:105:2:105:2 | b | +| main.go:119:17:119:21 | selection of a | main.go:89:2:89:2 | a | +| main.go:119:24:119:24 | p | main.go:110:6:110:6 | p | +| main.go:119:24:119:26 | selection of c | main.go:106:2:106:2 | c | diff --git a/ql/test/library-tests/semmle/go/dataflow/SSA/main.go b/ql/test/library-tests/semmle/go/dataflow/SSA/main.go index 8c20bb6da2f..cda85fdfc66 100644 --- a/ql/test/library-tests/semmle/go/dataflow/SSA/main.go +++ b/ql/test/library-tests/semmle/go/dataflow/SSA/main.go @@ -85,7 +85,10 @@ func multiRes() (a int, b float32) { return } -type s struct{} +type s struct { + a int + b int +} func (*s) foo(cb func()) {} @@ -96,3 +99,22 @@ func updateInClosure(wrapper struct{ s }) int { }) return x } + +type t struct { + a int + b s + c rune +} + +func ssaPhi() { + var p t + if cond() { + p = t{2, s{1, 5}, 'n'} + } else { + p = t{3, s{4, 5}, '2'} + } + + p.b.foo(func() {}) + + fmt.Print(p.a, p.b.a, p.c) +}