diff --git a/extractor/dbscheme/tables.go b/extractor/dbscheme/tables.go index f934ca57bb5..b541b178316 100644 --- a/extractor/dbscheme/tables.go +++ b/extractor/dbscheme/tables.go @@ -371,9 +371,15 @@ var ParenExpr = ExprKind.NewBranch("@parenexpr") // SelectorExpr is the type of selector expression AST nodes var SelectorExpr = ExprKind.NewBranch("@selectorexpr") -// IndexExpr is the type of index expression AST nodes +// IndexExpr is the type of index expression AST nodes which are not generic type +// instantiation expressions var IndexExpr = ExprKind.NewBranch("@indexexpr") +// GenericFunctionInstantiationExpr is the type of AST nodes that represent a instantiation +// of a generic type. These correspond to some index expression AST nodes and all index +// list expression AST nodes. +var GenericFunctionInstantiationExpr = ExprKind.NewBranch("@genericfunctioninstantiationexpr") + // SliceExpr is the type of slice expression AST nodes var SliceExpr = ExprKind.NewBranch("@sliceexpr") diff --git a/extractor/extractor.go b/extractor/extractor.go index 40ab6a8592d..c0eb6c32154 100644 --- a/extractor/extractor.go +++ b/extractor/extractor.go @@ -877,9 +877,24 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) { if expr == nil { return } - kind = dbscheme.IndexExpr.Index() + switch tp := tw.Package.TypesInfo.TypeOf(expr.X).Underlying().(type) { + case *types.Signature: + kind = dbscheme.GenericFunctionInstantiationExpr.Index() + case *types.Map, *types.Array, *types.Slice, *types.Basic, *types.Pointer: + // map, array, slice, string or pointer to array + kind = dbscheme.IndexExpr.Index() + default: + log.Fatalf("unsupported IndexExpr: its base expression is a %s.", tp.String()) + } extractExpr(tw, expr.X, lbl, 0) extractExpr(tw, expr.Index, lbl, 1) + case *ast.IndexListExpr: + if expr == nil { + return + } + kind = dbscheme.GenericFunctionInstantiationExpr.Index() + extractExpr(tw, expr.X, lbl, 0) + extractExprs(tw, expr.Indices, lbl, 1, 1) case *ast.SliceExpr: if expr == nil { return diff --git a/ql/lib/go.dbscheme b/ql/lib/go.dbscheme index e0ac0aab04f..e0d5be4b1ca 100644 --- a/ql/lib/go.dbscheme +++ b/ql/lib/go.dbscheme @@ -272,46 +272,47 @@ case @expr.kind of | 10 = @parenexpr | 11 = @selectorexpr | 12 = @indexexpr -| 13 = @sliceexpr -| 14 = @typeassertexpr -| 15 = @callorconversionexpr -| 16 = @starexpr -| 17 = @keyvalueexpr -| 18 = @arraytypeexpr -| 19 = @structtypeexpr -| 20 = @functypeexpr -| 21 = @interfacetypeexpr -| 22 = @maptypeexpr -| 23 = @plusexpr -| 24 = @minusexpr -| 25 = @notexpr -| 26 = @complementexpr -| 27 = @derefexpr -| 28 = @addressexpr -| 29 = @arrowexpr -| 30 = @lorexpr -| 31 = @landexpr -| 32 = @eqlexpr -| 33 = @neqexpr -| 34 = @lssexpr -| 35 = @leqexpr -| 36 = @gtrexpr -| 37 = @geqexpr -| 38 = @addexpr -| 39 = @subexpr -| 40 = @orexpr -| 41 = @xorexpr -| 42 = @mulexpr -| 43 = @quoexpr -| 44 = @remexpr -| 45 = @shlexpr -| 46 = @shrexpr -| 47 = @andexpr -| 48 = @andnotexpr -| 49 = @sendchantypeexpr -| 50 = @recvchantypeexpr -| 51 = @sendrcvchantypeexpr -| 52 = @errorexpr; +| 13 = @genericfunctioninstantiationexpr +| 14 = @sliceexpr +| 15 = @typeassertexpr +| 16 = @callorconversionexpr +| 17 = @starexpr +| 18 = @keyvalueexpr +| 19 = @arraytypeexpr +| 20 = @structtypeexpr +| 21 = @functypeexpr +| 22 = @interfacetypeexpr +| 23 = @maptypeexpr +| 24 = @plusexpr +| 25 = @minusexpr +| 26 = @notexpr +| 27 = @complementexpr +| 28 = @derefexpr +| 29 = @addressexpr +| 30 = @arrowexpr +| 31 = @lorexpr +| 32 = @landexpr +| 33 = @eqlexpr +| 34 = @neqexpr +| 35 = @lssexpr +| 36 = @leqexpr +| 37 = @gtrexpr +| 38 = @geqexpr +| 39 = @addexpr +| 40 = @subexpr +| 41 = @orexpr +| 42 = @xorexpr +| 43 = @mulexpr +| 44 = @quoexpr +| 45 = @remexpr +| 46 = @shlexpr +| 47 = @shrexpr +| 48 = @andexpr +| 49 = @andnotexpr +| 50 = @sendchantypeexpr +| 51 = @recvchantypeexpr +| 52 = @sendrcvchantypeexpr +| 53 = @errorexpr; @basiclit = @intlit | @floatlit | @imaglit | @charlit | @stringlit; diff --git a/ql/lib/semmle/go/Expr.qll b/ql/lib/semmle/go/Expr.qll index 4bddc6fc744..013b209637b 100644 --- a/ql/lib/semmle/go/Expr.qll +++ b/ql/lib/semmle/go/Expr.qll @@ -626,11 +626,16 @@ class PromotedSelector extends SelectorExpr { /** * An index expression, that is, a base expression followed by an index. + * Expressions which represent generic type instantiations have been + * excluded. * * Examples: * * ```go - * a[i] + * array[i] + * arrayptr[i] + * slice[i] + * map[key] * ``` */ class IndexExpr extends @indexexpr, Expr { @@ -647,6 +652,34 @@ class IndexExpr extends @indexexpr, Expr { override string getAPrimaryQlClass() { result = "IndexExpr" } } +/** + * A generic function instantiation, that is, a base expression that represents + * a generic function, followed by a list of type arguments. + * + * Examples: + * + * ```go + * genericfunction[type] + * genericfunction[type1, type2] + * ``` + */ +class GenericFunctionInstantiationExpr extends @genericfunctioninstantiationexpr, Expr { + /** Gets the generic type expression. */ + Expr getBase() { result = this.getChildExpr(0) } + + /** Gets the `i`th type argument. */ + Expr getTypeArgument(int i) { + i >= 0 and + result = this.getChildExpr(i + 1) + } + + override predicate mayHaveOwnSideEffects() { any() } + + override string toString() { result = "generic function instantiation expression" } + + override string getAPrimaryQlClass() { result = "GenericFunctionInstantiationExpr" } +} + /** * A slice expression, that is, a base expression followed by slice indices. * @@ -797,11 +830,16 @@ class CallExpr extends CallOrConversionExpr { result = callee.(Ident).getName() or result = callee.(SelectorExpr).getSelector().getName() + or + result = callee.(GenericFunctionInstantiationExpr).getBase().(Ident).getName() ) } /** Gets the declared target of this call. */ - Function getTarget() { this.getCalleeExpr() = result.getAReference() } + Function getTarget() { + this.getCalleeExpr() = result.getAReference() or + this.getCalleeExpr().(GenericFunctionInstantiationExpr).getBase() = result.getAReference() + } /** Holds if this call has an ellipsis after its last argument. */ predicate hasEllipsis() { has_ellipsis(this) }