From 5175f1dcbe3485570b06a4dccf3575cc69c075cf Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 13 Mar 2020 12:57:26 +0000 Subject: [PATCH] Take promoted methods into account when computing method sets. --- ql/src/semmle/go/Types.qll | 39 +++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/ql/src/semmle/go/Types.qll b/ql/src/semmle/go/Types.qll index c341656621b..d2b734e0785 100644 --- a/ql/src/semmle/go/Types.qll +++ b/ql/src/semmle/go/Types.qll @@ -441,11 +441,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,7 +584,7 @@ class SendRecvChanType extends @sendrcvchantype, ChanType { /** A named type. */ class NamedType extends @namedtype, CompositeType { - /** Gets a method with name `m` defined on this type. */ + /** Gets a method with name `m` defined on this type or its pointer type. */ MethodDecl getMethodDecl(string m) { result.getName() = m and this = result.getReceiverBaseType() @@ -580,6 +598,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() }