diff --git a/ql/src/semmle/go/Scopes.qll b/ql/src/semmle/go/Scopes.qll index f04c6fc685e..e081d7270ae 100644 --- a/ql/src/semmle/go/Scopes.qll +++ b/ql/src/semmle/go/Scopes.qll @@ -427,21 +427,40 @@ class Method extends Function { ) } - /** - * Holds if this method has name `m` and its receiver base type has qualified name `tp`. - */ - override predicate hasQualifiedName(string tp, string m) { - tp = getReceiverBaseType().getQualifiedName() and - m = getName() + /** Holds if this method has name `m` and belongs to the method set of type `tp` or `*tp`. */ + private predicate isIn(NamedType tp, string m) { + this = tp.getMethod(m) or + this = tp.getPointerType().getMethod(m) } /** - * Holds if this method has name `m` and its receiver base type is declared in package `pkg` and - * has name `tp`. + * Holds if this method has name `m` and belongs to the method set of a type `T` or `*T` where + * `T` has qualified name `tp`. + * + * Note that `meth.hasQualifiedName(tp, m)` is almost, but not quite, equivalent to + * `exists(Type t | tp = t.getQualifiedName() and meth = t.getMethod(m))`: the latter + * distinguishes between the method sets of `T` and `*T`, while the former does not. + */ + override predicate hasQualifiedName(string tp, string m) { + exists(NamedType t | + this.isIn(t, m) and + tp = t.getQualifiedName() + ) + } + + /** + * Holds if this method has name `m` and belongs to the method set of a type `T` or `*T` where + * `T` is declared in package `pkg` and has name `tp`. + * + * Note that `meth.hasQualifiedName(pkg, tp, m)` is almost, but not quite, equivalent to + * `exists(Type t | t.hasQualifiedName(pkg, tp) and meth = t.getMethod(m))`: the latter + * distinguishes between the method sets of `T` and `*T`, while the former does not. */ predicate hasQualifiedName(string pkg, string tp, string m) { - getReceiverBaseType().hasQualifiedName(pkg, tp) and - m = getName() + exists(NamedType t | + this.isIn(t, m) and + t.hasQualifiedName(pkg, tp) + ) } /** diff --git a/ql/src/semmle/go/Types.qll b/ql/src/semmle/go/Types.qll index c341656621b..ad87b688fea 100644 --- a/ql/src/semmle/go/Types.qll +++ b/ql/src/semmle/go/Types.qll @@ -40,6 +40,9 @@ class Type extends @type { /** * Gets the method `m` belonging to the method set of this type, if any. + * + * Note that this predicate never has a result for struct types. Methods are associated + * with the corresponding named type instead. */ Method getMethod(string m) { result.getReceiverType() = this and @@ -441,11 +444,29 @@ class PointerType extends @pointertype, CompositeType { override Package getPackage() { result = this.getBaseType().getPackage() } override Method getMethod(string m) { - // https://golang.org/ref/spec#Method_sets: "the method set of a pointer type *T is - // the set of all methods declared with receiver *T or T" result = CompositeType.super.getMethod(m) or + // https://golang.org/ref/spec#Method_sets: "the method set of a pointer type *T is + // the set of all methods declared with receiver *T or T" result = getBaseType().getMethod(m) + or + // promoted methods from embedded types + exists(StructType s, Type embedded | + s = getBaseType().(NamedType).getUnderlyingType() and + s.hasOwnField(_, _, embedded, true) and + // ensure that `m` can be promoted + not s.hasOwnField(_, m, _, _) and + not exists(Method m2 | m2.getReceiverBaseType() = getBaseType() and m2.getName() = m) + | + result = embedded.getMethod(m) + or + // If S contains an embedded field T, the method set of *S includes promoted methods with receiver T or T* + not embedded instanceof PointerType and + result = embedded.getPointerType().getMethod(m) + or + // If S contains an embedded field *T, the method set of *S includes promoted methods with receiver T or *T + result = embedded.(PointerType).getBaseType().getMethod(m) + ) } override string pp() { result = "* " + getBaseType().pp() } @@ -566,12 +587,6 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { /** A named type. */ class NamedType extends @namedtype, CompositeType { - /** Gets a method with name `m` defined on this type. */ - MethodDecl getMethodDecl(string m) { - result.getName() = m and - this = result.getReceiverBaseType() - } - /** Gets the type which this type is defined to be. */ Type getBaseType() { underlying_type(this, result) } @@ -580,6 +595,21 @@ class NamedType extends @namedtype, CompositeType { or methodhosts(result, this) and result.getName() = m + or + // handle promoted methods + exists(StructType s, Type embedded | + s = getBaseType() and + s.hasOwnField(_, _, embedded, true) and + // ensure `m` can be promoted + not s.hasOwnField(_, m, _, _) and + not exists(Method m2 | m2.getReceiverType() = this and m2.getName() = m) + | + // If S contains an embedded field T, the method set of S includes promoted methods with receiver T + result = embedded.getMethod(m) + or + // If S contains an embedded field *T, the method set of S includes promoted methods with receiver T or *T + result = embedded.(PointerType).getBaseType().getMethod(m) + ) } override Type getUnderlyingType() { result = getBaseType().getUnderlyingType() } diff --git a/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected b/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected index cef4e23d814..a8f42259f7a 100644 --- a/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected +++ b/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected @@ -1,3 +1,9 @@ +| pkg1/embedding.go:19:23:19:26 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/embedding.go:22:27:22:30 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/embedding.go:25:24:25:31 | embedder | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/embedding.go:28:24:28:31 | embedder | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/embedding.go:36:2:36:5 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/embedding.go:37:2:37:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/tst.go:4:2:4:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/tst.go:5:2:5:4 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/tst.go:6:2:6:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | diff --git a/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected b/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected index 2fc41465de9..92dba057c92 100644 --- a/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected +++ b/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected @@ -1,3 +1,13 @@ +| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder | base | +| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder2 | base | +| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder3 | base | +| pkg1/embedding.go:22:27:22:30 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.ptrembedder | base | +| pkg1/embedding.go:25:24:25:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder2 | embedder | +| pkg1/embedding.go:25:24:25:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder3 | embedder | +| pkg1/embedding.go:28:24:28:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder2 | embedder | +| pkg1/embedding.go:28:24:28:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder3 | embedder | +| pkg1/embedding.go:36:2:36:5 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder4 | base | +| pkg1/embedding.go:37:2:37:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder4 | f | | pkg1/tst.go:4:2:4:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | f | | pkg1/tst.go:5:2:5:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | Foo | | pkg1/tst.go:6:2:6:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | Bar | diff --git a/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected b/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected index c1b3243b1e3..4df101eb01c 100644 --- a/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected +++ b/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected @@ -1,3 +1,13 @@ +| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | base | +| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | base | +| pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | base | +| pkg1/embedding.go:22:27:22:30 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | ptrembedder | base | +| pkg1/embedding.go:25:24:25:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | embedder | +| pkg1/embedding.go:25:24:25:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | embedder | +| pkg1/embedding.go:28:24:28:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | embedder | +| pkg1/embedding.go:28:24:28:31 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | embedder | +| pkg1/embedding.go:36:2:36:5 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder4 | base | +| pkg1/embedding.go:37:2:37:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder4 | f | | pkg1/tst.go:4:2:4:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | f | | pkg1/tst.go:5:2:5:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | Foo | | pkg1/tst.go:6:2:6:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | Bar | diff --git a/ql/test/library-tests/semmle/go/Types/MethodCount.expected b/ql/test/library-tests/semmle/go/Types/MethodCount.expected index 9e04da9afc6..aa600fe82dc 100644 --- a/ql/test/library-tests/semmle/go/Types/MethodCount.expected +++ b/ql/test/library-tests/semmle/go/Types/MethodCount.expected @@ -1,4 +1,10 @@ | * Foo | 1 | +| * base | 2 | +| * embedder | 2 | +| * embedder2 | 2 | +| * embedder3 | 2 | +| * embedder4 | 1 | +| * ptrembedder | 2 | | A | 1 | | A2 | 1 | | AC | 3 | @@ -7,3 +13,11 @@ | B | 2 | | C | 2 | | Foo | 1 | +| T | 1 | +| T3 | 1 | +| T4 | 1 | +| base | 1 | +| embedder | 1 | +| embedder2 | 1 | +| embedder3 | 1 | +| ptrembedder | 2 | diff --git a/ql/test/library-tests/semmle/go/Types/MethodDecls.expected b/ql/test/library-tests/semmle/go/Types/MethodDecls.expected deleted file mode 100644 index 6dac3679096..00000000000 --- a/ql/test/library-tests/semmle/go/Types/MethodDecls.expected +++ /dev/null @@ -1 +0,0 @@ -| Foo | half | pkg1/tst.go:33:1:35:1 | function declaration | diff --git a/ql/test/library-tests/semmle/go/Types/MethodDecls.ql b/ql/test/library-tests/semmle/go/Types/MethodDecls.ql deleted file mode 100644 index c0fb55f3b19..00000000000 --- a/ql/test/library-tests/semmle/go/Types/MethodDecls.ql +++ /dev/null @@ -1,4 +0,0 @@ -import go - -from NamedType t, string m -select t, m, t.getMethodDecl(m) diff --git a/ql/test/library-tests/semmle/go/Types/MethodTypes.expected b/ql/test/library-tests/semmle/go/Types/MethodTypes.expected index 44a89c85994..fd509da3c0d 100644 --- a/ql/test/library-tests/semmle/go/Types/MethodTypes.expected +++ b/ql/test/library-tests/semmle/go/Types/MethodTypes.expected @@ -13,3 +13,8 @@ | T | half | func() Foo | | T3 | half | func() Foo | | T4 | half | func() Foo | +| embedder | f | func() int | +| embedder2 | f | func() int | +| embedder3 | f | func() int | +| ptrembedder | f | func() int | +| ptrembedder | g | func() int | diff --git a/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected new file mode 100644 index 00000000000..415f31ef447 --- /dev/null +++ b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected @@ -0,0 +1,27 @@ +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | base | f | +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | f | +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | f | +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | ptrembedder | f | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | base | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder4 | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | ptrembedder | g | +| pkg1/embedding.go:30:18:30:18 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | f | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | A | m | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AC | m | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AEmbedded | m | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AExtended | m | +| pkg1/interfaces.go:8:2:8:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | B | m | +| pkg1/interfaces.go:9:2:9:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | B | n | +| pkg1/interfaces.go:13:2:13:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AC | n | +| pkg1/interfaces.go:13:2:13:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | C | n | +| pkg1/interfaces.go:14:2:14:2 | o | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AC | o | +| pkg1/interfaces.go:14:2:14:2 | o | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | C | o | +| pkg1/interfaces.go:28:2:28:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AExtended | n | +| pkg1/interfaces.go:32:2:32:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | A2 | m | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | half | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | half | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | half | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | half | diff --git a/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.ql b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.ql new file mode 100644 index 00000000000..b8df1364fc1 --- /dev/null +++ b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.ql @@ -0,0 +1,5 @@ +import go + +from Method meth, string pkg, string tp, string m +where meth.hasQualifiedName(pkg, tp, m) +select meth.getDeclaration(), pkg, tp, m diff --git a/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected new file mode 100644 index 00000000000..415f31ef447 --- /dev/null +++ b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected @@ -0,0 +1,27 @@ +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | base | f | +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | f | +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | f | +| pkg1/embedding.go:10:13:10:13 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | ptrembedder | f | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | base | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder4 | g | +| pkg1/embedding.go:14:14:14:14 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | ptrembedder | g | +| pkg1/embedding.go:30:18:30:18 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | f | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | A | m | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AC | m | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AEmbedded | m | +| pkg1/interfaces.go:4:2:4:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AExtended | m | +| pkg1/interfaces.go:8:2:8:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | B | m | +| pkg1/interfaces.go:9:2:9:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | B | n | +| pkg1/interfaces.go:13:2:13:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AC | n | +| pkg1/interfaces.go:13:2:13:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | C | n | +| pkg1/interfaces.go:14:2:14:2 | o | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AC | o | +| pkg1/interfaces.go:14:2:14:2 | o | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | C | o | +| pkg1/interfaces.go:28:2:28:2 | n | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | AExtended | n | +| pkg1/interfaces.go:32:2:32:2 | m | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | A2 | m | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | half | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | half | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | half | +| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | half | diff --git a/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.ql b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.ql new file mode 100644 index 00000000000..b8df1364fc1 --- /dev/null +++ b/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.ql @@ -0,0 +1,5 @@ +import go + +from Method meth, string pkg, string tp, string m +where meth.hasQualifiedName(pkg, tp, m) +select meth.getDeclaration(), pkg, tp, m diff --git a/ql/test/library-tests/semmle/go/Types/Methods.expected b/ql/test/library-tests/semmle/go/Types/Methods.expected index 6868fc18b9d..b051d1b66a6 100644 --- a/ql/test/library-tests/semmle/go/Types/Methods.expected +++ b/ql/test/library-tests/semmle/go/Types/Methods.expected @@ -1,4 +1,15 @@ | * Foo | half | pkg1/tst.go:33:16:33:19 | half | +| * base | f | pkg1/embedding.go:10:13:10:13 | f | +| * base | g | pkg1/embedding.go:14:14:14:14 | g | +| * embedder | f | pkg1/embedding.go:10:13:10:13 | f | +| * embedder | g | pkg1/embedding.go:14:14:14:14 | g | +| * embedder2 | f | pkg1/embedding.go:10:13:10:13 | f | +| * embedder2 | g | pkg1/embedding.go:14:14:14:14 | g | +| * embedder3 | f | pkg1/embedding.go:30:18:30:18 | f | +| * embedder3 | g | pkg1/embedding.go:14:14:14:14 | g | +| * embedder4 | g | pkg1/embedding.go:14:14:14:14 | g | +| * ptrembedder | f | pkg1/embedding.go:10:13:10:13 | f | +| * ptrembedder | g | pkg1/embedding.go:14:14:14:14 | g | | A | m | pkg1/interfaces.go:4:2:4:2 | m | | A2 | m | pkg1/interfaces.go:32:2:32:2 | m | | AC | m | pkg1/interfaces.go:4:2:4:2 | m | @@ -12,3 +23,12 @@ | C | n | pkg1/interfaces.go:13:2:13:2 | n | | C | o | pkg1/interfaces.go:14:2:14:2 | o | | Foo | half | pkg1/tst.go:33:16:33:19 | half | +| T | half | pkg1/tst.go:33:16:33:19 | half | +| T3 | half | pkg1/tst.go:33:16:33:19 | half | +| T4 | half | pkg1/tst.go:33:16:33:19 | half | +| base | f | pkg1/embedding.go:10:13:10:13 | f | +| embedder | f | pkg1/embedding.go:10:13:10:13 | f | +| embedder2 | f | pkg1/embedding.go:10:13:10:13 | f | +| embedder3 | f | pkg1/embedding.go:30:18:30:18 | f | +| ptrembedder | f | pkg1/embedding.go:10:13:10:13 | f | +| ptrembedder | g | pkg1/embedding.go:14:14:14:14 | g | diff --git a/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected b/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected index e4b851704f6..2721d0e6bbc 100644 --- a/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected +++ b/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected @@ -13,3 +13,9 @@ | T2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | | T3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | | T4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | +| base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.base | +| embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder | +| embedder2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder2 | +| embedder3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder3 | +| embedder4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder4 | +| ptrembedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.ptrembedder | diff --git a/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected b/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected index 6f7f3920bdf..48855348e90 100644 --- a/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected +++ b/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected @@ -1,6 +1,10 @@ | main.go:5:1:5:30 | function declaration | 1 | | main.go:7:1:9:1 | function declaration | 2 | | main.go:11:1:11:14 | function declaration | 0 | +| pkg1/embedding.go:10:1:12:1 | function declaration | 0 | +| pkg1/embedding.go:14:1:16:1 | function declaration | 0 | +| pkg1/embedding.go:30:1:32:1 | function declaration | 0 | +| pkg1/embedding.go:40:1:61:1 | function declaration | 0 | | pkg1/tst.go:33:1:35:1 | function declaration | 0 | | pkg1/tst.go:37:1:37:26 | function declaration | 1 | | pkg1/tst.go:39:1:57:1 | function declaration | 2 | diff --git a/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected b/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected index 3b37704f7b3..a90412830d7 100644 --- a/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected +++ b/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected @@ -1,6 +1,10 @@ | main.go:5:1:5:30 | function declaration | 0 | | main.go:7:1:9:1 | function declaration | 2 | | main.go:11:1:11:14 | function declaration | 0 | +| pkg1/embedding.go:10:1:12:1 | function declaration | 1 | +| pkg1/embedding.go:14:1:16:1 | function declaration | 1 | +| pkg1/embedding.go:30:1:32:1 | function declaration | 1 | +| pkg1/embedding.go:40:1:61:1 | function declaration | 0 | | pkg1/tst.go:33:1:35:1 | function declaration | 1 | | pkg1/tst.go:37:1:37:26 | function declaration | 0 | | pkg1/tst.go:39:1:57:1 | function declaration | 0 | diff --git a/ql/test/library-tests/semmle/go/Types/StructFields.expected b/ql/test/library-tests/semmle/go/Types/StructFields.expected index 2f8ed48bbae..18363fb3e27 100644 --- a/ql/test/library-tests/semmle/go/Types/StructFields.expected +++ b/ql/test/library-tests/semmle/go/Types/StructFields.expected @@ -19,3 +19,15 @@ | T4 | pkg1/tst.go:19:9:22:1 | struct type | Foo | * Foo | | T4 | pkg1/tst.go:19:9:22:1 | struct type | flag | bool | | T4 | pkg1/tst.go:19:9:22:1 | struct type | val | int | +| embedder | pkg1/embedding.go:19:15:19:28 | struct type | base | base | +| embedder2 | pkg1/embedding.go:25:16:25:33 | struct type | base | base | +| embedder2 | pkg1/embedding.go:25:16:25:33 | struct type | embedder | embedder | +| embedder2 | pkg1/embedding.go:28:16:28:33 | struct type | base | base | +| embedder2 | pkg1/embedding.go:28:16:28:33 | struct type | embedder | embedder | +| embedder3 | pkg1/embedding.go:25:16:25:33 | struct type | base | base | +| embedder3 | pkg1/embedding.go:25:16:25:33 | struct type | embedder | embedder | +| embedder3 | pkg1/embedding.go:28:16:28:33 | struct type | base | base | +| embedder3 | pkg1/embedding.go:28:16:28:33 | struct type | embedder | embedder | +| embedder4 | pkg1/embedding.go:35:16:38:1 | struct type | base | base | +| embedder4 | pkg1/embedding.go:35:16:38:1 | struct type | f | int | +| ptrembedder | pkg1/embedding.go:22:18:22:32 | struct type | base | * base | diff --git a/ql/test/library-tests/semmle/go/Types/Types.expected b/ql/test/library-tests/semmle/go/Types/Types.expected index 5f298953227..04cce22549d 100644 --- a/ql/test/library-tests/semmle/go/Types/Types.expected +++ b/ql/test/library-tests/semmle/go/Types/Types.expected @@ -13,3 +13,9 @@ | T2 | T2 | | T3 | T3 | | T4 | T4 | +| base | base | +| embedder | embedder | +| embedder2 | embedder2 | +| embedder3 | embedder3 | +| embedder4 | embedder4 | +| ptrembedder | ptrembedder | diff --git a/ql/test/library-tests/semmle/go/Types/pkg1/embedding.go b/ql/test/library-tests/semmle/go/Types/pkg1/embedding.go new file mode 100644 index 00000000000..a322b68697c --- /dev/null +++ b/ql/test/library-tests/semmle/go/Types/pkg1/embedding.go @@ -0,0 +1,61 @@ +package pkg1 + +import ( + "fmt" +) + +// `base` and `*base` have method `f`; `*base` also has method `g` +type base struct{} + +func (base) f() int { + return 1 +} + +func (*base) g() int { + return 2 +} + +// `embedder` and `*embedder` have promoted method `f` from `base`; `*embedder` also has method `g` from `*base` +type embedder struct{ base } + +// `ptrembedder` and `*ptrembedder` have promoted methods `f` from `base` and `g` from `*base` +type ptrembedder struct{ *base } + +// `embedder2` and `*embedder2` have promoted method `f` from `base`; `*embedder2` also has method `g` from `*base` +type embedder2 struct{ embedder } + +// `embedder3` and `*embedder3` have their own version of `f`; `*embedder3` also has promoted method `g` from `*base` +type embedder3 struct{ embedder } + +func (embedder3) f() int { + return 3 +} + +// `embedder4` and `*embedder4` do not have a method `f`; `*embedder4` has promoted method `g` from `*base` +type embedder4 struct { + base + f int +} + +func main() { + var ( + b base + bp *base = &b + e embedder + ep *embedder = &e + pe ptrembedder = ptrembedder{bp} + pep *ptrembedder = &pe + e2 embedder2 + e2p *embedder2 = &e2 + e3 embedder3 + e3p *embedder3 = &e3 + e4 embedder4 + e4p *embedder4 = &e4 + ) + fmt.Println(base.f(b), (*base).f(bp) /*base.g(b),*/, (*base).g(bp)) + fmt.Println(embedder.f(e), (*embedder).f(ep) /*embedder.g(e),*/, (*embedder).g(ep)) + fmt.Println(ptrembedder.f(pe), (*ptrembedder).f(pep), ptrembedder.g(pe), (*ptrembedder).g(pep)) + fmt.Println(embedder2.f(e2), (*embedder2).f(e2p) /*embedder2.g(e2),*/, (*embedder2).g(e2p)) + fmt.Println(embedder3.f(e3), (*embedder3).f(e3p) /*embedder3.g(e3),*/, (*embedder3).g(e3p)) + fmt.Println( /*embedder4.f(e4), (*embedder4).f(e4p), embedder4.g(e3),*/ (*embedder4).g(e4p)) +}