From 92c331402debfeff232d1c4479ed592668fbd7e2 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 29 Mar 2022 14:54:49 +0100 Subject: [PATCH] Extract type parameters in types, not just decls --- extractor/dbscheme/tables.go | 12 +++++++++--- extractor/extractor.go | 34 +++++++++++++++++++++++++++++++--- extractor/trap/trapwriter.go | 18 ++++++++++-------- ql/lib/go.dbscheme | 8 ++++++-- ql/lib/semmle/go/Types.qll | 4 ++-- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/extractor/dbscheme/tables.go b/extractor/dbscheme/tables.go index 6325c6fd2a0..00b3bef14b3 100644 --- a/extractor/dbscheme/tables.go +++ b/extractor/dbscheme/tables.go @@ -682,6 +682,9 @@ var ObjectType = NewPrimaryKeyType("@object") // ObjectKind is a case type for distinguishing different kinds of built-in and declared objects var ObjectKind = NewCaseType(ObjectType, "kind") +// TypeParamParentObjectType is the type of objects that can have type parameters as children +var TypeParamParentObjectType = NewUnionType("@typeparamparentobject") + // DeclObjectType is the type of declared objects var DeclObjectType = NewUnionType("@declobject") @@ -695,7 +698,7 @@ var PkgObjectType = ObjectKind.NewBranch("@pkgobject") var TypeObjectType = NewUnionType("@typeobject") // DeclTypeObjectType is the type of declared named types -var DeclTypeObjectType = ObjectKind.NewBranch("@decltypeobject", TypeObjectType, DeclObjectType) +var DeclTypeObjectType = ObjectKind.NewBranch("@decltypeobject", TypeObjectType, DeclObjectType, TypeParamParentObjectType) // BuiltinTypeObjectType is the type of built-in named types var BuiltinTypeObjectType = ObjectKind.NewBranch("@builtintypeobject", TypeObjectType, BuiltinObjectType) @@ -722,7 +725,7 @@ var DeclVarObjectType = ObjectKind.NewBranch("@declvarobject", VarObjectType, De var FunctionObjectType = NewUnionType("@functionobject", ValueObjectType) // DeclFuncObjectType is the type of declared functions, including (abstract and concrete) methods -var DeclFuncObjectType = ObjectKind.NewBranch("@declfunctionobject", FunctionObjectType, DeclObjectType) +var DeclFuncObjectType = ObjectKind.NewBranch("@declfunctionobject", FunctionObjectType, DeclObjectType, TypeParamParentObjectType) // BuiltinFuncObjectType is the type of built-in functions var BuiltinFuncObjectType = ObjectKind.NewBranch("@builtinfunctionobject", FunctionObjectType, BuiltinObjectType) @@ -1206,8 +1209,11 @@ var VariadicTable = NewTable("variadic", EntityColumn(SignatureType, "id"), ) +// TypeParamTable is the table describing type parameter types var TypeParamTable = NewTable("typeparam", EntityColumn(TypeParamType, "tp").Unique(), StringColumn("name"), EntityColumn(CompositeType, "bound"), -) + EntityColumn(TypeParamParentObjectType, "parent"), + IntColumn("idx"), +).KeySet("parent", "idx") diff --git a/extractor/extractor.go b/extractor/extractor.go index 5a207ad5fba..e8e15ed32c2 100644 --- a/extractor/extractor.go +++ b/extractor/extractor.go @@ -363,6 +363,15 @@ func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label) obj := scope.Lookup(name) lbl, exists := tw.Labeler.ScopedObjectID(obj, func() trap.Label { return extractType(tw, obj.Type()) }) if !exists { + if funcObj, ok := obj.(*types.Func); ok { + populateTypeParamParents(tw, funcObj.Type().(*types.Signature).TypeParams(), lbl) + populateTypeParamParents(tw, funcObj.Type().(*types.Signature).RecvTypeParams(), lbl) + } + if typeNameObj, ok := obj.(*types.TypeName); ok { + if tp, ok := typeNameObj.Type().(*types.Named); ok { + populateTypeParamParents(tw, tp.TypeParams(), lbl) + } + } extractObject(tw, obj, lbl) } @@ -378,10 +387,14 @@ func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label) func extractMethod(tw *trap.Writer, meth *types.Func) trap.Label { // get the receiver type of the method recvtyp := meth.Type().(*types.Signature).Recv().Type() - recvlbl := extractType(tw, recvtyp) // ensure receiver type has been extracted + // ensure receiver type has been extracted + recvlbl := extractType(tw, recvtyp) + // if the method label does not exist, extract it methlbl, exists := tw.Labeler.MethodID(meth, recvlbl) if !exists { + populateTypeParamParents(tw, meth.Type().(*types.Signature).TypeParams(), methlbl) + populateTypeParamParents(tw, meth.Type().(*types.Signature).RecvTypeParams(), methlbl) extractObject(tw, meth, methlbl) } @@ -1512,7 +1525,12 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { } case *types.TypeParam: kind = dbscheme.TypeParamType.Index() - dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), extractType(tw, tp.Constraint())) + parentlbl, exists := tw.TypeParamParent[tp] + if !exists { + log.Fatalf("Parent of type parameter does not exist: %s", tp.String()) + } + constraintLabel := extractType(tw, tp.Constraint()) + dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, tp.Index()) case *types.Union: kind = dbscheme.TypeSetLiteral.Index() for i := 0; i < tp.Len(); i++ { @@ -1651,7 +1669,8 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { } lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};namedtype", entitylbl)) case *types.TypeParam: - lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s},{%s};typeparamtype", tp.Obj().Name(), extractType(tw, tp.Constraint()))) + parentlbl := tw.TypeParamParent[tp] + lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%v},%s;typeparamtype", parentlbl, tp.Obj().Name())) case *types.Union: var b strings.Builder for i := 0; i < tp.Len(); i++ { @@ -1828,3 +1847,12 @@ func extractTypeParamDecls(tw *trap.Writer, fields *ast.FieldList, parent trap.L idx += 1 } } + +// populateTypeParamParents sets `parentlbl` as the parent of the elements of `typeparams` +func populateTypeParamParents(tw *trap.Writer, typeparams *types.TypeParamList, parentlbl trap.Label) { + if typeparams != nil { + for idx := 0; idx < typeparams.Len(); idx++ { + tw.TypeParamParent[typeparams.At(idx)] = parentlbl + } + } +} diff --git a/extractor/trap/trapwriter.go b/extractor/trap/trapwriter.go index 299147e8a53..7647086b4dd 100644 --- a/extractor/trap/trapwriter.go +++ b/extractor/trap/trapwriter.go @@ -18,14 +18,15 @@ import ( // A Writer provides methods for writing data to a TRAP file type Writer struct { - zip *gzip.Writer - w *bufio.Writer - file *os.File - Labeler *Labeler - path string - trapFilePath string - Package *packages.Package - TypesOverride map[ast.Expr]types.Type + zip *gzip.Writer + w *bufio.Writer + file *os.File + Labeler *Labeler + path string + trapFilePath string + Package *packages.Package + TypesOverride map[ast.Expr]types.Type + TypeParamParent map[*types.TypeParam]Label } func FileFor(path string) (string, error) { @@ -64,6 +65,7 @@ func NewWriter(path string, pkg *packages.Package) (*Writer, error) { trapFilePath, pkg, make(map[ast.Expr]types.Type), + make(map[*types.TypeParam]Label), } tw.Labeler = newLabeler(tw) return tw, nil diff --git a/ql/lib/go.dbscheme b/ql/lib/go.dbscheme index 3110ca88d98..90fa7836e0a 100644 --- a/ql/lib/go.dbscheme +++ b/ql/lib/go.dbscheme @@ -227,7 +227,9 @@ has_ellipsis(int id: @callorconversionexpr ref); variadic(int id: @signaturetype ref); -typeparam(unique int tp: @typeparamtype ref, string name: string ref, int bound: @compositetype ref); +#keyset[parent, idx] +typeparam(unique int tp: @typeparamtype ref, string name: string ref, int bound: @compositetype ref, + int parent: @typeparamparentobject ref, int idx: int ref); @container = @file | @folder; @@ -248,7 +250,7 @@ typeparam(unique int tp: @typeparamtype ref, string name: string ref, int bound: @declparent = @file | @declstmt; -@typeparamdeclparent = @functypeexpr | @typespec; +@typeparamdeclparent = @funcdecl | @typespec; @funcdef = @funclit | @funcdecl; @@ -439,6 +441,8 @@ case @object.kind of | 7 = @builtinfunctionobject | 8 = @labelobject; +@typeparamparentobject = @decltypeobject | @declfunctionobject; + @declobject = @decltypeobject | @declconstobject | @declvarobject | @declfunctionobject; @builtinobject = @builtintypeobject | @builtinconstobject | @builtinfunctionobject; diff --git a/ql/lib/semmle/go/Types.qll b/ql/lib/semmle/go/Types.qll index 21ad88e83d7..ce1a5e8fa86 100644 --- a/ql/lib/semmle/go/Types.qll +++ b/ql/lib/semmle/go/Types.qll @@ -367,10 +367,10 @@ class CompositeType extends @compositetype, Type { } /** A type that comes from a type parameter. */ class TypeParamType extends @typeparamtype, CompositeType { /** Gets the name of this type parameter type. */ - string getParamName() { typeparam(this, result, _) } + string getParamName() { typeparam(this, result, _, _, _) } /** Gets the constraint of this type parameter type. */ - Type getConstraint() { typeparam(this, _, result) } + Type getConstraint() { typeparam(this, _, result, _, _) } override InterfaceType getUnderlyingType() { result = this.getConstraint().getUnderlyingType() }